[libgda] Upgraded to Sqlite 3.8.10.2 & SqlCipher 3.3.1
- From: Vivien Malerba <vivien src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libgda] Upgraded to Sqlite 3.8.10.2 & SqlCipher 3.3.1
- Date: Wed, 9 Mar 2016 21:12:34 +0000 (UTC)
commit dde55cf1b965e291d007015094e95d1187641898
Author: Vivien Malerba <malerba gnome-db org>
Date: Wed Mar 9 17:33:52 2016 +0100
Upgraded to Sqlite 3.8.10.2 & SqlCipher 3.3.1
libgda/sqlite/sqlite-src/PragmasPatch | 8 +-
libgda/sqlite/sqlite-src/sqlite3.c |20454 ++++++++++++------
libgda/sqlite/sqlite-src/sqlite3.h | 1607 +-
providers/sqlcipher/sqlcipher.patch |39053 ++++++++++++++++++++++++++++++---
4 files changed, 51095 insertions(+), 10027 deletions(-)
---
diff --git a/libgda/sqlite/sqlite-src/PragmasPatch b/libgda/sqlite/sqlite-src/PragmasPatch
index f5e88df..9f6cfbe 100644
--- a/libgda/sqlite/sqlite-src/PragmasPatch
+++ b/libgda/sqlite/sqlite-src/PragmasPatch
@@ -1,6 +1,6 @@
---- sqlite3.c.orig 2014-11-08 15:04:07.918458139 +0100
-+++ sqlite3.c 2014-11-08 15:04:12.087540578 +0100
-@@ -98888,6 +98888,24 @@
+--- sqlite3.c.orig 2016-03-09 15:37:00.631202362 +0100
++++ sqlite3.c 2016-03-09 15:37:05.456314760 +0100
+@@ -103838,6 +103838,24 @@
return azModeName[eMode];
}
@@ -25,7 +25,7 @@
/*
** Process a pragma statement.
**
-@@ -99614,6 +99632,54 @@
+@@ -104584,6 +104602,54 @@
#ifndef SQLITE_OMIT_SCHEMA_PRAGMAS
/*
diff --git a/libgda/sqlite/sqlite-src/sqlite3.c b/libgda/sqlite/sqlite-src/sqlite3.c
index db49726..c974749 100644
--- a/libgda/sqlite/sqlite-src/sqlite3.c
+++ b/libgda/sqlite/sqlite-src/sqlite3.c
@@ -1,6 +1,6 @@
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
-** version 3.8.6. By combining all the individual C code files into this
+** version 3.8.10.2. By combining all the individual C code files into this
** single large file, the entire code can be compiled as a single translation
** unit. This allows many compilers to do optimizations that would not be
** possible if the files were compiled separately. Performance improvements
@@ -22,9 +22,6 @@
#ifndef SQLITE_PRIVATE
# define SQLITE_PRIVATE static
#endif
-#ifndef SQLITE_API
-# define SQLITE_API
-#endif
/************** Begin file sqliteInt.h ***************************************/
/*
** 2001 September 15
@@ -44,6 +41,92 @@
#define _SQLITEINT_H_
/*
+** Include the header file used to customize the compiler options for MSVC.
+** This should be done first so that it can successfully prevent spurious
+** compiler warnings due to subsequent content in this file and other files
+** that are included by this file.
+*/
+/************** Include msvc.h in the middle of sqliteInt.h ******************/
+/************** Begin file msvc.h ********************************************/
+/*
+** 2015 January 12
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This file contains code that is specific to MSVC.
+*/
+#ifndef _MSVC_H_
+#define _MSVC_H_
+
+#if defined(_MSC_VER)
+#pragma warning(disable : 4054)
+#pragma warning(disable : 4055)
+#pragma warning(disable : 4100)
+#pragma warning(disable : 4127)
+#pragma warning(disable : 4130)
+#pragma warning(disable : 4152)
+#pragma warning(disable : 4189)
+#pragma warning(disable : 4206)
+#pragma warning(disable : 4210)
+#pragma warning(disable : 4232)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4305)
+#pragma warning(disable : 4306)
+#pragma warning(disable : 4702)
+#pragma warning(disable : 4706)
+#endif /* defined(_MSC_VER) */
+
+#endif /* _MSVC_H_ */
+
+/************** End of msvc.h ************************************************/
+/************** Continuing where we left off in sqliteInt.h ******************/
+
+/*
+** Special setup for VxWorks
+*/
+/************** Include vxworks.h in the middle of sqliteInt.h ***************/
+/************** Begin file vxworks.h *****************************************/
+/*
+** 2015-03-02
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This file contains code that is specific to Wind River's VxWorks
+*/
+#if defined(__RTP__) || defined(_WRS_KERNEL)
+/* This is VxWorks. Set up things specially for that OS
+*/
+#include <vxWorks.h>
+#include <pthread.h> /* amalgamator: dontcache */
+#define OS_VXWORKS 1
+#define SQLITE_OS_OTHER 0
+#define SQLITE_HOMEGROWN_RECURSIVE_MUTEX 1
+#define SQLITE_OMIT_LOAD_EXTENSION 1
+#define SQLITE_ENABLE_LOCKING_STYLE 0
+#define HAVE_UTIME 1
+#else
+/* This is not VxWorks. */
+#define OS_VXWORKS 0
+#endif /* defined(_WRS_KERNEL) */
+
+/************** End of vxworks.h *********************************************/
+/************** Continuing where we left off in sqliteInt.h ******************/
+
+/*
** These #defines should enable >2GB file support on POSIX if the
** underlying operating system supports it. If the OS lacks
** large file support, or if the OS is windows, these should be no-ops.
@@ -75,6 +158,15 @@
# define _LARGEFILE_SOURCE 1
#endif
+/* Needed for various definitions... */
+#if defined(__GNUC__) && !defined(_GNU_SOURCE)
+# define _GNU_SOURCE
+#endif
+
+#if defined(__OpenBSD__) && !defined(_BSD_SOURCE)
+# define _BSD_SOURCE
+#endif
+
/*
** For MinGW, check to see if we can include the header file containing its
** version information, among other things. Normally, this internal MinGW
@@ -158,21 +250,25 @@ extern "C" {
/*
-** Add the ability to override 'extern'
+** Provide the ability to override linkage features of the interface.
*/
#ifndef SQLITE_EXTERN
# define SQLITE_EXTERN extern
#endif
-
#ifndef SQLITE_API
# define SQLITE_API
#endif
-
+#ifndef SQLITE_CDECL
+# define SQLITE_CDECL
+#endif
+#ifndef SQLITE_STDCALL
+# define SQLITE_STDCALL
+#endif
/*
** These no-op macros are used in front of interfaces to mark those
** interfaces as either deprecated or experimental. New applications
-** should not use deprecated interfaces - they are support for backwards
+** should not use deprecated interfaces - they are supported for backwards
** compatibility only. Application writers should be aware that
** experimental interfaces are subject to change in point releases.
**
@@ -222,9 +318,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.8.6"
-#define SQLITE_VERSION_NUMBER 3008006
-#define SQLITE_SOURCE_ID "2014-08-15 11:46:33 9491ba7d738528f168657adb43a198238abde19e"
+#define SQLITE_VERSION "3.8.10.2"
+#define SQLITE_VERSION_NUMBER 3008010
+#define SQLITE_SOURCE_ID "2015-05-20 18:17:19 2ef4f3a5b1d1d0c4338f8243d40a2452cc1f7fe4"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -257,9 +353,9 @@ extern "C" {
** See also: [sqlite_version()] and [sqlite_source_id()].
*/
SQLITE_API const char sqlite3_version[] = SQLITE_VERSION;
-SQLITE_API const char *sqlite3_libversion(void);
-SQLITE_API const char *sqlite3_sourceid(void);
-SQLITE_API int sqlite3_libversion_number(void);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_libversion(void);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_sourceid(void);
+SQLITE_API int SQLITE_STDCALL sqlite3_libversion_number(void);
/*
** CAPI3REF: Run-Time Library Compilation Options Diagnostics
@@ -284,8 +380,8 @@ SQLITE_API int sqlite3_libversion_number(void);
** [sqlite_compileoption_get()] and the [compile_options pragma].
*/
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
-SQLITE_API int sqlite3_compileoption_used(const char *zOptName);
-SQLITE_API const char *sqlite3_compileoption_get(int N);
+SQLITE_API int SQLITE_STDCALL sqlite3_compileoption_used(const char *zOptName);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N);
#endif
/*
@@ -316,7 +412,7 @@ SQLITE_API const char *sqlite3_compileoption_get(int N);
** SQLITE_THREADSAFE=1 or =2 then mutexes are enabled by default but
** can be fully or partially disabled using a call to [sqlite3_config()]
** with the verbs [SQLITE_CONFIG_SINGLETHREAD], [SQLITE_CONFIG_MULTITHREAD],
-** or [SQLITE_CONFIG_MUTEX]. ^(The return value of the
+** or [SQLITE_CONFIG_SERIALIZED]. ^(The return value of the
** sqlite3_threadsafe() function shows only the compile-time setting of
** thread safety, not any run-time changes to that setting made by
** sqlite3_config(). In other words, the return value from sqlite3_threadsafe()
@@ -324,7 +420,7 @@ SQLITE_API const char *sqlite3_compileoption_get(int N);
**
** See the [threading mode] documentation for additional information.
*/
-SQLITE_API int sqlite3_threadsafe(void);
+SQLITE_API int SQLITE_STDCALL sqlite3_threadsafe(void);
/*
** CAPI3REF: Database Connection Handle
@@ -381,6 +477,7 @@ typedef sqlite_uint64 sqlite3_uint64;
/*
** CAPI3REF: Closing A Database Connection
+** DESTRUCTOR: sqlite3
**
** ^The sqlite3_close() and sqlite3_close_v2() routines are destructors
** for the [sqlite3] object.
@@ -420,8 +517,8 @@ typedef sqlite_uint64 sqlite3_uint64;
** ^Calling sqlite3_close() or sqlite3_close_v2() with a NULL pointer
** argument is a harmless no-op.
*/
-SQLITE_API int sqlite3_close(sqlite3*);
-SQLITE_API int sqlite3_close_v2(sqlite3*);
+SQLITE_API int SQLITE_STDCALL sqlite3_close(sqlite3*);
+SQLITE_API int SQLITE_STDCALL sqlite3_close_v2(sqlite3*);
/*
** The type for a callback function.
@@ -432,6 +529,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
/*
** CAPI3REF: One-Step Query Execution Interface
+** METHOD: sqlite3
**
** The sqlite3_exec() interface is a convenience wrapper around
** [sqlite3_prepare_v2()], [sqlite3_step()], and [sqlite3_finalize()],
@@ -491,7 +589,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running.
** </ul>
*/
-SQLITE_API int sqlite3_exec(
+SQLITE_API int SQLITE_STDCALL sqlite3_exec(
sqlite3*, /* An open database */
const char *sql, /* SQL to be evaluated */
int (*callback)(void*,int,char**,char**), /* Callback function */
@@ -612,6 +710,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8))
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8))
+#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8))
/*
** CAPI3REF: Flags For File Open Operations
@@ -870,14 +969,16 @@ struct sqlite3_io_methods {
** of the [sqlite3_io_methods] object and for the [sqlite3_file_control()]
** interface.
**
+** <ul>
+** <li>[[SQLITE_FCNTL_LOCKSTATE]]
** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This
** opcode causes the xFileControl method to write the current state of
** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED],
** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE])
** into an integer that the pArg argument points to. This capability
-** is used during testing and only needs to be supported when SQLITE_TEST
-** is defined.
-** <ul>
+** is used during testing and is only available when the SQLITE_TEST
+** compile-time option is used.
+**
** <li>[[SQLITE_FCNTL_SIZE_HINT]]
** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS
** layer a hint of how large the database file will grow to be during the
@@ -1002,7 +1103,9 @@ struct sqlite3_io_methods {
** [PRAGMA] processing continues. ^If the [SQLITE_FCNTL_PRAGMA]
** file control returns [SQLITE_OK], then the parser assumes that the
** VFS has handled the PRAGMA itself and the parser generates a no-op
-** prepared statement. ^If the [SQLITE_FCNTL_PRAGMA] file control returns
+** prepared statement if result string is NULL, or that returns a copy
+** of the result string if the string is non-NULL.
+** ^If the [SQLITE_FCNTL_PRAGMA] file control returns
** any result code other than [SQLITE_OK] or [SQLITE_NOTFOUND], that means
** that the VFS encountered an error while handling the [PRAGMA] and the
** compilation of the PRAGMA fails with an error. ^The [SQLITE_FCNTL_PRAGMA]
@@ -1060,12 +1163,19 @@ struct sqlite3_io_methods {
** pointed to by the pArg argument. This capability is used during testing
** and only needs to be supported when SQLITE_TEST is defined.
**
+** <li>[[SQLITE_FCNTL_WAL_BLOCK]]
+** The [SQLITE_FCNTL_WAL_BLOCK] is a signal to the VFS layer that it might
+** be advantageous to block on the next WAL lock if the lock is not immediately
+** available. The WAL subsystem issues this signal during rare
+** circumstances in order to fix a problem with priority inversion.
+** Applications should <em>not</em> use this file-control.
+**
** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE 1
-#define SQLITE_GET_LOCKPROXYFILE 2
-#define SQLITE_SET_LOCKPROXYFILE 3
-#define SQLITE_LAST_ERRNO 4
+#define SQLITE_FCNTL_GET_LOCKPROXYFILE 2
+#define SQLITE_FCNTL_SET_LOCKPROXYFILE 3
+#define SQLITE_FCNTL_LAST_ERRNO 4
#define SQLITE_FCNTL_SIZE_HINT 5
#define SQLITE_FCNTL_CHUNK_SIZE 6
#define SQLITE_FCNTL_FILE_POINTER 7
@@ -1084,6 +1194,13 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_SYNC 21
#define SQLITE_FCNTL_COMMIT_PHASETWO 22
#define SQLITE_FCNTL_WIN32_SET_HANDLE 23
+#define SQLITE_FCNTL_WAL_BLOCK 24
+
+/* deprecated names */
+#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
+#define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE
+#define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO
+
/*
** CAPI3REF: Mutex Handle
@@ -1335,7 +1452,7 @@ struct sqlite3_vfs {
** </ul>
**
** When unlocking, the same SHARED or EXCLUSIVE flag must be supplied as
-** was given no the corresponding lock.
+** was given on the corresponding lock.
**
** The xShmLock method can transition between unlocked and SHARED or
** between unlocked and EXCLUSIVE. It cannot transition between SHARED
@@ -1432,10 +1549,10 @@ struct sqlite3_vfs {
** must return [SQLITE_OK] on success and some other [error code] upon
** failure.
*/
-SQLITE_API int sqlite3_initialize(void);
-SQLITE_API int sqlite3_shutdown(void);
-SQLITE_API int sqlite3_os_init(void);
-SQLITE_API int sqlite3_os_end(void);
+SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void);
+SQLITE_API int SQLITE_STDCALL sqlite3_shutdown(void);
+SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void);
+SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void);
/*
** CAPI3REF: Configuring The SQLite Library
@@ -1466,10 +1583,11 @@ SQLITE_API int sqlite3_os_end(void);
** ^If the option is unknown or SQLite is unable to set the option
** then this routine returns a non-zero [error code].
*/
-SQLITE_API int sqlite3_config(int, ...);
+SQLITE_API int SQLITE_CDECL sqlite3_config(int, ...);
/*
** CAPI3REF: Configure database connections
+** METHOD: sqlite3
**
** The sqlite3_db_config() interface is used to make configuration
** changes to a [database connection]. The interface is similar to
@@ -1484,7 +1602,7 @@ SQLITE_API int sqlite3_config(int, ...);
** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if
** the call is considered successful.
*/
-SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
+SQLITE_API int SQLITE_CDECL sqlite3_db_config(sqlite3*, int op, ...);
/*
** CAPI3REF: Memory Allocation Routines
@@ -1618,31 +1736,33 @@ struct sqlite3_mem_methods {
** SQLITE_CONFIG_SERIALIZED configuration option.</dd>
**
** [[SQLITE_CONFIG_MALLOC]] <dt>SQLITE_CONFIG_MALLOC</dt>
-** <dd> ^(This option takes a single argument which is a pointer to an
-** instance of the [sqlite3_mem_methods] structure. The argument specifies
+** <dd> ^(The SQLITE_CONFIG_MALLOC option takes a single argument which is
+** a pointer to an instance of the [sqlite3_mem_methods] structure.
+** The argument specifies
** alternative low-level memory allocation routines to be used in place of
** the memory allocation routines built into SQLite.)^ ^SQLite makes
** its own private copy of the content of the [sqlite3_mem_methods] structure
** before the [sqlite3_config()] call returns.</dd>
**
** [[SQLITE_CONFIG_GETMALLOC]] <dt>SQLITE_CONFIG_GETMALLOC</dt>
-** <dd> ^(This option takes a single argument which is a pointer to an
-** instance of the [sqlite3_mem_methods] structure. The [sqlite3_mem_methods]
+** <dd> ^(The SQLITE_CONFIG_GETMALLOC option takes a single argument which
+** is a pointer to an instance of the [sqlite3_mem_methods] structure.
+** The [sqlite3_mem_methods]
** structure is filled with the currently defined memory allocation routines.)^
** This option can be used to overload the default memory allocation
** routines with a wrapper that simulations memory allocation failure or
** tracks memory usage, for example. </dd>
**
** [[SQLITE_CONFIG_MEMSTATUS]] <dt>SQLITE_CONFIG_MEMSTATUS</dt>
-** <dd> ^This option takes single argument of type int, interpreted as a
-** boolean, which enables or disables the collection of memory allocation
-** statistics. ^(When memory allocation statistics are disabled, the
-** following SQLite interfaces become non-operational:
+** <dd> ^The SQLITE_CONFIG_MEMSTATUS option takes single argument of type int,
+** interpreted as a boolean, which enables or disables the collection of
+** memory allocation statistics. ^(When memory allocation statistics are
+** disabled, the following SQLite interfaces become non-operational:
** <ul>
** <li> [sqlite3_memory_used()]
** <li> [sqlite3_memory_highwater()]
** <li> [sqlite3_soft_heap_limit64()]
-** <li> [sqlite3_status()]
+** <li> [sqlite3_status64()]
** </ul>)^
** ^Memory allocation statistics are enabled by default unless SQLite is
** compiled with [SQLITE_DEFAULT_MEMSTATUS]=0 in which case memory
@@ -1650,53 +1770,67 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_CONFIG_SCRATCH]] <dt>SQLITE_CONFIG_SCRATCH</dt>
-** <dd> ^This option specifies a static memory buffer that SQLite can use for
-** scratch memory. There are three arguments: A pointer an 8-byte
+** <dd> ^The SQLITE_CONFIG_SCRATCH option specifies a static memory buffer
+** that SQLite can use for scratch memory. ^(There are three arguments
+** to SQLITE_CONFIG_SCRATCH: A pointer an 8-byte
** aligned memory buffer from which the scratch allocations will be
** drawn, the size of each scratch allocation (sz),
-** and the maximum number of scratch allocations (N). The sz
-** argument must be a multiple of 16.
+** and the maximum number of scratch allocations (N).)^
** The first argument must be a pointer to an 8-byte aligned buffer
** of at least sz*N bytes of memory.
-** ^SQLite will use no more than two scratch buffers per thread. So
-** N should be set to twice the expected maximum number of threads.
-** ^SQLite will never require a scratch buffer that is more than 6
-** times the database page size. ^If SQLite needs needs additional
+** ^SQLite will not use more than one scratch buffers per thread.
+** ^SQLite will never request a scratch buffer that is more than 6
+** times the database page size.
+** ^If SQLite needs needs additional
** scratch memory beyond what is provided by this configuration option, then
-** [sqlite3_malloc()] will be used to obtain the memory needed.</dd>
+** [sqlite3_malloc()] will be used to obtain the memory needed.<p>
+** ^When the application provides any amount of scratch memory using
+** SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary large
+** [sqlite3_malloc|heap allocations].
+** This can help [Robson proof|prevent memory allocation failures] due to heap
+** fragmentation in low-memory embedded systems.
+** </dd>
**
** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt>
-** <dd> ^This option specifies a static memory buffer that SQLite can use for
-** the database page cache with the default page cache implementation.
+** <dd> ^The SQLITE_CONFIG_PAGECACHE option specifies a static memory buffer
+** that SQLite can use for the database page cache with the default page
+** cache implementation.
** This configuration should not be used if an application-define page
-** cache implementation is loaded using the SQLITE_CONFIG_PCACHE2 option.
-** There are three arguments to this option: A pointer to 8-byte aligned
+** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2]
+** configuration option.
+** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to
+** 8-byte aligned
** memory, the size of each page buffer (sz), and the number of pages (N).
** The sz argument should be the size of the largest database page
-** (a power of two between 512 and 32768) plus a little extra for each
-** page header. ^The page header size is 20 to 40 bytes depending on
-** the host architecture. ^It is harmless, apart from the wasted memory,
-** to make sz a little too large. The first
-** argument should point to an allocation of at least sz*N bytes of memory.
+** (a power of two between 512 and 65536) plus some extra bytes for each
+** page header. ^The number of extra bytes needed by the page header
+** can be determined using the [SQLITE_CONFIG_PCACHE_HDRSZ] option
+** to [sqlite3_config()].
+** ^It is harmless, apart from the wasted memory,
+** for the sz parameter to be larger than necessary. The first
+** argument should pointer to an 8-byte aligned block of memory that
+** is at least sz*N bytes of memory, otherwise subsequent behavior is
+** undefined.
** ^SQLite will use the memory provided by the first argument to satisfy its
** memory needs for the first N pages that it adds to cache. ^If additional
** page cache memory is needed beyond what is provided by this option, then
-** SQLite goes to [sqlite3_malloc()] for the additional storage space.
-** The pointer in the first argument must
-** be aligned to an 8-byte boundary or subsequent behavior of SQLite
-** will be undefined.</dd>
+** SQLite goes to [sqlite3_malloc()] for the additional storage space.</dd>
**
** [[SQLITE_CONFIG_HEAP]] <dt>SQLITE_CONFIG_HEAP</dt>
-** <dd> ^This option specifies a static memory buffer that SQLite will use
-** for all of its dynamic memory allocation needs beyond those provided
-** for by [SQLITE_CONFIG_SCRATCH] and [SQLITE_CONFIG_PAGECACHE].
-** There are three arguments: An 8-byte aligned pointer to the memory,
+** <dd> ^The SQLITE_CONFIG_HEAP option specifies a static memory buffer
+** that SQLite will use for all of its dynamic memory allocation needs
+** beyond those provided for by [SQLITE_CONFIG_SCRATCH] and
+** [SQLITE_CONFIG_PAGECACHE].
+** ^The SQLITE_CONFIG_HEAP option is only available if SQLite is compiled
+** with either [SQLITE_ENABLE_MEMSYS3] or [SQLITE_ENABLE_MEMSYS5] and returns
+** [SQLITE_ERROR] if invoked otherwise.
+** ^There are three arguments to SQLITE_CONFIG_HEAP:
+** An 8-byte aligned pointer to the memory,
** the number of bytes in the memory buffer, and the minimum allocation size.
** ^If the first pointer (the memory pointer) is NULL, then SQLite reverts
** to using its default memory allocator (the system malloc() implementation),
** undoing any prior invocation of [SQLITE_CONFIG_MALLOC]. ^If the
-** memory pointer is not NULL and either [SQLITE_ENABLE_MEMSYS3] or
-** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory
+** memory pointer is not NULL then the alternative memory
** allocator is engaged to handle all of SQLites memory allocation needs.
** The first pointer (the memory pointer) must be aligned to an 8-byte
** boundary or subsequent behavior of SQLite will be undefined.
@@ -1704,11 +1838,11 @@ struct sqlite3_mem_methods {
** for the minimum allocation size are 2**5 through 2**8.</dd>
**
** [[SQLITE_CONFIG_MUTEX]] <dt>SQLITE_CONFIG_MUTEX</dt>
-** <dd> ^(This option takes a single argument which is a pointer to an
-** instance of the [sqlite3_mutex_methods] structure. The argument specifies
-** alternative low-level mutex routines to be used in place
-** the mutex routines built into SQLite.)^ ^SQLite makes a copy of the
-** content of the [sqlite3_mutex_methods] structure before the call to
+** <dd> ^(The SQLITE_CONFIG_MUTEX option takes a single argument which is a
+** pointer to an instance of the [sqlite3_mutex_methods] structure.
+** The argument specifies alternative low-level mutex routines to be used
+** in place the mutex routines built into SQLite.)^ ^SQLite makes a copy of
+** the content of the [sqlite3_mutex_methods] structure before the call to
** [sqlite3_config()] returns. ^If SQLite is compiled with
** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then
** the entire mutexing subsystem is omitted from the build and hence calls to
@@ -1716,8 +1850,8 @@ struct sqlite3_mem_methods {
** return [SQLITE_ERROR].</dd>
**
** [[SQLITE_CONFIG_GETMUTEX]] <dt>SQLITE_CONFIG_GETMUTEX</dt>
-** <dd> ^(This option takes a single argument which is a pointer to an
-** instance of the [sqlite3_mutex_methods] structure. The
+** <dd> ^(The SQLITE_CONFIG_GETMUTEX option takes a single argument which
+** is a pointer to an instance of the [sqlite3_mutex_methods] structure. The
** [sqlite3_mutex_methods]
** structure is filled with the currently defined mutex routines.)^
** This option can be used to overload the default mutex allocation
@@ -1729,25 +1863,25 @@ struct sqlite3_mem_methods {
** return [SQLITE_ERROR].</dd>
**
** [[SQLITE_CONFIG_LOOKASIDE]] <dt>SQLITE_CONFIG_LOOKASIDE</dt>
-** <dd> ^(This option takes two arguments that determine the default
-** memory allocation for the lookaside memory allocator on each
-** [database connection]. The first argument is the
+** <dd> ^(The SQLITE_CONFIG_LOOKASIDE option takes two arguments that determine
+** the default size of lookaside memory on each [database connection].
+** The first argument is the
** size of each lookaside buffer slot and the second is the number of
-** slots allocated to each database connection.)^ ^(This option sets the
-** <i>default</i> lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE]
-** verb to [sqlite3_db_config()] can be used to change the lookaside
+** slots allocated to each database connection.)^ ^(SQLITE_CONFIG_LOOKASIDE
+** sets the <i>default</i> lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE]
+** option to [sqlite3_db_config()] can be used to change the lookaside
** configuration on individual connections.)^ </dd>
**
** [[SQLITE_CONFIG_PCACHE2]] <dt>SQLITE_CONFIG_PCACHE2</dt>
-** <dd> ^(This option takes a single argument which is a pointer to
-** an [sqlite3_pcache_methods2] object. This object specifies the interface
-** to a custom page cache implementation.)^ ^SQLite makes a copy of the
-** object and uses it for page cache memory allocations.</dd>
+** <dd> ^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is
+** a pointer to an [sqlite3_pcache_methods2] object. This object specifies
+** the interface to a custom page cache implementation.)^
+** ^SQLite makes a copy of the [sqlite3_pcache_methods2] object.</dd>
**
** [[SQLITE_CONFIG_GETPCACHE2]] <dt>SQLITE_CONFIG_GETPCACHE2</dt>
-** <dd> ^(This option takes a single argument which is a pointer to an
-** [sqlite3_pcache_methods2] object. SQLite copies of the current
-** page cache implementation into that object.)^ </dd>
+** <dd> ^(The SQLITE_CONFIG_GETPCACHE2 option takes a single argument which
+** is a pointer to an [sqlite3_pcache_methods2] object. SQLite copies of
+** the current page cache implementation into that object.)^ </dd>
**
** [[SQLITE_CONFIG_LOG]] <dt>SQLITE_CONFIG_LOG</dt>
** <dd> The SQLITE_CONFIG_LOG option is used to configure the SQLite
@@ -1770,10 +1904,11 @@ struct sqlite3_mem_methods {
** function must be threadsafe. </dd>
**
** [[SQLITE_CONFIG_URI]] <dt>SQLITE_CONFIG_URI
-** <dd>^(This option takes a single argument of type int. If non-zero, then
-** URI handling is globally enabled. If the parameter is zero, then URI handling
-** is globally disabled.)^ ^If URI handling is globally enabled, all filenames
-** passed to [sqlite3_open()], [sqlite3_open_v2()], [sqlite3_open16()] or
+** <dd>^(The SQLITE_CONFIG_URI option takes a single argument of type int.
+** If non-zero, then URI handling is globally enabled. If the parameter is zero,
+** then URI handling is globally disabled.)^ ^If URI handling is globally
+** enabled, all filenames passed to [sqlite3_open()], [sqlite3_open_v2()],
+** [sqlite3_open16()] or
** specified as part of [ATTACH] commands are interpreted as URIs, regardless
** of whether or not the [SQLITE_OPEN_URI] flag is set when the database
** connection is opened. ^If it is globally disabled, filenames are
@@ -1783,9 +1918,10 @@ struct sqlite3_mem_methods {
** [SQLITE_USE_URI] symbol defined.)^
**
** [[SQLITE_CONFIG_COVERING_INDEX_SCAN]] <dt>SQLITE_CONFIG_COVERING_INDEX_SCAN
-** <dd>^This option takes a single integer argument which is interpreted as
-** a boolean in order to enable or disable the use of covering indices for
-** full table scans in the query optimizer. ^The default setting is determined
+** <dd>^The SQLITE_CONFIG_COVERING_INDEX_SCAN option takes a single integer
+** argument which is interpreted as a boolean in order to enable or disable
+** the use of covering indices for full table scans in the query optimizer.
+** ^The default setting is determined
** by the [SQLITE_ALLOW_COVERING_INDEX_SCAN] compile-time option, or is "on"
** if that compile-time option is omitted.
** The ability to disable the use of covering indices for full table scans
@@ -1825,18 +1961,37 @@ struct sqlite3_mem_methods {
** ^The default setting can be overridden by each database connection using
** either the [PRAGMA mmap_size] command, or by using the
** [SQLITE_FCNTL_MMAP_SIZE] file control. ^(The maximum allowed mmap size
-** cannot be changed at run-time. Nor may the maximum allowed mmap size
-** exceed the compile-time maximum mmap size set by the
+** will be silently truncated if necessary so that it does not exceed the
+** compile-time maximum mmap size set by the
** [SQLITE_MAX_MMAP_SIZE] compile-time option.)^
** ^If either argument to this option is negative, then that argument is
** changed to its compile-time default.
**
** [[SQLITE_CONFIG_WIN32_HEAPSIZE]]
** <dt>SQLITE_CONFIG_WIN32_HEAPSIZE
-** <dd>^This option is only available if SQLite is compiled for Windows
-** with the [SQLITE_WIN32_MALLOC] pre-processor macro defined.
-** SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value
+** <dd>^The SQLITE_CONFIG_WIN32_HEAPSIZE option is only available if SQLite is
+** compiled for Windows with the [SQLITE_WIN32_MALLOC] pre-processor macro
+** defined. ^SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value
** that specifies the maximum size of the created heap.
+**
+** [[SQLITE_CONFIG_PCACHE_HDRSZ]]
+** <dt>SQLITE_CONFIG_PCACHE_HDRSZ
+** <dd>^The SQLITE_CONFIG_PCACHE_HDRSZ option takes a single parameter which
+** is a pointer to an integer and writes into that integer the number of extra
+** bytes per page required for each page in [SQLITE_CONFIG_PAGECACHE].
+** The amount of extra space required can change depending on the compiler,
+** target platform, and SQLite version.
+**
+** [[SQLITE_CONFIG_PMASZ]]
+** <dt>SQLITE_CONFIG_PMASZ
+** <dd>^The SQLITE_CONFIG_PMASZ option takes a single parameter which
+** is an unsigned integer and sets the "Minimum PMA Size" for the multithreaded
+** sorter to that integer. The default minimum PMA Size is set by the
+** [SQLITE_SORTER_PMASZ] compile-time option. New threads are launched
+** to help with sort operations when multithreaded sorting
+** is enabled (using the [PRAGMA threads] command) and the amount of content
+** to be sorted exceeds the page size times the minimum of the
+** [PRAGMA cache_size] setting and this value.
** </dl>
*/
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
@@ -1862,6 +2017,8 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */
#define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */
+#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */
+#define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */
/*
** CAPI3REF: Database Connection Configuration Options
@@ -1928,15 +2085,17 @@ struct sqlite3_mem_methods {
/*
** CAPI3REF: Enable Or Disable Extended Result Codes
+** METHOD: sqlite3
**
** ^The sqlite3_extended_result_codes() routine enables or disables the
** [extended result codes] feature of SQLite. ^The extended result
** codes are disabled by default for historical compatibility.
*/
-SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff);
+SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3*, int onoff);
/*
** CAPI3REF: Last Insert Rowid
+** METHOD: sqlite3
**
** ^Each entry in most SQLite tables (except for [WITHOUT ROWID] tables)
** has a unique 64-bit signed
@@ -1984,52 +2143,51 @@ SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff);
** unpredictable and might not equal either the old or the new
** last insert [rowid].
*/
-SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_last_insert_rowid(sqlite3*);
/*
** CAPI3REF: Count The Number Of Rows Modified
+** METHOD: sqlite3
+**
+** ^This function returns the number of rows modified, inserted or
+** deleted by the most recently completed INSERT, UPDATE or DELETE
+** statement on the database connection specified by the only parameter.
+** ^Executing any other type of SQL statement does not modify the value
+** returned by this function.
**
-** ^This function returns the number of database rows that were changed
-** or inserted or deleted by the most recently completed SQL statement
-** on the [database connection] specified by the first parameter.
-** ^(Only changes that are directly specified by the [INSERT], [UPDATE],
-** or [DELETE] statement are counted. Auxiliary changes caused by
-** triggers or [foreign key actions] are not counted.)^ Use the
-** [sqlite3_total_changes()] function to find the total number of changes
-** including changes caused by triggers and foreign key actions.
-**
-** ^Changes to a view that are simulated by an [INSTEAD OF trigger]
-** are not counted. Only real table changes are counted.
-**
-** ^(A "row change" is a change to a single row of a single table
-** caused by an INSERT, DELETE, or UPDATE statement. Rows that
-** are changed as side effects of [REPLACE] constraint resolution,
-** rollback, ABORT processing, [DROP TABLE], or by any other
-** mechanisms do not count as direct row changes.)^
-**
-** A "trigger context" is a scope of execution that begins and
-** ends with the script of a [CREATE TRIGGER | trigger].
-** Most SQL statements are
-** evaluated outside of any trigger. This is the "top level"
-** trigger context. If a trigger fires from the top level, a
-** new trigger context is entered for the duration of that one
-** trigger. Subtriggers create subcontexts for their duration.
-**
-** ^Calling [sqlite3_exec()] or [sqlite3_step()] recursively does
-** not create a new trigger context.
-**
-** ^This function returns the number of direct row changes in the
-** most recent INSERT, UPDATE, or DELETE statement within the same
-** trigger context.
-**
-** ^Thus, when called from the top level, this function returns the
-** number of changes in the most recent INSERT, UPDATE, or DELETE
-** that also occurred at the top level. ^(Within the body of a trigger,
-** the sqlite3_changes() interface can be called to find the number of
-** changes in the most recently completed INSERT, UPDATE, or DELETE
-** statement within the body of the same trigger.
-** However, the number returned does not include changes
-** caused by subtriggers since those have their own context.)^
+** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are
+** considered - auxiliary changes caused by [CREATE TRIGGER | triggers],
+** [foreign key actions] or [REPLACE] constraint resolution are not counted.
+**
+** Changes to a view that are intercepted by
+** [INSTEAD OF trigger | INSTEAD OF triggers] are not counted. ^The value
+** returned by sqlite3_changes() immediately after an INSERT, UPDATE or
+** DELETE statement run on a view is always zero. Only changes made to real
+** tables are counted.
+**
+** Things are more complicated if the sqlite3_changes() function is
+** executed while a trigger program is running. This may happen if the
+** program uses the [changes() SQL function], or if some other callback
+** function invokes sqlite3_changes() directly. Essentially:
+**
+** <ul>
+** <li> ^(Before entering a trigger program the value returned by
+** sqlite3_changes() function is saved. After the trigger program
+** has finished, the original value is restored.)^
+**
+** <li> ^(Within a trigger program each INSERT, UPDATE and DELETE
+** statement sets the value returned by sqlite3_changes()
+** upon completion as normal. Of course, this value will not include
+** any changes performed by sub-triggers, as the sqlite3_changes()
+** value will be saved and restored after each sub-trigger has run.)^
+** </ul>
+**
+** ^This means that if the changes() SQL function (or similar) is used
+** by the first INSERT, UPDATE or DELETE statement within a trigger, it
+** returns the value as set when the calling statement began executing.
+** ^If it is used by the second or subsequent such statement within a trigger
+** program, the value returned reflects the number of rows modified by the
+** previous INSERT, UPDATE or DELETE statement within the same trigger.
**
** See also the [sqlite3_total_changes()] interface, the
** [count_changes pragma], and the [changes() SQL function].
@@ -2038,25 +2196,23 @@ SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
** while [sqlite3_changes()] is running then the value returned
** is unpredictable and not meaningful.
*/
-SQLITE_API int sqlite3_changes(sqlite3*);
+SQLITE_API int SQLITE_STDCALL sqlite3_changes(sqlite3*);
/*
** CAPI3REF: Total Number Of Rows Modified
+** METHOD: sqlite3
**
-** ^This function returns the number of row changes caused by [INSERT],
-** [UPDATE] or [DELETE] statements since the [database connection] was opened.
-** ^(The count returned by sqlite3_total_changes() includes all changes
-** from all [CREATE TRIGGER | trigger] contexts and changes made by
-** [foreign key actions]. However,
-** the count does not include changes used to implement [REPLACE] constraints,
-** do rollbacks or ABORT processing, or [DROP TABLE] processing. The
-** count does not include rows of views that fire an [INSTEAD OF trigger],
-** though if the INSTEAD OF trigger makes changes of its own, those changes
-** are counted.)^
-** ^The sqlite3_total_changes() function counts the changes as soon as
-** the statement that makes them is completed (when the statement handle
-** is passed to [sqlite3_reset()] or [sqlite3_finalize()]).
-**
+** ^This function returns the total number of rows inserted, modified or
+** deleted by all [INSERT], [UPDATE] or [DELETE] statements completed
+** since the database connection was opened, including those executed as
+** part of trigger programs. ^Executing any other type of SQL statement
+** does not affect the value returned by sqlite3_total_changes().
+**
+** ^Changes made as part of [foreign key actions] are included in the
+** count, but those made as part of REPLACE constraint resolution are
+** not. ^Changes to a view that are intercepted by INSTEAD OF triggers
+** are not counted.
+**
** See also the [sqlite3_changes()] interface, the
** [count_changes pragma], and the [total_changes() SQL function].
**
@@ -2064,10 +2220,11 @@ SQLITE_API int sqlite3_changes(sqlite3*);
** while [sqlite3_total_changes()] is running then the value
** returned is unpredictable and not meaningful.
*/
-SQLITE_API int sqlite3_total_changes(sqlite3*);
+SQLITE_API int SQLITE_STDCALL sqlite3_total_changes(sqlite3*);
/*
** CAPI3REF: Interrupt A Long-Running Query
+** METHOD: sqlite3
**
** ^This function causes any pending database operation to abort and
** return at its earliest opportunity. This routine is typically
@@ -2103,7 +2260,7 @@ SQLITE_API int sqlite3_total_changes(sqlite3*);
** If the database connection closes while [sqlite3_interrupt()]
** is running then bad things will likely happen.
*/
-SQLITE_API void sqlite3_interrupt(sqlite3*);
+SQLITE_API void SQLITE_STDCALL sqlite3_interrupt(sqlite3*);
/*
** CAPI3REF: Determine If An SQL Statement Is Complete
@@ -2138,11 +2295,13 @@ SQLITE_API void sqlite3_interrupt(sqlite3*);
** The input to [sqlite3_complete16()] must be a zero-terminated
** UTF-16 string in native byte order.
*/
-SQLITE_API int sqlite3_complete(const char *sql);
-SQLITE_API int sqlite3_complete16(const void *sql);
+SQLITE_API int SQLITE_STDCALL sqlite3_complete(const char *sql);
+SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *sql);
/*
** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors
+** KEYWORDS: {busy-handler callback} {busy handler}
+** METHOD: sqlite3
**
** ^The sqlite3_busy_handler(D,X,P) routine sets a callback function X
** that might be invoked with argument P whenever
@@ -2159,7 +2318,7 @@ SQLITE_API int sqlite3_complete16(const void *sql);
** ^The first argument to the busy handler is a copy of the void* pointer which
** is the third argument to sqlite3_busy_handler(). ^The second argument to
** the busy handler callback is the number of times that the busy handler has
-** been invoked for the same locking event. ^If the
+** been invoked previously for the same locking event. ^If the
** busy callback returns 0, then no additional attempts are made to
** access the database and [SQLITE_BUSY] is returned
** to the application.
@@ -2198,10 +2357,11 @@ SQLITE_API int sqlite3_complete16(const void *sql);
** A busy handler must not close the database connection
** or [prepared statement] that invoked the busy handler.
*/
-SQLITE_API int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
+SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
/*
** CAPI3REF: Set A Busy Timeout
+** METHOD: sqlite3
**
** ^This routine sets a [sqlite3_busy_handler | busy handler] that sleeps
** for a specified amount of time when a table is locked. ^The handler
@@ -2214,16 +2374,17 @@ SQLITE_API int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
** turns off all busy handlers.
**
** ^(There can only be a single busy handler for a particular
-** [database connection] any any given moment. If another busy handler
+** [database connection] at any given moment. If another busy handler
** was defined (using [sqlite3_busy_handler()]) prior to calling
** this routine, that other busy handler is cleared.)^
**
** See also: [PRAGMA busy_timeout]
*/
-SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
+SQLITE_API int SQLITE_STDCALL sqlite3_busy_timeout(sqlite3*, int ms);
/*
** CAPI3REF: Convenience Routines For Running Queries
+** METHOD: sqlite3
**
** This is a legacy interface that is preserved for backwards compatibility.
** Use of this interface is not recommended.
@@ -2294,7 +2455,7 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
** reflected in subsequent calls to [sqlite3_errcode()] or
** [sqlite3_errmsg()].
*/
-SQLITE_API int sqlite3_get_table(
+SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
sqlite3 *db, /* An open database */
const char *zSql, /* SQL to be evaluated */
char ***pazResult, /* Results of the query */
@@ -2302,13 +2463,17 @@ SQLITE_API int sqlite3_get_table(
int *pnColumn, /* Number of result columns written here */
char **pzErrmsg /* Error msg written here */
);
-SQLITE_API void sqlite3_free_table(char **result);
+SQLITE_API void SQLITE_STDCALL sqlite3_free_table(char **result);
/*
** CAPI3REF: Formatted String Printing Functions
**
** These routines are work-alikes of the "printf()" family of functions
** from the standard C library.
+** These routines understand most of the common K&R formatting options,
+** plus some additional non-standard formats, detailed below.
+** Note that some of the more obscure formatting options from recent
+** C-library standards are omitted from this implementation.
**
** ^The sqlite3_mprintf() and sqlite3_vmprintf() routines write their
** results into memory obtained from [sqlite3_malloc()].
@@ -2341,7 +2506,7 @@ SQLITE_API void sqlite3_free_table(char **result);
** These routines all implement some additional formatting
** options that are useful for constructing SQL statements.
** All of the usual printf() formatting options apply. In addition, there
-** is are "%q", "%Q", and "%z" options.
+** is are "%q", "%Q", "%w" and "%z" options.
**
** ^(The %q option works like %s in that it substitutes a nul-terminated
** string from the argument list. But %q also doubles every '\'' character.
@@ -2394,14 +2559,20 @@ SQLITE_API void sqlite3_free_table(char **result);
** The code above will render a correct SQL statement in the zSQL
** variable even if the zText variable is a NULL pointer.
**
+** ^(The "%w" formatting option is like "%q" except that it expects to
+** be contained within double-quotes instead of single quotes, and it
+** escapes the double-quote character instead of the single-quote
+** character.)^ The "%w" formatting option is intended for safely inserting
+** table and column names into a constructed SQL statement.
+**
** ^(The "%z" formatting option works like "%s" but with the
** addition that after the string has been read and copied into
** the result, [sqlite3_free()] is called on the input string.)^
*/
-SQLITE_API char *sqlite3_mprintf(const char*,...);
-SQLITE_API char *sqlite3_vmprintf(const char*, va_list);
-SQLITE_API char *sqlite3_snprintf(int,char*,const char*, ...);
-SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
+SQLITE_API char *SQLITE_CDECL sqlite3_mprintf(const char*,...);
+SQLITE_API char *SQLITE_STDCALL sqlite3_vmprintf(const char*, va_list);
+SQLITE_API char *SQLITE_CDECL sqlite3_snprintf(int,char*,const char*, ...);
+SQLITE_API char *SQLITE_STDCALL sqlite3_vsnprintf(int,char*,const char*, va_list);
/*
** CAPI3REF: Memory Allocation Subsystem
@@ -2418,6 +2589,10 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
** sqlite3_malloc() is zero or negative then sqlite3_malloc() returns
** a NULL pointer.
**
+** ^The sqlite3_malloc64(N) routine works just like
+** sqlite3_malloc(N) except that N is an unsigned 64-bit integer instead
+** of a signed 32-bit integer.
+**
** ^Calling sqlite3_free() with a pointer previously returned
** by sqlite3_malloc() or sqlite3_realloc() releases that memory so
** that it might be reused. ^The sqlite3_free() routine is
@@ -2429,24 +2604,38 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
** might result if sqlite3_free() is called with a non-NULL pointer that
** was not obtained from sqlite3_malloc() or sqlite3_realloc().
**
-** ^(The sqlite3_realloc() interface attempts to resize a
-** prior memory allocation to be at least N bytes, where N is the
-** second parameter. The memory allocation to be resized is the first
-** parameter.)^ ^ If the first parameter to sqlite3_realloc()
+** ^The sqlite3_realloc(X,N) interface attempts to resize a
+** prior memory allocation X to be at least N bytes.
+** ^If the X parameter to sqlite3_realloc(X,N)
** is a NULL pointer then its behavior is identical to calling
-** sqlite3_malloc(N) where N is the second parameter to sqlite3_realloc().
-** ^If the second parameter to sqlite3_realloc() is zero or
+** sqlite3_malloc(N).
+** ^If the N parameter to sqlite3_realloc(X,N) is zero or
** negative then the behavior is exactly the same as calling
-** sqlite3_free(P) where P is the first parameter to sqlite3_realloc().
-** ^sqlite3_realloc() returns a pointer to a memory allocation
-** of at least N bytes in size or NULL if sufficient memory is unavailable.
+** sqlite3_free(X).
+** ^sqlite3_realloc(X,N) returns a pointer to a memory allocation
+** of at least N bytes in size or NULL if insufficient memory is available.
** ^If M is the size of the prior allocation, then min(N,M) bytes
** of the prior allocation are copied into the beginning of buffer returned
-** by sqlite3_realloc() and the prior allocation is freed.
-** ^If sqlite3_realloc() returns NULL, then the prior allocation
-** is not freed.
-**
-** ^The memory returned by sqlite3_malloc() and sqlite3_realloc()
+** by sqlite3_realloc(X,N) and the prior allocation is freed.
+** ^If sqlite3_realloc(X,N) returns NULL and N is positive, then the
+** prior allocation is not freed.
+**
+** ^The sqlite3_realloc64(X,N) interfaces works the same as
+** sqlite3_realloc(X,N) except that N is a 64-bit unsigned integer instead
+** of a 32-bit signed integer.
+**
+** ^If X is a memory allocation previously obtained from sqlite3_malloc(),
+** sqlite3_malloc64(), sqlite3_realloc(), or sqlite3_realloc64(), then
+** sqlite3_msize(X) returns the size of that memory allocation in bytes.
+** ^The value returned by sqlite3_msize(X) might be larger than the number
+** of bytes requested when X was allocated. ^If X is a NULL pointer then
+** sqlite3_msize(X) returns zero. If X points to something that is not
+** the beginning of memory allocation, or if it points to a formerly
+** valid memory allocation that has now been freed, then the behavior
+** of sqlite3_msize(X) is undefined and possibly harmful.
+**
+** ^The memory returned by sqlite3_malloc(), sqlite3_realloc(),
+** sqlite3_malloc64(), and sqlite3_realloc64()
** is always aligned to at least an 8 byte boundary, or to a
** 4 byte boundary if the [SQLITE_4_BYTE_ALIGNED_MALLOC] compile-time
** option is used.
@@ -2473,9 +2662,12 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
** a block of memory after it has been released using
** [sqlite3_free()] or [sqlite3_realloc()].
*/
-SQLITE_API void *sqlite3_malloc(int);
-SQLITE_API void *sqlite3_realloc(void*, int);
-SQLITE_API void sqlite3_free(void*);
+SQLITE_API void *SQLITE_STDCALL sqlite3_malloc(int);
+SQLITE_API void *SQLITE_STDCALL sqlite3_malloc64(sqlite3_uint64);
+SQLITE_API void *SQLITE_STDCALL sqlite3_realloc(void*, int);
+SQLITE_API void *SQLITE_STDCALL sqlite3_realloc64(void*, sqlite3_uint64);
+SQLITE_API void SQLITE_STDCALL sqlite3_free(void*);
+SQLITE_API sqlite3_uint64 SQLITE_STDCALL sqlite3_msize(void*);
/*
** CAPI3REF: Memory Allocator Statistics
@@ -2500,8 +2692,8 @@ SQLITE_API void sqlite3_free(void*);
** by [sqlite3_memory_highwater(1)] is the high-water mark
** prior to the reset.
*/
-SQLITE_API sqlite3_int64 sqlite3_memory_used(void);
-SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag);
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_used(void);
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_highwater(int resetFlag);
/*
** CAPI3REF: Pseudo-Random Number Generator
@@ -2513,20 +2705,22 @@ SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag);
** applications to access the same PRNG for other purposes.
**
** ^A call to this routine stores N bytes of randomness into buffer P.
-** ^If N is less than one, then P can be a NULL pointer.
+** ^The P parameter can be a NULL pointer.
**
** ^If this routine has not been previously called or if the previous
-** call had N less than one, then the PRNG is seeded using randomness
-** obtained from the xRandomness method of the default [sqlite3_vfs] object.
-** ^If the previous call to this routine had an N of 1 or more then
-** the pseudo-randomness is generated
+** call had N less than one or a NULL pointer for P, then the PRNG is
+** seeded using randomness obtained from the xRandomness method of
+** the default [sqlite3_vfs] object.
+** ^If the previous call to this routine had an N of 1 or more and a
+** non-NULL P then the pseudo-randomness is generated
** internally and without recourse to the [sqlite3_vfs] xRandomness
** method.
*/
-SQLITE_API void sqlite3_randomness(int N, void *P);
+SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *P);
/*
** CAPI3REF: Compile-Time Authorization Callbacks
+** METHOD: sqlite3
**
** ^This routine registers an authorizer callback with a particular
** [database connection], supplied in the first argument.
@@ -2605,7 +2799,7 @@ SQLITE_API void sqlite3_randomness(int N, void *P);
** as stated in the previous paragraph, sqlite3_step() invokes
** sqlite3_prepare_v2() to reprepare a statement after a schema change.
*/
-SQLITE_API int sqlite3_set_authorizer(
+SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer(
sqlite3*,
int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
void *pUserData
@@ -2683,6 +2877,7 @@ SQLITE_API int sqlite3_set_authorizer(
/*
** CAPI3REF: Tracing And Profiling Functions
+** METHOD: sqlite3
**
** These routines register callback functions that can be used for
** tracing and profiling the execution of SQL statements.
@@ -2709,12 +2904,13 @@ SQLITE_API int sqlite3_set_authorizer(
** sqlite3_profile() function is considered experimental and is
** subject to change in future versions of SQLite.
*/
-SQLITE_API void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
-SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_profile(sqlite3*,
+SQLITE_API void *SQLITE_STDCALL sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
+SQLITE_API SQLITE_EXPERIMENTAL void *SQLITE_STDCALL sqlite3_profile(sqlite3*,
void(*xProfile)(void*,const char*,sqlite3_uint64), void*);
/*
** CAPI3REF: Query Progress Callbacks
+** METHOD: sqlite3
**
** ^The sqlite3_progress_handler(D,N,X,P) interface causes the callback
** function X to be invoked periodically during long running calls to
@@ -2744,10 +2940,11 @@ SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_profile(sqlite3*,
** database connections for the meaning of "modify" in this paragraph.
**
*/
-SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
+SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
/*
** CAPI3REF: Opening A New Database Connection
+** CONSTRUCTOR: sqlite3
**
** ^These routines open an SQLite database file as specified by the
** filename argument. ^The filename argument is interpreted as UTF-8 for
@@ -2762,9 +2959,9 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** an English language description of the error following a failure of any
** of the sqlite3_open() routines.
**
-** ^The default encoding for the database will be UTF-8 if
-** sqlite3_open() or sqlite3_open_v2() is called and
-** UTF-16 in the native byte order if sqlite3_open16() is used.
+** ^The default encoding will be UTF-8 for databases created using
+** sqlite3_open() or sqlite3_open_v2(). ^The default encoding for databases
+** created using sqlite3_open16() will be UTF-16 in the native byte order.
**
** Whether or not an error occurs when it is opened, resources
** associated with the [database connection] handle should be released by
@@ -2852,13 +3049,14 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** then it is interpreted as an absolute path. ^If the path does not begin
** with a '/' (meaning that the authority section is omitted from the URI)
** then the path is interpreted as a relative path.
-** ^On windows, the first component of an absolute path
-** is a drive specification (e.g. "C:").
+** ^(On windows, the first component of an absolute path
+** is a drive specification (e.g. "C:").)^
**
** [[core URI query parameters]]
** The query component of a URI may contain parameters that are interpreted
** either by SQLite itself, or by a [VFS | custom VFS implementation].
-** SQLite interprets the following three query parameters:
+** SQLite and its built-in [VFSes] interpret the
+** following query parameters:
**
** <ul>
** <li> <b>vfs</b>: ^The "vfs" parameter may be used to specify the name of
@@ -2893,11 +3091,9 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** a URI filename, its value overrides any behavior requested by setting
** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag.
**
-** <li> <b>psow</b>: ^The psow parameter may be "true" (or "on" or "yes" or
-** "1") or "false" (or "off" or "no" or "0") to indicate that the
+** <li> <b>psow</b>: ^The psow parameter indicates whether or not the
** [powersafe overwrite] property does or does not apply to the
-** storage media on which the database file resides. ^The psow query
-** parameter only works for the built-in unix and Windows VFSes.
+** storage media on which the database file resides.
**
** <li> <b>nolock</b>: ^The nolock parameter is a boolean query parameter
** which if set disables file locking in rollback journal modes. This
@@ -2973,15 +3169,15 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
**
** See also: [sqlite3_temp_directory]
*/
-SQLITE_API int sqlite3_open(
+SQLITE_API int SQLITE_STDCALL sqlite3_open(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb /* OUT: SQLite db handle */
);
-SQLITE_API int sqlite3_open16(
+SQLITE_API int SQLITE_STDCALL sqlite3_open16(
const void *filename, /* Database filename (UTF-16) */
sqlite3 **ppDb /* OUT: SQLite db handle */
);
-SQLITE_API int sqlite3_open_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_open_v2(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb, /* OUT: SQLite db handle */
int flags, /* Flags */
@@ -3027,19 +3223,22 @@ SQLITE_API int sqlite3_open_v2(
** VFS method, then the behavior of this routine is undefined and probably
** undesirable.
*/
-SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam);
-SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
-SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_uri_parameter(const char *zFilename, const char *zParam);
+SQLITE_API int SQLITE_STDCALL sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
/*
** CAPI3REF: Error Codes And Messages
-**
-** ^The sqlite3_errcode() interface returns the numeric [result code] or
-** [extended result code] for the most recent failed sqlite3_* API call
-** associated with a [database connection]. If a prior API call failed
-** but the most recent API call succeeded, the return value from
-** sqlite3_errcode() is undefined. ^The sqlite3_extended_errcode()
+** METHOD: sqlite3
+**
+** ^If the most recent sqlite3_* API call associated with
+** [database connection] D failed, then the sqlite3_errcode(D) interface
+** returns the numeric [result code] or [extended result code] for that
+** API call.
+** If the most recent API call was successful,
+** then the return value from sqlite3_errcode() is undefined.
+** ^The sqlite3_extended_errcode()
** interface is the same except that it always returns the
** [extended result code] even when extended result codes are
** disabled.
@@ -3070,40 +3269,41 @@ SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int
** was invoked incorrectly by the application. In that case, the
** error code and message may or may not be set.
*/
-SQLITE_API int sqlite3_errcode(sqlite3 *db);
-SQLITE_API int sqlite3_extended_errcode(sqlite3 *db);
-SQLITE_API const char *sqlite3_errmsg(sqlite3*);
-SQLITE_API const void *sqlite3_errmsg16(sqlite3*);
-SQLITE_API const char *sqlite3_errstr(int);
+SQLITE_API int SQLITE_STDCALL sqlite3_errcode(sqlite3 *db);
+SQLITE_API int SQLITE_STDCALL sqlite3_extended_errcode(sqlite3 *db);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_errmsg(sqlite3*);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_errmsg16(sqlite3*);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_errstr(int);
/*
-** CAPI3REF: SQL Statement Object
+** CAPI3REF: Prepared Statement Object
** KEYWORDS: {prepared statement} {prepared statements}
**
-** An instance of this object represents a single SQL statement.
-** This object is variously known as a "prepared statement" or a
-** "compiled SQL statement" or simply as a "statement".
+** An instance of this object represents a single SQL statement that
+** has been compiled into binary form and is ready to be evaluated.
**
-** The life of a statement object goes something like this:
+** Think of each SQL statement as a separate computer program. The
+** original SQL text is source code. A prepared statement object
+** is the compiled object code. All SQL must be converted into a
+** prepared statement before it can be run.
+**
+** The life-cycle of a prepared statement object usually goes like this:
**
** <ol>
-** <li> Create the object using [sqlite3_prepare_v2()] or a related
-** function.
-** <li> Bind values to [host parameters] using the sqlite3_bind_*()
+** <li> Create the prepared statement object using [sqlite3_prepare_v2()].
+** <li> Bind values to [parameters] using the sqlite3_bind_*()
** interfaces.
** <li> Run the SQL by calling [sqlite3_step()] one or more times.
-** <li> Reset the statement using [sqlite3_reset()] then go back
+** <li> Reset the prepared statement using [sqlite3_reset()] then go back
** to step 2. Do this zero or more times.
** <li> Destroy the object using [sqlite3_finalize()].
** </ol>
-**
-** Refer to documentation on individual methods above for additional
-** information.
*/
typedef struct sqlite3_stmt sqlite3_stmt;
/*
** CAPI3REF: Run-time Limits
+** METHOD: sqlite3
**
** ^(This interface allows the size of various constructs to be limited
** on a connection by connection basis. The first parameter is the
@@ -3141,7 +3341,7 @@ typedef struct sqlite3_stmt sqlite3_stmt;
**
** New run-time limit categories may be added in future releases.
*/
-SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
+SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal);
/*
** CAPI3REF: Run-Time Limit Categories
@@ -3193,6 +3393,10 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
**
** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(<dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt>
** <dd>The maximum depth of recursion for triggers.</dd>)^
+**
+** [[SQLITE_LIMIT_WORKER_THREADS]] ^(<dt>SQLITE_LIMIT_WORKER_THREADS</dt>
+** <dd>The maximum number of auxiliary worker threads that a single
+** [prepared statement] may start.</dd>)^
** </dl>
*/
#define SQLITE_LIMIT_LENGTH 0
@@ -3206,10 +3410,13 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
#define SQLITE_LIMIT_LIKE_PATTERN_LENGTH 8
#define SQLITE_LIMIT_VARIABLE_NUMBER 9
#define SQLITE_LIMIT_TRIGGER_DEPTH 10
+#define SQLITE_LIMIT_WORKER_THREADS 11
/*
** CAPI3REF: Compiling An SQL Statement
** KEYWORDS: {SQL statement compiler}
+** METHOD: sqlite3
+** CONSTRUCTOR: sqlite3_stmt
**
** To execute an SQL query, it must first be compiled into a byte-code
** program using one of these routines.
@@ -3223,16 +3430,14 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** interfaces use UTF-8, and sqlite3_prepare16() and sqlite3_prepare16_v2()
** use UTF-16.
**
-** ^If the nByte argument is less than zero, then zSql is read up to the
-** first zero terminator. ^If nByte is non-negative, then it is the maximum
-** number of bytes read from zSql. ^When nByte is non-negative, the
-** zSql string ends at either the first '\000' or '\u0000' character or
-** the nByte-th byte, whichever comes first. If the caller knows
-** that the supplied string is nul-terminated, then there is a small
-** performance advantage to be gained by passing an nByte parameter that
-** is equal to the number of bytes in the input string <i>including</i>
-** the nul-terminator bytes as this saves SQLite from having to
-** make a copy of the input string.
+** ^If the nByte argument is negative, then zSql is read up to the
+** first zero terminator. ^If nByte is positive, then it is the
+** number of bytes read from zSql. ^If nByte is zero, then no prepared
+** statement is generated.
+** If the caller knows that the supplied string is nul-terminated, then
+** there is a small performance advantage to passing an nByte parameter that
+** is the number of bytes in the input string <i>including</i>
+** the nul-terminator.
**
** ^If pzTail is not NULL then *pzTail is made to point to the first byte
** past the end of the first SQL statement in zSql. These routines only
@@ -3288,28 +3493,28 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** </li>
** </ol>
*/
-SQLITE_API int sqlite3_prepare(
+SQLITE_API int SQLITE_STDCALL sqlite3_prepare(
sqlite3 *db, /* Database handle */
const char *zSql, /* SQL statement, UTF-8 encoded */
int nByte, /* Maximum length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const char **pzTail /* OUT: Pointer to unused portion of zSql */
);
-SQLITE_API int sqlite3_prepare_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_prepare_v2(
sqlite3 *db, /* Database handle */
const char *zSql, /* SQL statement, UTF-8 encoded */
int nByte, /* Maximum length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const char **pzTail /* OUT: Pointer to unused portion of zSql */
);
-SQLITE_API int sqlite3_prepare16(
+SQLITE_API int SQLITE_STDCALL sqlite3_prepare16(
sqlite3 *db, /* Database handle */
const void *zSql, /* SQL statement, UTF-16 encoded */
int nByte, /* Maximum length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const void **pzTail /* OUT: Pointer to unused portion of zSql */
);
-SQLITE_API int sqlite3_prepare16_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_prepare16_v2(
sqlite3 *db, /* Database handle */
const void *zSql, /* SQL statement, UTF-16 encoded */
int nByte, /* Maximum length of zSql in bytes. */
@@ -3319,15 +3524,17 @@ SQLITE_API int sqlite3_prepare16_v2(
/*
** CAPI3REF: Retrieving Statement SQL
+** METHOD: sqlite3_stmt
**
** ^This interface can be used to retrieve a saved copy of the original
** SQL text used to create a [prepared statement] if that statement was
** compiled using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()].
*/
-SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Determine If An SQL Statement Writes The Database
+** METHOD: sqlite3_stmt
**
** ^The sqlite3_stmt_readonly(X) interface returns true (non-zero) if
** and only if the [prepared statement] X makes no direct changes to
@@ -3355,10 +3562,11 @@ SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt);
** change the configuration of a database connection, they do not make
** changes to the content of the database files on disk.
*/
-SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
+SQLITE_API int SQLITE_STDCALL sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Determine If A Prepared Statement Has Been Reset
+** METHOD: sqlite3_stmt
**
** ^The sqlite3_stmt_busy(S) interface returns true (non-zero) if the
** [prepared statement] S has been stepped at least once using
@@ -3374,7 +3582,7 @@ SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
** for example, in diagnostic routines to search for prepared
** statements that are holding a transaction open.
*/
-SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
+SQLITE_API int SQLITE_STDCALL sqlite3_stmt_busy(sqlite3_stmt*);
/*
** CAPI3REF: Dynamically Typed Value Object
@@ -3433,6 +3641,7 @@ typedef struct sqlite3_context sqlite3_context;
** CAPI3REF: Binding Values To Prepared Statements
** KEYWORDS: {host parameter} {host parameters} {host parameter name}
** KEYWORDS: {SQL parameter} {SQL parameters} {parameter binding}
+** METHOD: sqlite3_stmt
**
** ^(In the SQL statement text input to [sqlite3_prepare_v2()] and its variants,
** literals may be replaced by a [parameter] that matches one of following
@@ -3479,18 +3688,18 @@ typedef struct sqlite3_context sqlite3_context;
** If the fourth parameter to sqlite3_bind_blob() is negative, then
** the behavior is undefined.
** If a non-negative fourth parameter is provided to sqlite3_bind_text()
-** or sqlite3_bind_text16() then that parameter must be the byte offset
+** 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
** 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.
**
-** ^The fifth argument to sqlite3_bind_blob(), sqlite3_bind_text(), and
-** sqlite3_bind_text16() is a destructor used to dispose of the BLOB or
+** ^The fifth argument to the BLOB and string binding interfaces
+** is a destructor used to dispose of the BLOB or
** string after SQLite has finished with it. ^The destructor is called
-** to dispose of the BLOB or string even if the call to sqlite3_bind_blob(),
-** sqlite3_bind_text(), or sqlite3_bind_text16() fails.
+** to dispose of the BLOB or string even if the call to bind API fails.
** ^If the fifth argument is
** the special value [SQLITE_STATIC], then SQLite assumes that the
** information is in static, unmanaged space and does not need to be freed.
@@ -3498,6 +3707,14 @@ typedef struct sqlite3_context sqlite3_context;
** SQLite makes its own private copy of the data immediately, before
** the sqlite3_bind_*() routine returns.
**
+** ^The sixth argument to sqlite3_bind_text64() must be one of
+** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]
+** to specify the encoding of the text in the third parameter. If
+** the sixth argument to sqlite3_bind_text64() is not one of the
+** allowed values shown above, or if the text encoding is different
+** from the encoding specified by the sixth parameter, then the behavior
+** is undefined.
+**
** ^The sqlite3_bind_zeroblob() routine binds a BLOB of length N that
** is filled with zeroes. ^A zeroblob uses a fixed amount of memory
** (just an integer to hold its size) while it is being processed.
@@ -3518,24 +3735,32 @@ typedef struct sqlite3_context sqlite3_context;
**
** ^The sqlite3_bind_* routines return [SQLITE_OK] on success or an
** [error code] if anything goes wrong.
+** ^[SQLITE_TOOBIG] might be returned if the size of a string or BLOB
+** exceeds limits imposed by [sqlite3_limit]([SQLITE_LIMIT_LENGTH]) or
+** [SQLITE_MAX_LENGTH].
** ^[SQLITE_RANGE] is returned if the parameter
** index is out of range. ^[SQLITE_NOMEM] is returned if malloc() fails.
**
** See also: [sqlite3_bind_parameter_count()],
** [sqlite3_bind_parameter_name()], and [sqlite3_bind_parameter_index()].
*/
-SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
-SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double);
-SQLITE_API int sqlite3_bind_int(sqlite3_stmt*, int, int);
-SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
-SQLITE_API int sqlite3_bind_null(sqlite3_stmt*, int);
-SQLITE_API int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*));
-SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
-SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
-SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64,
+ void(*)(void*));
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_double(sqlite3_stmt*, int, double);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_int(sqlite3_stmt*, int, int);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_null(sqlite3_stmt*, int);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*));
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64,
+ void(*)(void*), unsigned char encoding);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
/*
** CAPI3REF: Number Of SQL Parameters
+** METHOD: sqlite3_stmt
**
** ^This routine can be used to find the number of [SQL parameters]
** in a [prepared statement]. SQL parameters are tokens of the
@@ -3552,10 +3777,11 @@ SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
** [sqlite3_bind_parameter_name()], and
** [sqlite3_bind_parameter_index()].
*/
-SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_count(sqlite3_stmt*);
/*
** CAPI3REF: Name Of A Host Parameter
+** METHOD: sqlite3_stmt
**
** ^The sqlite3_bind_parameter_name(P,N) interface returns
** the name of the N-th [SQL parameter] in the [prepared statement] P.
@@ -3579,10 +3805,11 @@ SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*);
** [sqlite3_bind_parameter_count()], and
** [sqlite3_bind_parameter_index()].
*/
-SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt*, int);
/*
** CAPI3REF: Index Of A Parameter With A Given Name
+** METHOD: sqlite3_stmt
**
** ^Return the index of an SQL parameter given its name. ^The
** index value returned is suitable for use as the second
@@ -3595,19 +3822,21 @@ SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int);
** [sqlite3_bind_parameter_count()], and
** [sqlite3_bind_parameter_index()].
*/
-SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
/*
** CAPI3REF: Reset All Bindings On A Prepared Statement
+** METHOD: sqlite3_stmt
**
** ^Contrary to the intuition of many, [sqlite3_reset()] does not reset
** the [sqlite3_bind_blob | bindings] on a [prepared statement].
** ^Use this routine to reset all host parameters to NULL.
*/
-SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*);
+SQLITE_API int SQLITE_STDCALL sqlite3_clear_bindings(sqlite3_stmt*);
/*
** CAPI3REF: Number Of Columns In A Result Set
+** METHOD: sqlite3_stmt
**
** ^Return the number of columns in the result set returned by the
** [prepared statement]. ^This routine returns 0 if pStmt is an SQL
@@ -3615,10 +3844,11 @@ SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*);
**
** See also: [sqlite3_data_count()]
*/
-SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt);
+SQLITE_API int SQLITE_STDCALL sqlite3_column_count(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Column Names In A Result Set
+** METHOD: sqlite3_stmt
**
** ^These routines return the name assigned to a particular column
** in the result set of a [SELECT] statement. ^The sqlite3_column_name()
@@ -3643,11 +3873,12 @@ SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt);
** then the name of the column is unspecified and may change from
** one release of SQLite to the next.
*/
-SQLITE_API const char *sqlite3_column_name(sqlite3_stmt*, int N);
-SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_column_name(sqlite3_stmt*, int N);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_name16(sqlite3_stmt*, int N);
/*
** CAPI3REF: Source Of Data In A Query Result
+** METHOD: sqlite3_stmt
**
** ^These routines provide a means to determine the database, table, and
** table column that is the origin of a particular result column in
@@ -3691,15 +3922,16 @@ SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N);
** for the same [prepared statement] and result column
** at the same time then the results are undefined.
*/
-SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt*,int);
-SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt*,int);
-SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt*,int);
-SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt*,int);
-SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt*,int);
-SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt*,int);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_column_database_name(sqlite3_stmt*,int);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_database_name16(sqlite3_stmt*,int);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_column_table_name(sqlite3_stmt*,int);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_table_name16(sqlite3_stmt*,int);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_column_origin_name(sqlite3_stmt*,int);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_origin_name16(sqlite3_stmt*,int);
/*
** CAPI3REF: Declared Datatype Of A Query Result
+** METHOD: sqlite3_stmt
**
** ^(The first parameter is a [prepared statement].
** If this statement is a [SELECT] statement and the Nth column of the
@@ -3727,11 +3959,12 @@ SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt*,int);
** is associated with individual values, not with the containers
** used to hold those values.
*/
-SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt*,int);
-SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_column_decltype(sqlite3_stmt*,int);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt*,int);
/*
** CAPI3REF: Evaluate An SQL Statement
+** METHOD: sqlite3_stmt
**
** After a [prepared statement] has been prepared using either
** [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] or one of the legacy
@@ -3807,10 +4040,11 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
** then the more specific [error codes] are returned directly
** by sqlite3_step(). The use of the "v2" interface is recommended.
*/
-SQLITE_API int sqlite3_step(sqlite3_stmt*);
+SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt*);
/*
** CAPI3REF: Number of columns in a result set
+** METHOD: sqlite3_stmt
**
** ^The sqlite3_data_count(P) interface returns the number of columns in the
** current row of the result set of [prepared statement] P.
@@ -3827,7 +4061,7 @@ SQLITE_API int sqlite3_step(sqlite3_stmt*);
**
** See also: [sqlite3_column_count()]
*/
-SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
+SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Fundamental Datatypes
@@ -3864,6 +4098,7 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Result Values From A Query
** KEYWORDS: {column access functions}
+** METHOD: sqlite3_stmt
**
** These routines form the "result set" interface.
**
@@ -4023,19 +4258,20 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
** pointer. Subsequent calls to [sqlite3_errcode()] will return
** [SQLITE_NOMEM].)^
*/
-SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
-SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
-SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
-SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol);
-SQLITE_API int sqlite3_column_int(sqlite3_stmt*, int iCol);
-SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
-SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
-SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
-SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol);
-SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_blob(sqlite3_stmt*, int iCol);
+SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes(sqlite3_stmt*, int iCol);
+SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
+SQLITE_API double SQLITE_STDCALL sqlite3_column_double(sqlite3_stmt*, int iCol);
+SQLITE_API int SQLITE_STDCALL sqlite3_column_int(sqlite3_stmt*, int iCol);
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_column_int64(sqlite3_stmt*, int iCol);
+SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_column_text(sqlite3_stmt*, int iCol);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_text16(sqlite3_stmt*, int iCol);
+SQLITE_API int SQLITE_STDCALL sqlite3_column_type(sqlite3_stmt*, int iCol);
+SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_column_value(sqlite3_stmt*, int iCol);
/*
** CAPI3REF: Destroy A Prepared Statement Object
+** DESTRUCTOR: sqlite3_stmt
**
** ^The sqlite3_finalize() function is called to delete a [prepared statement].
** ^If the most recent evaluation of the statement encountered no errors
@@ -4059,10 +4295,11 @@ SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
** statement after it has been finalized can result in undefined and
** undesirable behavior such as segfaults and heap corruption.
*/
-SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt);
+SQLITE_API int SQLITE_STDCALL sqlite3_finalize(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Reset A Prepared Statement Object
+** METHOD: sqlite3_stmt
**
** The sqlite3_reset() function is called to reset a [prepared statement]
** object back to its initial state, ready to be re-executed.
@@ -4085,13 +4322,14 @@ SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt);
** ^The [sqlite3_reset(S)] interface does not change the values
** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S.
*/
-SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
+SQLITE_API int SQLITE_STDCALL sqlite3_reset(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Create Or Redefine SQL Functions
** KEYWORDS: {function creation routines}
** KEYWORDS: {application-defined SQL function}
** KEYWORDS: {application-defined SQL functions}
+** METHOD: sqlite3
**
** ^These functions (collectively known as "function creation routines")
** are used to add SQL functions or aggregates or to redefine the behavior
@@ -4184,7 +4422,7 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
** close the database connection nor finalize or reset the prepared
** statement in which the function is running.
*/
-SQLITE_API int sqlite3_create_function(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_function(
sqlite3 *db,
const char *zFunctionName,
int nArg,
@@ -4194,7 +4432,7 @@ SQLITE_API int sqlite3_create_function(
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*)
);
-SQLITE_API int sqlite3_create_function16(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_function16(
sqlite3 *db,
const void *zFunctionName,
int nArg,
@@ -4204,7 +4442,7 @@ SQLITE_API int sqlite3_create_function16(
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*)
);
-SQLITE_API int sqlite3_create_function_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2(
sqlite3 *db,
const char *zFunctionName,
int nArg,
@@ -4222,9 +4460,9 @@ SQLITE_API int sqlite3_create_function_v2(
** These constant define integer codes that represent the various
** text encodings supported by SQLite.
*/
-#define SQLITE_UTF8 1
-#define SQLITE_UTF16LE 2
-#define SQLITE_UTF16BE 3
+#define SQLITE_UTF8 1 /* IMP: R-37514-35566 */
+#define SQLITE_UTF16LE 2 /* IMP: R-03371-37637 */
+#define SQLITE_UTF16BE 3 /* IMP: R-51971-34154 */
#define SQLITE_UTF16 4 /* Use native byte order */
#define SQLITE_ANY 5 /* Deprecated */
#define SQLITE_UTF16_ALIGNED 8 /* sqlite3_create_collation only */
@@ -4246,21 +4484,22 @@ SQLITE_API int sqlite3_create_function_v2(
** These functions are [deprecated]. In order to maintain
** backwards compatibility with older code, these functions continue
** to be supported. However, new applications should avoid
-** the use of these functions. To help encourage people to avoid
-** using these functions, we are not going to tell you what they do.
+** the use of these functions. To encourage programmers to avoid
+** these functions, we will not explain what they do.
*/
#ifndef SQLITE_OMIT_DEPRECATED
-SQLITE_API SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*);
-SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*);
-SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*);
-SQLITE_API SQLITE_DEPRECATED int sqlite3_global_recover(void);
-SQLITE_API SQLITE_DEPRECATED void sqlite3_thread_cleanup(void);
-SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
+SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_aggregate_count(sqlite3_context*);
+SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_expired(sqlite3_stmt*);
+SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*);
+SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_global_recover(void);
+SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_thread_cleanup(void);
+SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
void*,sqlite3_int64);
#endif
/*
** CAPI3REF: Obtaining SQL Function Parameter Values
+** METHOD: sqlite3_value
**
** The C-language implementation of SQL functions and aggregates uses
** this set of interface routines to access the parameter values on
@@ -4279,7 +4518,7 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6
** object results in undefined behavior.
**
** ^These routines work just like the corresponding [column access functions]
-** except that these routines take a single [protected sqlite3_value] object
+** except that these routines take a single [protected sqlite3_value] object
** pointer instead of a [sqlite3_stmt*] pointer and an integer column number.
**
** ^The sqlite3_value_text16() interface extracts a UTF-16 string
@@ -4304,21 +4543,22 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6
** These routines must be called from the same thread as
** the SQL function that supplied the [sqlite3_value*] parameters.
*/
-SQLITE_API const void *sqlite3_value_blob(sqlite3_value*);
-SQLITE_API int sqlite3_value_bytes(sqlite3_value*);
-SQLITE_API int sqlite3_value_bytes16(sqlite3_value*);
-SQLITE_API double sqlite3_value_double(sqlite3_value*);
-SQLITE_API int sqlite3_value_int(sqlite3_value*);
-SQLITE_API sqlite3_int64 sqlite3_value_int64(sqlite3_value*);
-SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value*);
-SQLITE_API const void *sqlite3_value_text16(sqlite3_value*);
-SQLITE_API const void *sqlite3_value_text16le(sqlite3_value*);
-SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*);
-SQLITE_API int sqlite3_value_type(sqlite3_value*);
-SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_value_blob(sqlite3_value*);
+SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes(sqlite3_value*);
+SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes16(sqlite3_value*);
+SQLITE_API double SQLITE_STDCALL sqlite3_value_double(sqlite3_value*);
+SQLITE_API int SQLITE_STDCALL sqlite3_value_int(sqlite3_value*);
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_value_int64(sqlite3_value*);
+SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_value_text(sqlite3_value*);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16(sqlite3_value*);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16le(sqlite3_value*);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16be(sqlite3_value*);
+SQLITE_API int SQLITE_STDCALL sqlite3_value_type(sqlite3_value*);
+SQLITE_API int SQLITE_STDCALL sqlite3_value_numeric_type(sqlite3_value*);
/*
** CAPI3REF: Obtain Aggregate Function Context
+** METHOD: sqlite3_context
**
** Implementations of aggregate SQL functions use this
** routine to allocate memory for storing their state.
@@ -4359,10 +4599,11 @@ SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
** This routine must be called from the same thread in which
** the aggregate SQL function is running.
*/
-SQLITE_API void *sqlite3_aggregate_context(sqlite3_context*, int nBytes);
+SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context*, int nBytes);
/*
** CAPI3REF: User Data For Functions
+** METHOD: sqlite3_context
**
** ^The sqlite3_user_data() interface returns a copy of
** the pointer that was the pUserData parameter (the 5th parameter)
@@ -4373,10 +4614,11 @@ SQLITE_API void *sqlite3_aggregate_context(sqlite3_context*, int nBytes);
** This routine must be called from the same thread in which
** the application-defined function is running.
*/
-SQLITE_API void *sqlite3_user_data(sqlite3_context*);
+SQLITE_API void *SQLITE_STDCALL sqlite3_user_data(sqlite3_context*);
/*
** CAPI3REF: Database Connection For Functions
+** METHOD: sqlite3_context
**
** ^The sqlite3_context_db_handle() interface returns a copy of
** the pointer to the [database connection] (the 1st parameter)
@@ -4384,10 +4626,11 @@ SQLITE_API void *sqlite3_user_data(sqlite3_context*);
** and [sqlite3_create_function16()] routines that originally
** registered the application defined function.
*/
-SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
+SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*);
/*
** CAPI3REF: Function Auxiliary Data
+** METHOD: sqlite3_context
**
** These functions may be used by (non-aggregate) SQL functions to
** associate metadata with argument values. If the same value is passed to
@@ -4436,8 +4679,8 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
** These routines must be called from the same thread in which
** the SQL function is running.
*/
-SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N);
-SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
+SQLITE_API void *SQLITE_STDCALL sqlite3_get_auxdata(sqlite3_context*, int N);
+SQLITE_API void SQLITE_STDCALL sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
/*
@@ -4460,6 +4703,7 @@ typedef void (*sqlite3_destructor_type)(void*);
/*
** CAPI3REF: Setting The Result Of An SQL Function
+** METHOD: sqlite3_context
**
** These routines are used by the xFunc or xFinal callbacks that
** implement SQL functions and aggregates. See
@@ -4526,6 +4770,10 @@ typedef void (*sqlite3_destructor_type)(void*);
** set the return value of the application-defined function to be
** a text string which is represented as UTF-8, UTF-16 native byte order,
** UTF-16 little endian, or UTF-16 big endian, respectively.
+** ^The sqlite3_result_text64() interface sets the return value of an
+** application-defined function to be a text string in an encoding
+** specified by the fifth (and last) parameter, which must be one
+** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE].
** ^SQLite takes the text result from the application from
** the 2nd parameter of the sqlite3_result_text* interfaces.
** ^If the 3rd parameter to the sqlite3_result_text* interfaces
@@ -4568,25 +4816,30 @@ typedef void (*sqlite3_destructor_type)(void*);
** than the one containing the application-defined function that received
** the [sqlite3_context] pointer, the results are undefined.
*/
-SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
-SQLITE_API void sqlite3_result_double(sqlite3_context*, double);
-SQLITE_API void sqlite3_result_error(sqlite3_context*, const char*, int);
-SQLITE_API void sqlite3_result_error16(sqlite3_context*, const void*, int);
-SQLITE_API void sqlite3_result_error_toobig(sqlite3_context*);
-SQLITE_API void sqlite3_result_error_nomem(sqlite3_context*);
-SQLITE_API void sqlite3_result_error_code(sqlite3_context*, int);
-SQLITE_API void sqlite3_result_int(sqlite3_context*, int);
-SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
-SQLITE_API void sqlite3_result_null(sqlite3_context*);
-SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
-SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*));
-SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
-SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
-SQLITE_API void sqlite3_result_value(sqlite3_context*, sqlite3_value*);
-SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
+SQLITE_API void SQLITE_STDCALL sqlite3_result_blob64(sqlite3_context*,const void*,
+ sqlite3_uint64,void(*)(void*));
+SQLITE_API void SQLITE_STDCALL sqlite3_result_double(sqlite3_context*, double);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_error(sqlite3_context*, const char*, int);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_error16(sqlite3_context*, const void*, int);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_error_toobig(sqlite3_context*);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_error_nomem(sqlite3_context*);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_error_code(sqlite3_context*, int);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_int(sqlite3_context*, int);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_null(sqlite3_context*);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
+SQLITE_API void SQLITE_STDCALL sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64,
+ void(*)(void*), unsigned char encoding);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*));
+SQLITE_API void SQLITE_STDCALL sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
+SQLITE_API void SQLITE_STDCALL sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
+SQLITE_API void SQLITE_STDCALL sqlite3_result_value(sqlite3_context*, sqlite3_value*);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_zeroblob(sqlite3_context*, int n);
/*
** CAPI3REF: Define New Collating Sequences
+** METHOD: sqlite3
**
** ^These functions add, remove, or modify a [collation] associated
** with the [database connection] specified as the first argument.
@@ -4664,14 +4917,14 @@ SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n);
**
** See also: [sqlite3_collation_needed()] and [sqlite3_collation_needed16()].
*/
-SQLITE_API int sqlite3_create_collation(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_collation(
sqlite3*,
const char *zName,
int eTextRep,
void *pArg,
int(*xCompare)(void*,int,const void*,int,const void*)
);
-SQLITE_API int sqlite3_create_collation_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_collation_v2(
sqlite3*,
const char *zName,
int eTextRep,
@@ -4679,7 +4932,7 @@ SQLITE_API int sqlite3_create_collation_v2(
int(*xCompare)(void*,int,const void*,int,const void*),
void(*xDestroy)(void*)
);
-SQLITE_API int sqlite3_create_collation16(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_collation16(
sqlite3*,
const void *zName,
int eTextRep,
@@ -4689,6 +4942,7 @@ SQLITE_API int sqlite3_create_collation16(
/*
** CAPI3REF: Collation Needed Callbacks
+** METHOD: sqlite3
**
** ^To avoid having to register all collation sequences before a database
** can be used, a single callback function may be registered with the
@@ -4713,12 +4967,12 @@ SQLITE_API int sqlite3_create_collation16(
** [sqlite3_create_collation()], [sqlite3_create_collation16()], or
** [sqlite3_create_collation_v2()].
*/
-SQLITE_API int sqlite3_collation_needed(
+SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed(
sqlite3*,
void*,
void(*)(void*,sqlite3*,int eTextRep,const char*)
);
-SQLITE_API int sqlite3_collation_needed16(
+SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed16(
sqlite3*,
void*,
void(*)(void*,sqlite3*,int eTextRep,const void*)
@@ -4732,11 +4986,11 @@ SQLITE_API int sqlite3_collation_needed16(
** The code to implement this API is not available in the public release
** of SQLite.
*/
-SQLITE_API int sqlite3_key(
+SQLITE_API int SQLITE_STDCALL sqlite3_key(
sqlite3 *db, /* Database to be rekeyed */
const void *pKey, int nKey /* The key */
);
-SQLITE_API int sqlite3_key_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_key_v2(
sqlite3 *db, /* Database to be rekeyed */
const char *zDbName, /* Name of the database */
const void *pKey, int nKey /* The key */
@@ -4750,11 +5004,11 @@ SQLITE_API int sqlite3_key_v2(
** The code to implement this API is not available in the public release
** of SQLite.
*/
-SQLITE_API int sqlite3_rekey(
+SQLITE_API int SQLITE_STDCALL sqlite3_rekey(
sqlite3 *db, /* Database to be rekeyed */
const void *pKey, int nKey /* The new key */
);
-SQLITE_API int sqlite3_rekey_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_rekey_v2(
sqlite3 *db, /* Database to be rekeyed */
const char *zDbName, /* Name of the database */
const void *pKey, int nKey /* The new key */
@@ -4764,7 +5018,7 @@ SQLITE_API int sqlite3_rekey_v2(
** Specify the activation key for a SEE database. Unless
** activated, none of the SEE routines will work.
*/
-SQLITE_API void sqlite3_activate_see(
+SQLITE_API void SQLITE_STDCALL sqlite3_activate_see(
const char *zPassPhrase /* Activation phrase */
);
#endif
@@ -4774,7 +5028,7 @@ SQLITE_API void sqlite3_activate_see(
** Specify the activation key for a CEROD database. Unless
** activated, none of the CEROD routines will work.
*/
-SQLITE_API void sqlite3_activate_cerod(
+SQLITE_API void SQLITE_STDCALL sqlite3_activate_cerod(
const char *zPassPhrase /* Activation phrase */
);
#endif
@@ -4796,7 +5050,7 @@ SQLITE_API void sqlite3_activate_cerod(
** all, then the behavior of sqlite3_sleep() may deviate from the description
** in the previous paragraphs.
*/
-SQLITE_API int sqlite3_sleep(int);
+SQLITE_API int SQLITE_STDCALL sqlite3_sleep(int);
/*
** CAPI3REF: Name Of The Folder Holding Temporary Files
@@ -4896,6 +5150,7 @@ SQLITE_API char *sqlite3_data_directory;
/*
** CAPI3REF: Test For Auto-Commit Mode
** KEYWORDS: {autocommit mode}
+** METHOD: sqlite3
**
** ^The sqlite3_get_autocommit() interface returns non-zero or
** zero if the given database connection is or is not in autocommit mode,
@@ -4914,10 +5169,11 @@ SQLITE_API char *sqlite3_data_directory;
** connection while this routine is running, then the return value
** is undefined.
*/
-SQLITE_API int sqlite3_get_autocommit(sqlite3*);
+SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3*);
/*
** CAPI3REF: Find The Database Handle Of A Prepared Statement
+** METHOD: sqlite3_stmt
**
** ^The sqlite3_db_handle interface returns the [database connection] handle
** to which a [prepared statement] belongs. ^The [database connection]
@@ -4926,10 +5182,11 @@ SQLITE_API int sqlite3_get_autocommit(sqlite3*);
** to the [sqlite3_prepare_v2()] call (or its variants) that was used to
** create the statement in the first place.
*/
-SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
+SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_db_handle(sqlite3_stmt*);
/*
** CAPI3REF: Return The Filename For A Database Connection
+** METHOD: sqlite3
**
** ^The sqlite3_db_filename(D,N) interface returns a pointer to a filename
** associated with database N of connection D. ^The main database file
@@ -4942,19 +5199,21 @@ SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
** will be an absolute pathname, even if the filename used
** to open the database originally was a URI or relative pathname.
*/
-SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_db_filename(sqlite3 *db, const char *zDbName);
/*
** CAPI3REF: Determine if a database is read-only
+** METHOD: sqlite3
**
** ^The sqlite3_db_readonly(D,N) interface returns 1 if the database N
** of connection D is read-only, 0 if it is read/write, or -1 if N is not
** the name of a database on connection D.
*/
-SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
+SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
/*
** CAPI3REF: Find the next prepared statement
+** METHOD: sqlite3
**
** ^This interface returns a pointer to the next [prepared statement] after
** pStmt associated with the [database connection] pDb. ^If pStmt is NULL
@@ -4966,10 +5225,11 @@ SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
** [sqlite3_next_stmt(D,S)] must refer to an open database
** connection and in particular must not be a NULL pointer.
*/
-SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
+SQLITE_API sqlite3_stmt *SQLITE_STDCALL sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
/*
** CAPI3REF: Commit And Rollback Notification Callbacks
+** METHOD: sqlite3
**
** ^The sqlite3_commit_hook() interface registers a callback
** function to be invoked whenever a transaction is [COMMIT | committed].
@@ -5014,11 +5274,12 @@ SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
**
** See also the [sqlite3_update_hook()] interface.
*/
-SQLITE_API void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
-SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
+SQLITE_API void *SQLITE_STDCALL sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
+SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
/*
** CAPI3REF: Data Change Notification Callbacks
+** METHOD: sqlite3
**
** ^The sqlite3_update_hook() interface registers a callback function
** with the [database connection] identified by the first argument
@@ -5065,7 +5326,7 @@ SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
** See also the [sqlite3_commit_hook()] and [sqlite3_rollback_hook()]
** interfaces.
*/
-SQLITE_API void *sqlite3_update_hook(
+SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook(
sqlite3*,
void(*)(void *,int ,char const *,char const *,sqlite3_int64),
void*
@@ -5095,12 +5356,17 @@ SQLITE_API void *sqlite3_update_hook(
** future releases of SQLite. Applications that care about shared
** cache setting should set it explicitly.
**
+** Note: This method is disabled on MacOS X 10.7 and iOS version 5.0
+** and will always return SQLITE_MISUSE. On those systems,
+** shared cache mode should be enabled per-database connection via
+** [sqlite3_open_v2()] with [SQLITE_OPEN_SHAREDCACHE].
+**
** This interface is threadsafe on processors where writing a
** 32-bit integer is atomic.
**
** See Also: [SQLite Shared-Cache Mode]
*/
-SQLITE_API int sqlite3_enable_shared_cache(int);
+SQLITE_API int SQLITE_STDCALL sqlite3_enable_shared_cache(int);
/*
** CAPI3REF: Attempt To Free Heap Memory
@@ -5116,10 +5382,11 @@ SQLITE_API int sqlite3_enable_shared_cache(int);
**
** See also: [sqlite3_db_release_memory()]
*/
-SQLITE_API int sqlite3_release_memory(int);
+SQLITE_API int SQLITE_STDCALL sqlite3_release_memory(int);
/*
** CAPI3REF: Free Memory Used By A Database Connection
+** METHOD: sqlite3
**
** ^The sqlite3_db_release_memory(D) interface attempts to free as much heap
** memory as possible from database connection D. Unlike the
@@ -5129,7 +5396,7 @@ SQLITE_API int sqlite3_release_memory(int);
**
** See also: [sqlite3_release_memory()]
*/
-SQLITE_API int sqlite3_db_release_memory(sqlite3*);
+SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3*);
/*
** CAPI3REF: Impose A Limit On Heap Size
@@ -5181,7 +5448,7 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*);
** The circumstances under which SQLite will enforce the soft heap limit may
** changes in future releases of SQLite.
*/
-SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N);
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_soft_heap_limit64(sqlite3_int64 N);
/*
** CAPI3REF: Deprecated Soft Heap Limit Interface
@@ -5192,26 +5459,34 @@ SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N);
** only. All new applications should use the
** [sqlite3_soft_heap_limit64()] interface rather than this one.
*/
-SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
+SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_soft_heap_limit(int N);
/*
** CAPI3REF: Extract Metadata About A Column Of A Table
-**
-** ^This routine returns metadata about a specific column of a specific
-** database table accessible using the [database connection] handle
-** passed as the first function argument.
+** METHOD: sqlite3
+**
+** ^(The sqlite3_table_column_metadata(X,D,T,C,....) routine returns
+** information about column C of table T in database D
+** on [database connection] X.)^ ^The sqlite3_table_column_metadata()
+** interface returns SQLITE_OK and fills in the non-NULL pointers in
+** the final five arguments with appropriate values if the specified
+** column exists. ^The sqlite3_table_column_metadata() interface returns
+** SQLITE_ERROR and if the specified column does not exist.
+** ^If the column-name parameter to sqlite3_table_column_metadata() is a
+** NULL pointer, then this routine simply checks for the existance of the
+** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it
+** does not.
**
** ^The column is identified by the second, third and fourth parameters to
-** this function. ^The second parameter is either the name of the database
+** this function. ^(The second parameter is either the name of the database
** (i.e. "main", "temp", or an attached database) containing the specified
-** table or NULL. ^If it is NULL, then all attached databases are searched
+** table or NULL.)^ ^If it is NULL, then all attached databases are searched
** for the table using the same algorithm used by the database engine to
** resolve unqualified table references.
**
** ^The third and fourth parameters to this function are the table and column
-** name of the desired column, respectively. Neither of these parameters
-** may be NULL.
+** name of the desired column, respectively.
**
** ^Metadata is returned by writing to the memory locations passed as the 5th
** and subsequent parameters to this function. ^Any of these arguments may be
@@ -5230,16 +5505,17 @@ SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
** </blockquote>)^
**
** ^The memory pointed to by the character pointers returned for the
-** declaration type and collation sequence is valid only until the next
+** declaration type and collation sequence is valid until the next
** call to any SQLite API function.
**
** ^If the specified table is actually a view, an [error code] is returned.
**
-** ^If the specified column is "rowid", "oid" or "_rowid_" and an
+** ^If the specified column is "rowid", "oid" or "_rowid_" and the table
+** is not a [WITHOUT ROWID] table and an
** [INTEGER PRIMARY KEY] column has been explicitly declared, then the output
** parameters are set for the explicitly declared column. ^(If there is no
-** explicitly declared [INTEGER PRIMARY KEY] column, then the output
-** parameters are set as follows:
+** [INTEGER PRIMARY KEY] column, then the outputs
+** for the [rowid] are set as follows:
**
** <pre>
** data type: "INTEGER"
@@ -5249,15 +5525,11 @@ SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
** auto increment: 0
** </pre>)^
**
-** ^(This function may load one or more schemas from database files. If an
-** error occurs during this process, or if the requested table or column
-** cannot be found, an [error code] is returned and an error message left
-** in the [database connection] (to be retrieved using sqlite3_errmsg()).)^
-**
-** ^This API is only available if the library was compiled with the
-** [SQLITE_ENABLE_COLUMN_METADATA] C-preprocessor symbol defined.
+** ^This function causes all database schemas to be read from disk and
+** parsed, if that has not already been done, and returns an error if
+** any errors are encountered while loading the schema.
*/
-SQLITE_API int sqlite3_table_column_metadata(
+SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata(
sqlite3 *db, /* Connection handle */
const char *zDbName, /* Database name or NULL */
const char *zTableName, /* Table name */
@@ -5271,6 +5543,7 @@ SQLITE_API int sqlite3_table_column_metadata(
/*
** CAPI3REF: Load An Extension
+** METHOD: sqlite3
**
** ^This interface loads an SQLite extension library from the named file.
**
@@ -5303,7 +5576,7 @@ SQLITE_API int sqlite3_table_column_metadata(
**
** See also the [load_extension() SQL function].
*/
-SQLITE_API int sqlite3_load_extension(
+SQLITE_API int SQLITE_STDCALL sqlite3_load_extension(
sqlite3 *db, /* Load the extension into this database connection */
const char *zFile, /* Name of the shared library containing extension */
const char *zProc, /* Entry point. Derived from zFile if 0 */
@@ -5312,6 +5585,7 @@ SQLITE_API int sqlite3_load_extension(
/*
** CAPI3REF: Enable Or Disable Extension Loading
+** METHOD: sqlite3
**
** ^So as not to open security holes in older applications that are
** unprepared to deal with [extension loading], and as a means of disabling
@@ -5323,7 +5597,7 @@ SQLITE_API int sqlite3_load_extension(
** to turn extension loading on and call it with onoff==0 to turn
** it back off again.
*/
-SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
+SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int onoff);
/*
** CAPI3REF: Automatically Load Statically Linked Extensions
@@ -5361,7 +5635,7 @@ SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
** See also: [sqlite3_reset_auto_extension()]
** and [sqlite3_cancel_auto_extension()]
*/
-SQLITE_API int sqlite3_auto_extension(void (*xEntryPoint)(void));
+SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xEntryPoint)(void));
/*
** CAPI3REF: Cancel Automatic Extension Loading
@@ -5373,7 +5647,7 @@ SQLITE_API int sqlite3_auto_extension(void (*xEntryPoint)(void));
** unregistered and it returns 0 if X was not on the list of initialization
** routines.
*/
-SQLITE_API int sqlite3_cancel_auto_extension(void (*xEntryPoint)(void));
+SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xEntryPoint)(void));
/*
** CAPI3REF: Reset Automatic Extension Loading
@@ -5381,7 +5655,7 @@ SQLITE_API int sqlite3_cancel_auto_extension(void (*xEntryPoint)(void));
** ^This interface disables all automatic extensions previously
** registered using [sqlite3_auto_extension()].
*/
-SQLITE_API void sqlite3_reset_auto_extension(void);
+SQLITE_API void SQLITE_STDCALL sqlite3_reset_auto_extension(void);
/*
** The interface to the virtual-table mechanism is currently considered
@@ -5561,6 +5835,7 @@ struct sqlite3_index_info {
/*
** CAPI3REF: Register A Virtual Table Implementation
+** METHOD: sqlite3
**
** ^These routines are used to register a new [virtual table module] name.
** ^Module names must be registered before
@@ -5584,13 +5859,13 @@ struct sqlite3_index_info {
** interface is equivalent to sqlite3_create_module_v2() with a NULL
** destructor.
*/
-SQLITE_API int sqlite3_create_module(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_module(
sqlite3 *db, /* SQLite connection to register module with */
const char *zName, /* Name of the module */
const sqlite3_module *p, /* Methods for the module */
void *pClientData /* Client data for xCreate/xConnect */
);
-SQLITE_API int sqlite3_create_module_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_module_v2(
sqlite3 *db, /* SQLite connection to register module with */
const char *zName, /* Name of the module */
const sqlite3_module *p, /* Methods for the module */
@@ -5618,7 +5893,7 @@ SQLITE_API int sqlite3_create_module_v2(
*/
struct sqlite3_vtab {
const sqlite3_module *pModule; /* The module for this virtual table */
- int nRef; /* NO LONGER USED */
+ int nRef; /* Number of open cursors */
char *zErrMsg; /* Error message from sqlite3_mprintf() */
/* Virtual table implementations will typically add additional fields */
};
@@ -5653,10 +5928,11 @@ struct sqlite3_vtab_cursor {
** to declare the format (the names and datatypes of the columns) of
** the virtual tables they implement.
*/
-SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
+SQLITE_API int SQLITE_STDCALL sqlite3_declare_vtab(sqlite3*, const char *zSQL);
/*
** CAPI3REF: Overload A Function For A Virtual Table
+** METHOD: sqlite3
**
** ^(Virtual tables can provide alternative implementations of functions
** using the [xFindFunction] method of the [virtual table module].
@@ -5671,7 +5947,7 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
** purpose is to be a placeholder function that can be overloaded
** by a [virtual table].
*/
-SQLITE_API int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
+SQLITE_API int SQLITE_STDCALL sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
/*
** The interface to the virtual-table mechanism defined above (back up
@@ -5699,6 +5975,8 @@ typedef struct sqlite3_blob sqlite3_blob;
/*
** CAPI3REF: Open A BLOB For Incremental I/O
+** METHOD: sqlite3
+** CONSTRUCTOR: sqlite3_blob
**
** ^(This interfaces opens a [BLOB handle | handle] to the BLOB located
** in row iRow, column zColumn, table zTable in database zDb;
@@ -5708,26 +5986,42 @@ typedef struct sqlite3_blob sqlite3_blob;
** SELECT zColumn FROM zDb.zTable WHERE [rowid] = iRow;
** </pre>)^
**
+** ^(Parameter zDb is not the filename that contains the database, but
+** rather the symbolic name of the database. For attached databases, this is
+** the name that appears after the AS keyword in the [ATTACH] statement.
+** For the main database file, the database name is "main". For TEMP
+** tables, the database name is "temp".)^
+**
** ^If the flags parameter is non-zero, then the BLOB is opened for read
-** and write access. ^If it is zero, the BLOB is opened for read access.
-** ^It is not possible to open a column that is part of an index or primary
-** key for writing. ^If [foreign key constraints] are enabled, it is
-** not possible to open a column that is part of a [child key] for writing.
-**
-** ^Note that the database name is not the filename that contains
-** the database but rather the symbolic name of the database that
-** appears after the AS keyword when the database is connected using [ATTACH].
-** ^For the main database file, the database name is "main".
-** ^For TEMP tables, the database name is "temp".
-**
-** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is written
-** to *ppBlob. Otherwise an [error code] is returned and *ppBlob is set
-** to be a null pointer.)^
-** ^This function sets the [database connection] error code and message
-** accessible via [sqlite3_errcode()] and [sqlite3_errmsg()] and related
-** functions. ^Note that the *ppBlob variable is always initialized in a
-** way that makes it safe to invoke [sqlite3_blob_close()] on *ppBlob
-** regardless of the success or failure of this routine.
+** and write access. ^If the flags parameter is zero, the BLOB is opened for
+** read-only access.
+**
+** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is stored
+** in *ppBlob. Otherwise an [error code] is returned and, unless the error
+** code is SQLITE_MISUSE, *ppBlob is set to NULL.)^ ^This means that, provided
+** the API is not misused, it is always safe to call [sqlite3_blob_close()]
+** on *ppBlob after this function it returns.
+**
+** This function fails with SQLITE_ERROR if any of the following are true:
+** <ul>
+** <li> ^(Database zDb does not exist)^,
+** <li> ^(Table zTable does not exist within database zDb)^,
+** <li> ^(Table zTable is a WITHOUT ROWID table)^,
+** <li> ^(Column zColumn does not exist)^,
+** <li> ^(Row iRow is not present in the table)^,
+** <li> ^(The specified column of row iRow contains a value that is not
+** a TEXT or BLOB value)^,
+** <li> ^(Column zColumn is part of an index, PRIMARY KEY or UNIQUE
+** constraint and the blob is being opened for read/write access)^,
+** <li> ^([foreign key constraints | Foreign key constraints] are enabled,
+** column zColumn is part of a [child key] definition and the blob is
+** being opened for read/write access)^.
+** </ul>
+**
+** ^Unless it returns SQLITE_MISUSE, this function sets the
+** [database connection] error code and message accessible via
+** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions.
+**
**
** ^(If the row that a BLOB handle points to is modified by an
** [UPDATE], [DELETE], or by [ON CONFLICT] side-effects
@@ -5745,18 +6039,14 @@ typedef struct sqlite3_blob sqlite3_blob;
** interface. Use the [UPDATE] SQL command to change the size of a
** blob.
**
-** ^The [sqlite3_blob_open()] interface will fail for a [WITHOUT ROWID]
-** table. Incremental BLOB I/O is not possible on [WITHOUT ROWID] tables.
-**
** ^The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces
-** and the built-in [zeroblob] SQL function can be used, if desired,
-** to create an empty, zero-filled blob in which to read or write using
-** this interface.
+** and the built-in [zeroblob] SQL function may be used to create a
+** zero-filled blob to read or write using the incremental-blob interface.
**
** To avoid a resource leak, every open [BLOB handle] should eventually
** be released by a call to [sqlite3_blob_close()].
*/
-SQLITE_API int sqlite3_blob_open(
+SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
sqlite3*,
const char *zDb,
const char *zTable,
@@ -5768,6 +6058,7 @@ SQLITE_API int sqlite3_blob_open(
/*
** CAPI3REF: Move a BLOB Handle to a New Row
+** METHOD: sqlite3_blob
**
** ^This function is used to move an existing blob handle so that it points
** to a different row of the same database table. ^The new row is identified
@@ -5788,34 +6079,34 @@ SQLITE_API int sqlite3_blob_open(
**
** ^This function sets the database handle error code and message.
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
+SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
/*
** CAPI3REF: Close A BLOB Handle
+** DESTRUCTOR: sqlite3_blob
**
-** ^Closes an open [BLOB handle].
+** ^This function closes an open [BLOB handle]. ^(The BLOB handle is closed
+** unconditionally. Even if this routine returns an error code, the
+** handle is still closed.)^
**
-** ^Closing a BLOB shall cause the current transaction to commit
-** if there are no other BLOBs, no pending prepared statements, and the
-** database connection is in [autocommit mode].
-** ^If any writes were made to the BLOB, they might be held in cache
-** until the close operation if they will fit.
+** ^If the blob handle being closed was opened for read-write access, and if
+** the database is in auto-commit mode and there are no other open read-write
+** blob handles or active write statements, the current transaction is
+** committed. ^If an error occurs while committing the transaction, an error
+** code is returned and the transaction rolled back.
**
-** ^(Closing the BLOB often forces the changes
-** out to disk and so if any I/O errors occur, they will likely occur
-** at the time when the BLOB is closed. Any errors that occur during
-** closing are reported as a non-zero return value.)^
-**
-** ^(The BLOB is closed unconditionally. Even if this routine returns
-** an error code, the BLOB is still closed.)^
-**
-** ^Calling this routine with a null pointer (such as would be returned
-** by a failed call to [sqlite3_blob_open()]) is a harmless no-op.
+** Calling this function with an argument that is not a NULL pointer or an
+** open blob handle results in undefined behaviour. ^Calling this routine
+** with a null pointer (such as would be returned by a failed call to
+** [sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function
+** is passed a valid open blob handle, the values returned by the
+** sqlite3_errcode() and sqlite3_errmsg() functions are set before returning.
*/
-SQLITE_API int sqlite3_blob_close(sqlite3_blob *);
+SQLITE_API int SQLITE_STDCALL sqlite3_blob_close(sqlite3_blob *);
/*
** CAPI3REF: Return The Size Of An Open BLOB
+** METHOD: sqlite3_blob
**
** ^Returns the size in bytes of the BLOB accessible via the
** successfully opened [BLOB handle] in its only argument. ^The
@@ -5827,10 +6118,11 @@ SQLITE_API int sqlite3_blob_close(sqlite3_blob *);
** been closed by [sqlite3_blob_close()]. Passing any other pointer in
** to this routine results in undefined and probably undesirable behavior.
*/
-SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *);
+SQLITE_API int SQLITE_STDCALL sqlite3_blob_bytes(sqlite3_blob *);
/*
** CAPI3REF: Read Data From A BLOB Incrementally
+** METHOD: sqlite3_blob
**
** ^(This function is used to read data from an open [BLOB handle] into a
** caller-supplied buffer. N bytes of data are copied into buffer Z
@@ -5855,26 +6147,33 @@ SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *);
**
** See also: [sqlite3_blob_write()].
*/
-SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
+SQLITE_API int SQLITE_STDCALL sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
/*
** CAPI3REF: Write Data Into A BLOB Incrementally
+** METHOD: sqlite3_blob
**
-** ^This function is used to write data into an open [BLOB handle] from a
-** caller-supplied buffer. ^N bytes of data are copied from the buffer Z
-** into the open BLOB, starting at offset iOffset.
+** ^(This function is used to write data into an open [BLOB handle] from a
+** caller-supplied buffer. N bytes of data are copied from the buffer Z
+** into the open BLOB, starting at offset iOffset.)^
+**
+** ^(On success, sqlite3_blob_write() returns SQLITE_OK.
+** Otherwise, an [error code] or an [extended error code] is returned.)^
+** ^Unless SQLITE_MISUSE is returned, this function sets the
+** [database connection] error code and message accessible via
+** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions.
**
** ^If the [BLOB handle] passed as the first argument was not opened for
** writing (the flags parameter to [sqlite3_blob_open()] was zero),
** this function returns [SQLITE_READONLY].
**
-** ^This function may only modify the contents of the BLOB; it is
+** This function may only modify the contents of the BLOB; it is
** not possible to increase the size of a BLOB using this API.
** ^If offset iOffset is less than N bytes from the end of the BLOB,
-** [SQLITE_ERROR] is returned and no data is written. ^If N is
-** less than zero [SQLITE_ERROR] is returned and no data is written.
-** The size of the BLOB (and hence the maximum value of N+iOffset)
-** can be determined using the [sqlite3_blob_bytes()] interface.
+** [SQLITE_ERROR] is returned and no data is written. The size of the
+** BLOB (and hence the maximum value of N+iOffset) can be determined
+** using the [sqlite3_blob_bytes()] interface. ^If N or iOffset are less
+** than zero [SQLITE_ERROR] is returned and no data is written.
**
** ^An attempt to write to an expired [BLOB handle] fails with an
** error code of [SQLITE_ABORT]. ^Writes to the BLOB that occurred
@@ -5883,9 +6182,6 @@ SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
** have been overwritten by the statement that expired the BLOB handle
** or by other independent statements.
**
-** ^(On success, sqlite3_blob_write() returns SQLITE_OK.
-** Otherwise, an [error code] or an [extended error code] is returned.)^
-**
** This routine only works on a [BLOB handle] which has been created
** by a prior successful call to [sqlite3_blob_open()] and which has not
** been closed by [sqlite3_blob_close()]. Passing any other pointer in
@@ -5893,7 +6189,7 @@ SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
**
** See also: [sqlite3_blob_read()].
*/
-SQLITE_API int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset);
+SQLITE_API int SQLITE_STDCALL sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset);
/*
** CAPI3REF: Virtual File System Objects
@@ -5924,9 +6220,9 @@ SQLITE_API int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOff
** ^(If the default VFS is unregistered, another VFS is chosen as
** the default. The choice for the new VFS is arbitrary.)^
*/
-SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName);
-SQLITE_API int sqlite3_vfs_register(sqlite3_vfs*, int makeDflt);
-SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
+SQLITE_API sqlite3_vfs *SQLITE_STDCALL sqlite3_vfs_find(const char *zVfsName);
+SQLITE_API int SQLITE_STDCALL sqlite3_vfs_register(sqlite3_vfs*, int makeDflt);
+SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs*);
/*
** CAPI3REF: Mutexes
@@ -5938,34 +6234,34 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
**
** The SQLite source code contains multiple implementations
** of these mutex routines. An appropriate implementation
-** is selected automatically at compile-time. ^(The following
+** is selected automatically at compile-time. The following
** implementations are available in the SQLite core:
**
** <ul>
** <li> SQLITE_MUTEX_PTHREADS
** <li> SQLITE_MUTEX_W32
** <li> SQLITE_MUTEX_NOOP
-** </ul>)^
+** </ul>
**
-** ^The SQLITE_MUTEX_NOOP implementation is a set of routines
+** The SQLITE_MUTEX_NOOP implementation is a set of routines
** that does no real locking and is appropriate for use in
-** a single-threaded application. ^The SQLITE_MUTEX_PTHREADS and
+** a single-threaded application. The SQLITE_MUTEX_PTHREADS and
** SQLITE_MUTEX_W32 implementations are appropriate for use on Unix
** and Windows.
**
-** ^(If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor
+** If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor
** macro defined (with "-DSQLITE_MUTEX_APPDEF=1"), then no mutex
** implementation is included with the library. In this case the
** application must supply a custom mutex implementation using the
** [SQLITE_CONFIG_MUTEX] option of the sqlite3_config() function
** before calling sqlite3_initialize() or any other public sqlite3_
-** function that calls sqlite3_initialize().)^
+** function that calls sqlite3_initialize().
**
** ^The sqlite3_mutex_alloc() routine allocates a new
-** mutex and returns a pointer to it. ^If it returns NULL
-** that means that a mutex could not be allocated. ^SQLite
-** will unwind its stack and return an error. ^(The argument
-** to sqlite3_mutex_alloc() is one of these integer constants:
+** mutex and returns a pointer to it. ^The sqlite3_mutex_alloc()
+** routine returns NULL if it is unable to allocate the requested
+** mutex. The argument to sqlite3_mutex_alloc() must one of these
+** integer constants:
**
** <ul>
** <li> SQLITE_MUTEX_FAST
@@ -5978,7 +6274,8 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
** <li> SQLITE_MUTEX_STATIC_PMEM
** <li> SQLITE_MUTEX_STATIC_APP1
** <li> SQLITE_MUTEX_STATIC_APP2
-** </ul>)^
+** <li> SQLITE_MUTEX_STATIC_APP3
+** </ul>
**
** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE)
** cause sqlite3_mutex_alloc() to create
@@ -5986,14 +6283,14 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
** is used but not necessarily so when SQLITE_MUTEX_FAST is used.
** The mutex implementation does not need to make a distinction
** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does
-** not want to. ^SQLite will only request a recursive mutex in
-** cases where it really needs one. ^If a faster non-recursive mutex
+** not want to. SQLite will only request a recursive mutex in
+** cases where it really needs one. If a faster non-recursive mutex
** implementation is available on the host platform, the mutex subsystem
** might return such a mutex in response to SQLITE_MUTEX_FAST.
**
** ^The other allowed parameters to sqlite3_mutex_alloc() (anything other
** than SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) each return
-** a pointer to a static preexisting mutex. ^Six static mutexes are
+** a pointer to a static preexisting mutex. ^Nine static mutexes are
** used by the current version of SQLite. Future versions of SQLite
** may add additional static mutexes. Static mutexes are for internal
** use by SQLite only. Applications that use SQLite mutexes should
@@ -6002,16 +6299,13 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
**
** ^Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST
** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc()
-** returns a different mutex on every call. ^But for the static
+** returns a different mutex on every call. ^For the static
** mutex types, the same mutex is returned on every call that has
** the same type number.
**
** ^The sqlite3_mutex_free() routine deallocates a previously
-** allocated dynamic mutex. ^SQLite is careful to deallocate every
-** dynamic mutex that it allocates. The dynamic mutexes must not be in
-** use when they are deallocated. Attempting to deallocate a static
-** mutex results in undefined behavior. ^SQLite never deallocates
-** a static mutex.
+** allocated dynamic mutex. Attempting to deallocate a static
+** mutex results in undefined behavior.
**
** ^The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
** to enter a mutex. ^If another thread is already within the mutex,
@@ -6019,23 +6313,21 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
** SQLITE_BUSY. ^The sqlite3_mutex_try() interface returns [SQLITE_OK]
** upon successful entry. ^(Mutexes created using
** SQLITE_MUTEX_RECURSIVE can be entered multiple times by the same thread.
-** In such cases the,
+** In such cases, the
** mutex must be exited an equal number of times before another thread
-** can enter.)^ ^(If the same thread tries to enter any other
-** kind of mutex more than once, the behavior is undefined.
-** SQLite will never exhibit
-** such behavior in its own use of mutexes.)^
+** can enter.)^ If the same thread tries to enter any mutex other
+** than an SQLITE_MUTEX_RECURSIVE more than once, the behavior is undefined.
**
** ^(Some systems (for example, Windows 95) do not support the operation
** implemented by sqlite3_mutex_try(). On those systems, sqlite3_mutex_try()
-** will always return SQLITE_BUSY. The SQLite core only ever uses
-** sqlite3_mutex_try() as an optimization so this is acceptable behavior.)^
+** will always return SQLITE_BUSY. The SQLite core only ever uses
+** sqlite3_mutex_try() as an optimization so this is acceptable
+** behavior.)^
**
** ^The sqlite3_mutex_leave() routine exits a mutex that was
-** previously entered by the same thread. ^(The behavior
+** previously entered by the same thread. The behavior
** is undefined if the mutex is not currently entered by the
-** calling thread or is not currently allocated. SQLite will
-** never do either.)^
+** calling thread or is not currently allocated.
**
** ^If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(), or
** sqlite3_mutex_leave() is a NULL pointer, then all three routines
@@ -6043,11 +6335,11 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
**
** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()].
*/
-SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int);
-SQLITE_API void sqlite3_mutex_free(sqlite3_mutex*);
-SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex*);
-SQLITE_API int sqlite3_mutex_try(sqlite3_mutex*);
-SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*);
+SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_mutex_alloc(int);
+SQLITE_API void SQLITE_STDCALL sqlite3_mutex_free(sqlite3_mutex*);
+SQLITE_API void SQLITE_STDCALL sqlite3_mutex_enter(sqlite3_mutex*);
+SQLITE_API int SQLITE_STDCALL sqlite3_mutex_try(sqlite3_mutex*);
+SQLITE_API void SQLITE_STDCALL sqlite3_mutex_leave(sqlite3_mutex*);
/*
** CAPI3REF: Mutex Methods Object
@@ -6056,9 +6348,9 @@ SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*);
** used to allocate and use mutexes.
**
** Usually, the default mutex implementations provided by SQLite are
-** sufficient, however the user has the option of substituting a custom
+** sufficient, however the application has the option of substituting a custom
** implementation for specialized deployments or systems for which SQLite
-** does not provide a suitable implementation. In this case, the user
+** does not provide a suitable implementation. In this case, the application
** creates and populates an instance of this structure to pass
** to sqlite3_config() along with the [SQLITE_CONFIG_MUTEX] option.
** Additionally, an instance of this structure can be used as an
@@ -6099,13 +6391,13 @@ SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*);
** (i.e. it is acceptable to provide an implementation that segfaults if
** it is passed a NULL pointer).
**
-** The xMutexInit() method must be threadsafe. ^It must be harmless to
+** The xMutexInit() method must be threadsafe. It must be harmless to
** invoke xMutexInit() multiple times within the same process and without
** intervening calls to xMutexEnd(). Second and subsequent calls to
** xMutexInit() must be no-ops.
**
-** ^xMutexInit() must not use SQLite memory allocation ([sqlite3_malloc()]
-** and its associates). ^Similarly, xMutexAlloc() must not use SQLite memory
+** xMutexInit() must not use SQLite memory allocation ([sqlite3_malloc()]
+** and its associates). Similarly, xMutexAlloc() must not use SQLite memory
** allocation for a static mutex. ^However xMutexAlloc() may use SQLite
** memory allocation for a fast or recursive mutex.
**
@@ -6131,34 +6423,34 @@ struct sqlite3_mutex_methods {
** CAPI3REF: Mutex Verification Routines
**
** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routines
-** are intended for use inside assert() statements. ^The SQLite core
+** are intended for use inside assert() statements. The SQLite core
** never uses these routines except inside an assert() and applications
-** are advised to follow the lead of the core. ^The SQLite core only
+** are advised to follow the lead of the core. The SQLite core only
** provides implementations for these routines when it is compiled
-** with the SQLITE_DEBUG flag. ^External mutex implementations
+** with the SQLITE_DEBUG flag. External mutex implementations
** are only required to provide these routines if SQLITE_DEBUG is
** defined and if NDEBUG is not defined.
**
-** ^These routines should return true if the mutex in their argument
+** These routines should return true if the mutex in their argument
** is held or not held, respectively, by the calling thread.
**
-** ^The implementation is not required to provide versions of these
+** The implementation is not required to provide versions of these
** routines that actually work. If the implementation does not provide working
** versions of these routines, it should at least provide stubs that always
** return true so that one does not get spurious assertion failures.
**
-** ^If the argument to sqlite3_mutex_held() is a NULL pointer then
+** If the argument to sqlite3_mutex_held() is a NULL pointer then
** the routine should return 1. This seems counter-intuitive since
** clearly the mutex cannot be held if it does not exist. But
** the reason the mutex does not exist is because the build is not
** using mutexes. And we do not want the assert() containing the
** call to sqlite3_mutex_held() to fail, so a non-zero return is
-** the appropriate thing to do. ^The sqlite3_mutex_notheld()
+** the appropriate thing to do. The sqlite3_mutex_notheld()
** interface should also return 1 when given a NULL pointer.
*/
#ifndef NDEBUG
-SQLITE_API int sqlite3_mutex_held(sqlite3_mutex*);
-SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
+SQLITE_API int SQLITE_STDCALL sqlite3_mutex_held(sqlite3_mutex*);
+SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex*);
#endif
/*
@@ -6187,6 +6479,7 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
/*
** CAPI3REF: Retrieve the mutex for a database connection
+** METHOD: sqlite3
**
** ^This interface returns a pointer the [sqlite3_mutex] object that
** serializes access to the [database connection] given in the argument
@@ -6194,10 +6487,11 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
** ^If the [threading mode] is Single-thread or Multi-thread then this
** routine returns a NULL pointer.
*/
-SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
+SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3*);
/*
** CAPI3REF: Low-Level Control Of Database Files
+** METHOD: sqlite3
**
** ^The [sqlite3_file_control()] interface makes a direct call to the
** xFileControl method for the [sqlite3_io_methods] object associated
@@ -6228,7 +6522,7 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
**
** See also: [SQLITE_FCNTL_LOCKSTATE]
*/
-SQLITE_API int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
+SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
/*
** CAPI3REF: Testing Interface
@@ -6247,7 +6541,7 @@ SQLITE_API int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*
** Unlike most of the SQLite API, this function is not guaranteed to
** operate consistently from one release to the next.
*/
-SQLITE_API int sqlite3_test_control(int op, ...);
+SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...);
/*
** CAPI3REF: Testing Interface Operation Codes
@@ -6275,17 +6569,19 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_ISKEYWORD 16
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
-#define SQLITE_TESTCTRL_EXPLAIN_STMT 19
+#define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */
#define SQLITE_TESTCTRL_NEVER_CORRUPT 20
#define SQLITE_TESTCTRL_VDBE_COVERAGE 21
#define SQLITE_TESTCTRL_BYTEORDER 22
#define SQLITE_TESTCTRL_ISINIT 23
-#define SQLITE_TESTCTRL_LAST 23
+#define SQLITE_TESTCTRL_SORTER_MMAP 24
+#define SQLITE_TESTCTRL_IMPOSTER 25
+#define SQLITE_TESTCTRL_LAST 25
/*
** CAPI3REF: SQLite Runtime Status
**
-** ^This interface is used to retrieve runtime status information
+** ^These interfaces are used to retrieve runtime status information
** about the performance of SQLite, and optionally to reset various
** highwater marks. ^The first argument is an integer code for
** the specific parameter to measure. ^(Recognized integer codes
@@ -6299,19 +6595,22 @@ SQLITE_API int sqlite3_test_control(int op, ...);
** ^(Other parameters record only the highwater mark and not the current
** value. For these latter parameters nothing is written into *pCurrent.)^
**
-** ^The sqlite3_status() routine returns SQLITE_OK on success and a
-** non-zero [error code] on failure.
+** ^The sqlite3_status() and sqlite3_status64() routines return
+** SQLITE_OK on success and a non-zero [error code] on failure.
**
-** This routine is threadsafe but is not atomic. This routine can be
-** called while other threads are running the same or different SQLite
-** interfaces. However the values returned in *pCurrent and
-** *pHighwater reflect the status of SQLite at different points in time
-** and it is possible that another thread might change the parameter
-** in between the times when *pCurrent and *pHighwater are written.
+** If either the current value or the highwater mark is too large to
+** be represented by a 32-bit integer, then the values returned by
+** sqlite3_status() are undefined.
**
** See also: [sqlite3_db_status()]
*/
-SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
+SQLITE_API int SQLITE_STDCALL sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
+SQLITE_API int SQLITE_STDCALL sqlite3_status64(
+ int op,
+ sqlite3_int64 *pCurrent,
+ sqlite3_int64 *pHighwater,
+ int resetFlag
+);
/*
@@ -6409,6 +6708,7 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
/*
** CAPI3REF: Database Connection Status
+** METHOD: sqlite3
**
** ^This interface is used to retrieve runtime status information
** about a single [database connection]. ^The first argument is the
@@ -6429,7 +6729,7 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
**
** See also: [sqlite3_status()] and [sqlite3_stmt_status()].
*/
-SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
+SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
/*
** CAPI3REF: Status Parameters for database connections
@@ -6471,12 +6771,12 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
** the current value is always zero.)^
**
** [[SQLITE_DBSTATUS_CACHE_USED]] ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt>
-** <dd>This parameter returns the approximate number of of bytes of heap
+** <dd>This parameter returns the approximate number of bytes of heap
** memory used by all pager caches associated with the database connection.)^
** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
**
** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt>
-** <dd>This parameter returns the approximate number of of bytes of heap
+** <dd>This parameter returns the approximate number of bytes of heap
** memory used to store the schema for all databases associated
** with the connection - main, temp, and any [ATTACH]-ed databases.)^
** ^The full amount of memory used by the schemas is reported, even if the
@@ -6485,7 +6785,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0.
**
** [[SQLITE_DBSTATUS_STMT_USED]] ^(<dt>SQLITE_DBSTATUS_STMT_USED</dt>
-** <dd>This parameter returns the approximate number of of bytes of heap
+** <dd>This parameter returns the approximate number of bytes of heap
** and lookaside memory used by all prepared statements associated with
** the database connection.)^
** ^The highwater mark associated with SQLITE_DBSTATUS_STMT_USED is always 0.
@@ -6537,6 +6837,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
/*
** CAPI3REF: Prepared Statement Status
+** METHOD: sqlite3_stmt
**
** ^(Each prepared statement maintains various
** [SQLITE_STMTSTATUS counters] that measure the number
@@ -6558,7 +6859,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
**
** See also: [sqlite3_status()] and [sqlite3_db_status()].
*/
-SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
+SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
/*
** CAPI3REF: Status Parameters for prepared statements
@@ -6885,6 +7186,10 @@ typedef struct sqlite3_backup sqlite3_backup;
** must be different or else sqlite3_backup_init(D,N,S,M) will fail with
** an error.
**
+** ^A call to sqlite3_backup_init() will fail, returning SQLITE_ERROR, if
+** there is already a read or read-write transaction open on the
+** destination database.
+**
** ^If an error occurs within sqlite3_backup_init(D,N,S,M), then NULL is
** returned and an error code and error message are stored in the
** destination [database connection] D.
@@ -6977,20 +7282,20 @@ typedef struct sqlite3_backup sqlite3_backup;
** is not a permanent error and does not affect the return value of
** sqlite3_backup_finish().
**
-** [[sqlite3_backup__remaining()]] [[sqlite3_backup_pagecount()]]
+** [[sqlite3_backup_remaining()]] [[sqlite3_backup_pagecount()]]
** <b>sqlite3_backup_remaining() and sqlite3_backup_pagecount()</b>
**
-** ^Each call to sqlite3_backup_step() sets two values inside
-** the [sqlite3_backup] object: the number of pages still to be backed
-** up and the total number of pages in the source database file.
-** The sqlite3_backup_remaining() and sqlite3_backup_pagecount() interfaces
-** retrieve these two values, respectively.
-**
-** ^The values returned by these functions are only updated by
-** sqlite3_backup_step(). ^If the source database is modified during a backup
-** operation, then the values are not updated to account for any extra
-** pages that need to be updated or the size of the source database file
-** changing.
+** ^The sqlite3_backup_remaining() routine returns the number of pages still
+** to be backed up at the conclusion of the most recent sqlite3_backup_step().
+** ^The sqlite3_backup_pagecount() routine returns the total number of pages
+** in the source database at the conclusion of the most recent
+** sqlite3_backup_step().
+** ^(The values returned by these functions are only updated by
+** sqlite3_backup_step(). If the source database is modified in a way that
+** changes the size of the source database or the number of pages remaining,
+** those changes are not reflected in the output of sqlite3_backup_pagecount()
+** and sqlite3_backup_remaining() until after the next
+** sqlite3_backup_step().)^
**
** <b>Concurrent Usage of Database Handles</b>
**
@@ -7023,19 +7328,20 @@ typedef struct sqlite3_backup sqlite3_backup;
** same time as another thread is invoking sqlite3_backup_step() it is
** possible that they return invalid values.
*/
-SQLITE_API sqlite3_backup *sqlite3_backup_init(
+SQLITE_API sqlite3_backup *SQLITE_STDCALL sqlite3_backup_init(
sqlite3 *pDest, /* Destination database handle */
const char *zDestName, /* Destination database name */
sqlite3 *pSource, /* Source database handle */
const char *zSourceName /* Source database name */
);
-SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage);
-SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p);
-SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p);
-SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
+SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage);
+SQLITE_API int SQLITE_STDCALL sqlite3_backup_finish(sqlite3_backup *p);
+SQLITE_API int SQLITE_STDCALL sqlite3_backup_remaining(sqlite3_backup *p);
+SQLITE_API int SQLITE_STDCALL sqlite3_backup_pagecount(sqlite3_backup *p);
/*
** CAPI3REF: Unlock Notification
+** METHOD: sqlite3
**
** ^When running in shared-cache mode, a database operation may fail with
** an [SQLITE_LOCKED] error if the required locks on the shared-cache or
@@ -7148,7 +7454,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
** the special "DROP TABLE/INDEX" case, the extended error code is just
** SQLITE_LOCKED.)^
*/
-SQLITE_API int sqlite3_unlock_notify(
+SQLITE_API int SQLITE_STDCALL sqlite3_unlock_notify(
sqlite3 *pBlocked, /* Waiting connection */
void (*xNotify)(void **apArg, int nArg), /* Callback function to invoke */
void *pNotifyArg /* Argument to pass to xNotify */
@@ -7163,8 +7469,8 @@ SQLITE_API int sqlite3_unlock_notify(
** strings in a case-independent fashion, using the same definition of "case
** independence" that SQLite uses internally when comparing identifiers.
*/
-SQLITE_API int sqlite3_stricmp(const char *, const char *);
-SQLITE_API int sqlite3_strnicmp(const char *, const char *, int);
+SQLITE_API int SQLITE_STDCALL sqlite3_stricmp(const char *, const char *);
+SQLITE_API int SQLITE_STDCALL sqlite3_strnicmp(const char *, const char *, int);
/*
** CAPI3REF: String Globbing
@@ -7179,7 +7485,7 @@ SQLITE_API int sqlite3_strnicmp(const char *, const char *, int);
** Note that this routine returns zero on a match and non-zero if the strings
** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()].
*/
-SQLITE_API int sqlite3_strglob(const char *zGlob, const char *zStr);
+SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlob, const char *zStr);
/*
** CAPI3REF: Error Logging Interface
@@ -7202,18 +7508,17 @@ SQLITE_API int sqlite3_strglob(const char *zGlob, const char *zStr);
** a few hundred characters, it will be truncated to the length of the
** buffer.
*/
-SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
+SQLITE_API void SQLITE_CDECL sqlite3_log(int iErrCode, const char *zFormat, ...);
/*
** CAPI3REF: Write-Ahead Log Commit Hook
+** METHOD: sqlite3
**
** ^The [sqlite3_wal_hook()] function is used to register a callback that
-** will be invoked each time a database connection commits data to a
-** [write-ahead log] (i.e. whenever a transaction is committed in
-** [journal_mode | journal_mode=WAL mode]).
+** is invoked each time data is committed to a database in wal mode.
**
-** ^The callback is invoked by SQLite after the commit has taken place and
-** the associated write-lock on the database released, so the implementation
+** ^(The callback is invoked by SQLite after the commit has taken place and
+** the associated write-lock on the database released)^, so the implementation
** may read, write or [checkpoint] the database as required.
**
** ^The first parameter passed to the callback function when it is invoked
@@ -7239,7 +7544,7 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will
** those overwrite any prior [sqlite3_wal_hook()] settings.
*/
-SQLITE_API void *sqlite3_wal_hook(
+SQLITE_API void *SQLITE_STDCALL sqlite3_wal_hook(
sqlite3*,
int(*)(void *,sqlite3*,const char*,int),
void*
@@ -7247,6 +7552,7 @@ SQLITE_API void *sqlite3_wal_hook(
/*
** CAPI3REF: Configure an auto-checkpoint
+** METHOD: sqlite3
**
** ^The [sqlite3_wal_autocheckpoint(D,N)] is a wrapper around
** [sqlite3_wal_hook()] that causes any database on [database connection] D
@@ -7273,104 +7579,123 @@ SQLITE_API void *sqlite3_wal_hook(
** is only necessary if the default setting is found to be suboptimal
** for a particular application.
*/
-SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
+SQLITE_API int SQLITE_STDCALL sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
/*
** CAPI3REF: Checkpoint a database
+** METHOD: sqlite3
**
-** ^The [sqlite3_wal_checkpoint(D,X)] interface causes database named X
-** on [database connection] D to be [checkpointed]. ^If X is NULL or an
-** empty string, then a checkpoint is run on all databases of
-** connection D. ^If the database connection D is not in
-** [WAL | write-ahead log mode] then this interface is a harmless no-op.
-** ^The [sqlite3_wal_checkpoint(D,X)] interface initiates a
-** [sqlite3_wal_checkpoint_v2|PASSIVE] checkpoint.
-** Use the [sqlite3_wal_checkpoint_v2()] interface to get a FULL
-** or RESET checkpoint.
+** ^(The sqlite3_wal_checkpoint(D,X) is equivalent to
+** [sqlite3_wal_checkpoint_v2](D,X,[SQLITE_CHECKPOINT_PASSIVE],0,0).)^
**
-** ^The [wal_checkpoint pragma] can be used to invoke this interface
-** from SQL. ^The [sqlite3_wal_autocheckpoint()] interface and the
-** [wal_autocheckpoint pragma] can be used to cause this interface to be
-** run whenever the WAL reaches a certain size threshold.
+** In brief, sqlite3_wal_checkpoint(D,X) causes the content in the
+** [write-ahead log] for database X on [database connection] D to be
+** transferred into the database file and for the write-ahead log to
+** be reset. See the [checkpointing] documentation for addition
+** information.
**
-** See also: [sqlite3_wal_checkpoint_v2()]
+** This interface used to be the only way to cause a checkpoint to
+** occur. But then the newer and more powerful [sqlite3_wal_checkpoint_v2()]
+** interface was added. This interface is retained for backwards
+** compatibility and as a convenience for applications that need to manually
+** start a callback but which do not need the full power (and corresponding
+** complication) of [sqlite3_wal_checkpoint_v2()].
*/
-SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
+SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
/*
** CAPI3REF: Checkpoint a database
+** METHOD: sqlite3
**
-** Run a checkpoint operation on WAL database zDb attached to database
-** handle db. The specific operation is determined by the value of the
-** eMode parameter:
+** ^(The sqlite3_wal_checkpoint_v2(D,X,M,L,C) interface runs a checkpoint
+** operation on database X of [database connection] D in mode M. Status
+** information is written back into integers pointed to by L and C.)^
+** ^(The M parameter must be a valid [checkpoint mode]:)^
**
** <dl>
** <dt>SQLITE_CHECKPOINT_PASSIVE<dd>
-** Checkpoint as many frames as possible without waiting for any database
-** readers or writers to finish. Sync the db file if all frames in the log
-** are checkpointed. This mode is the same as calling
-** sqlite3_wal_checkpoint(). The [sqlite3_busy_handler|busy-handler callback]
-** is never invoked.
+** ^Checkpoint as many frames as possible without waiting for any database
+** readers or writers to finish, then sync the database file if all frames
+** in the log were checkpointed. ^The [busy-handler callback]
+** is never invoked in the SQLITE_CHECKPOINT_PASSIVE mode.
+** ^On the other hand, passive mode might leave the checkpoint unfinished
+** if there are concurrent readers or writers.
**
** <dt>SQLITE_CHECKPOINT_FULL<dd>
-** This mode blocks (it invokes the
+** ^This mode blocks (it invokes the
** [sqlite3_busy_handler|busy-handler callback]) until there is no
** database writer and all readers are reading from the most recent database
-** snapshot. It then checkpoints all frames in the log file and syncs the
-** database file. This call blocks database writers while it is running,
-** but not database readers.
+** snapshot. ^It then checkpoints all frames in the log file and syncs the
+** database file. ^This mode blocks new database writers while it is pending,
+** but new database readers are allowed to continue unimpeded.
**
** <dt>SQLITE_CHECKPOINT_RESTART<dd>
-** This mode works the same way as SQLITE_CHECKPOINT_FULL, except after
-** checkpointing the log file it blocks (calls the
-** [sqlite3_busy_handler|busy-handler callback])
-** until all readers are reading from the database file only. This ensures
-** that the next client to write to the database file restarts the log file
-** from the beginning. This call blocks database writers while it is running,
-** but not database readers.
+** ^This mode works the same way as SQLITE_CHECKPOINT_FULL with the addition
+** that after checkpointing the log file it blocks (calls the
+** [busy-handler callback])
+** until all readers are reading from the database file only. ^This ensures
+** that the next writer will restart the log file from the beginning.
+** ^Like SQLITE_CHECKPOINT_FULL, this mode blocks new
+** database writer attempts while it is pending, but does not impede readers.
+**
+** <dt>SQLITE_CHECKPOINT_TRUNCATE<dd>
+** ^This mode works the same way as SQLITE_CHECKPOINT_RESTART with the
+** addition that it also truncates the log file to zero bytes just prior
+** to a successful return.
** </dl>
**
-** If pnLog is not NULL, then *pnLog is set to the total number of frames in
-** the log file before returning. If pnCkpt is not NULL, then *pnCkpt is set to
-** the total number of checkpointed frames (including any that were already
-** checkpointed when this function is called). *pnLog and *pnCkpt may be
-** populated even if sqlite3_wal_checkpoint_v2() returns other than SQLITE_OK.
-** If no values are available because of an error, they are both set to -1
-** before returning to communicate this to the caller.
-**
-** All calls obtain an exclusive "checkpoint" lock on the database file. If
+** ^If pnLog is not NULL, then *pnLog is set to the total number of frames in
+** the log file or to -1 if the checkpoint could not run because
+** of an error or because the database is not in [WAL mode]. ^If pnCkpt is not
+** NULL,then *pnCkpt is set to the total number of checkpointed frames in the
+** log file (including any that were already checkpointed before the function
+** was called) or to -1 if the checkpoint could not run due to an error or
+** because the database is not in WAL mode. ^Note that upon successful
+** completion of an SQLITE_CHECKPOINT_TRUNCATE, the log file will have been
+** truncated to zero bytes and so both *pnLog and *pnCkpt will be set to zero.
+**
+** ^All calls obtain an exclusive "checkpoint" lock on the database file. ^If
** any other process is running a checkpoint operation at the same time, the
-** lock cannot be obtained and SQLITE_BUSY is returned. Even if there is a
+** lock cannot be obtained and SQLITE_BUSY is returned. ^Even if there is a
** busy-handler configured, it will not be invoked in this case.
**
-** The SQLITE_CHECKPOINT_FULL and RESTART modes also obtain the exclusive
-** "writer" lock on the database file. If the writer lock cannot be obtained
-** immediately, and a busy-handler is configured, it is invoked and the writer
-** lock retried until either the busy-handler returns 0 or the lock is
-** successfully obtained. The busy-handler is also invoked while waiting for
-** database readers as described above. If the busy-handler returns 0 before
+** ^The SQLITE_CHECKPOINT_FULL, RESTART and TRUNCATE modes also obtain the
+** exclusive "writer" lock on the database file. ^If the writer lock cannot be
+** obtained immediately, and a busy-handler is configured, it is invoked and
+** the writer lock retried until either the busy-handler returns 0 or the lock
+** is successfully obtained. ^The busy-handler is also invoked while waiting for
+** database readers as described above. ^If the busy-handler returns 0 before
** the writer lock is obtained or while waiting for database readers, the
** checkpoint operation proceeds from that point in the same way as
** SQLITE_CHECKPOINT_PASSIVE - checkpointing as many frames as possible
-** without blocking any further. SQLITE_BUSY is returned in this case.
+** without blocking any further. ^SQLITE_BUSY is returned in this case.
**
-** If parameter zDb is NULL or points to a zero length string, then the
-** specified operation is attempted on all WAL databases. In this case the
-** values written to output parameters *pnLog and *pnCkpt are undefined. If
+** ^If parameter zDb is NULL or points to a zero length string, then the
+** specified operation is attempted on all WAL databases [attached] to
+** [database connection] db. In this case the
+** values written to output parameters *pnLog and *pnCkpt are undefined. ^If
** an SQLITE_BUSY error is encountered when processing one or more of the
** attached WAL databases, the operation is still attempted on any remaining
-** attached databases and SQLITE_BUSY is returned to the caller. If any other
+** attached databases and SQLITE_BUSY is returned at the end. ^If any other
** error occurs while processing an attached database, processing is abandoned
-** and the error code returned to the caller immediately. If no error
+** and the error code is returned to the caller immediately. ^If no error
** (SQLITE_BUSY or otherwise) is encountered while processing the attached
** databases, SQLITE_OK is returned.
**
-** If database zDb is the name of an attached database that is not in WAL
-** mode, SQLITE_OK is returned and both *pnLog and *pnCkpt set to -1. If
+** ^If database zDb is the name of an attached database that is not in WAL
+** mode, SQLITE_OK is returned and both *pnLog and *pnCkpt set to -1. ^If
** zDb is not NULL (or a zero length string) and is not the name of any
** attached database, SQLITE_ERROR is returned to the caller.
+**
+** ^Unless it returns SQLITE_MISUSE,
+** the sqlite3_wal_checkpoint_v2() interface
+** sets the error information that is queried by
+** [sqlite3_errcode()] and [sqlite3_errmsg()].
+**
+** ^The [PRAGMA wal_checkpoint] command can be used to invoke this interface
+** from SQL.
*/
-SQLITE_API int sqlite3_wal_checkpoint_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2(
sqlite3 *db, /* Database handle */
const char *zDb, /* Name of attached database (or NULL) */
int eMode, /* SQLITE_CHECKPOINT_* value */
@@ -7379,16 +7704,18 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
);
/*
-** CAPI3REF: Checkpoint operation parameters
+** CAPI3REF: Checkpoint Mode Values
+** KEYWORDS: {checkpoint mode}
**
-** These constants can be used as the 3rd parameter to
-** [sqlite3_wal_checkpoint_v2()]. See the [sqlite3_wal_checkpoint_v2()]
-** documentation for additional information about the meaning and use of
-** each of these values.
+** These constants define all valid values for the "checkpoint mode" passed
+** as the third parameter to the [sqlite3_wal_checkpoint_v2()] interface.
+** See the [sqlite3_wal_checkpoint_v2()] documentation for details on the
+** meaning of each of these checkpoint modes.
*/
-#define SQLITE_CHECKPOINT_PASSIVE 0
-#define SQLITE_CHECKPOINT_FULL 1
-#define SQLITE_CHECKPOINT_RESTART 2
+#define SQLITE_CHECKPOINT_PASSIVE 0 /* Do as much as possible w/o blocking */
+#define SQLITE_CHECKPOINT_FULL 1 /* Wait for writers, then checkpoint */
+#define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for for readers */
+#define SQLITE_CHECKPOINT_TRUNCATE 3 /* Like RESTART but also truncate WAL */
/*
** CAPI3REF: Virtual Table Interface Configuration
@@ -7404,7 +7731,7 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
** this function. (See [SQLITE_VTAB_CONSTRAINT_SUPPORT].) Further options
** may be added in the future.
*/
-SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
+SQLITE_API int SQLITE_CDECL sqlite3_vtab_config(sqlite3*, int op, ...);
/*
** CAPI3REF: Virtual Table Configuration Options
@@ -7457,7 +7784,7 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
** of the SQL statement that triggered the call to the [xUpdate] method of the
** [virtual table].
*/
-SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
+SQLITE_API int SQLITE_STDCALL sqlite3_vtab_on_conflict(sqlite3 *);
/*
** CAPI3REF: Conflict resolution modes
@@ -7477,6 +7804,108 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
/* #define SQLITE_ABORT 4 // Also an error code */
#define SQLITE_REPLACE 5
+/*
+** CAPI3REF: Prepared Statement Scan Status Opcodes
+** KEYWORDS: {scanstatus options}
+**
+** The following constants can be used for the T parameter to the
+** [sqlite3_stmt_scanstatus(S,X,T,V)] interface. Each constant designates a
+** different metric for sqlite3_stmt_scanstatus() to return.
+**
+** When the value returned to V is a string, space to hold that string is
+** managed by the prepared statement S and will be automatically freed when
+** S is finalized.
+**
+** <dl>
+** [[SQLITE_SCANSTAT_NLOOP]] <dt>SQLITE_SCANSTAT_NLOOP</dt>
+** <dd>^The [sqlite3_int64] variable pointed to by the T parameter will be
+** set to the total number of times that the X-th loop has run.</dd>
+**
+** [[SQLITE_SCANSTAT_NVISIT]] <dt>SQLITE_SCANSTAT_NVISIT</dt>
+** <dd>^The [sqlite3_int64] variable pointed to by the T parameter will be set
+** to the total number of rows examined by all iterations of the X-th loop.</dd>
+**
+** [[SQLITE_SCANSTAT_EST]] <dt>SQLITE_SCANSTAT_EST</dt>
+** <dd>^The "double" variable pointed to by the T parameter will be set to the
+** query planner's estimate for the average number of rows output from each
+** iteration of the X-th loop. If the query planner's estimates was accurate,
+** then this value will approximate the quotient NVISIT/NLOOP and the
+** product of this value for all prior loops with the same SELECTID will
+** be the NLOOP value for the current loop.
+**
+** [[SQLITE_SCANSTAT_NAME]] <dt>SQLITE_SCANSTAT_NAME</dt>
+** <dd>^The "const char *" variable pointed to by the T parameter will be set
+** to a zero-terminated UTF-8 string containing the name of the index or table
+** used for the X-th loop.
+**
+** [[SQLITE_SCANSTAT_EXPLAIN]] <dt>SQLITE_SCANSTAT_EXPLAIN</dt>
+** <dd>^The "const char *" variable pointed to by the T parameter will be set
+** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN]
+** description for the X-th loop.
+**
+** [[SQLITE_SCANSTAT_SELECTID]] <dt>SQLITE_SCANSTAT_SELECT</dt>
+** <dd>^The "int" variable pointed to by the T parameter will be set to the
+** "select-id" for the X-th loop. The select-id identifies which query or
+** subquery the loop is part of. The main query has a select-id of zero.
+** The select-id is the same value as is output in the first column
+** of an [EXPLAIN QUERY PLAN] query.
+** </dl>
+*/
+#define SQLITE_SCANSTAT_NLOOP 0
+#define SQLITE_SCANSTAT_NVISIT 1
+#define SQLITE_SCANSTAT_EST 2
+#define SQLITE_SCANSTAT_NAME 3
+#define SQLITE_SCANSTAT_EXPLAIN 4
+#define SQLITE_SCANSTAT_SELECTID 5
+
+/*
+** CAPI3REF: Prepared Statement Scan Status
+** METHOD: sqlite3_stmt
+**
+** This interface returns information about the predicted and measured
+** performance for pStmt. Advanced applications can use this
+** interface to compare the predicted and the measured performance and
+** issue warnings and/or rerun [ANALYZE] if discrepancies are found.
+**
+** Since this interface is expected to be rarely used, it is only
+** available if SQLite is compiled using the [SQLITE_ENABLE_STMT_SCANSTATUS]
+** compile-time option.
+**
+** The "iScanStatusOp" parameter determines which status information to return.
+** The "iScanStatusOp" must be one of the [scanstatus options] or the behavior
+** of this interface is undefined.
+** ^The requested measurement is written into a variable pointed to by
+** the "pOut" parameter.
+** Parameter "idx" identifies the specific loop to retrieve statistics for.
+** Loops are numbered starting from zero. ^If idx is out of range - less than
+** zero or greater than or equal to the total number of loops used to implement
+** the statement - a non-zero value is returned and the variable that pOut
+** points to is unchanged.
+**
+** ^Statistics might not be available for all loops in all statements. ^In cases
+** where there exist loops with no available statistics, this function behaves
+** as if the loop did not exist - it returns non-zero and leave the variable
+** that pOut points to unchanged.
+**
+** See also: [sqlite3_stmt_scanstatus_reset()]
+*/
+SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_stmt_scanstatus(
+ sqlite3_stmt *pStmt, /* Prepared statement for which info desired */
+ int idx, /* Index of loop to report on */
+ int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */
+ void *pOut /* Result written here */
+);
+
+/*
+** CAPI3REF: Zero Scan-Status Counters
+** METHOD: sqlite3_stmt
+**
+** ^Zero all [sqlite3_stmt_scanstatus()] related event counters.
+**
+** This API is only available if the library is built with pre-processor
+** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined.
+*/
+SQLITE_API SQLITE_EXPERIMENTAL void SQLITE_STDCALL sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
/*
@@ -7531,7 +7960,7 @@ typedef struct sqlite3_rtree_query_info sqlite3_rtree_query_info;
**
** SELECT ... FROM <rtree> WHERE <rtree col> MATCH $zGeom(... params ...)
*/
-SQLITE_API int sqlite3_rtree_geometry_callback(
+SQLITE_API int SQLITE_STDCALL sqlite3_rtree_geometry_callback(
sqlite3 *db,
const char *zGeom,
int (*xGeom)(sqlite3_rtree_geometry*, int, sqlite3_rtree_dbl*,int*),
@@ -7557,7 +7986,7 @@ struct sqlite3_rtree_geometry {
**
** SELECT ... FROM <rtree> WHERE <rtree col> MATCH $zQueryFunc(... params ...)
*/
-SQLITE_API int sqlite3_rtree_query_callback(
+SQLITE_API int SQLITE_STDCALL sqlite3_rtree_query_callback(
sqlite3 *db,
const char *zQueryFunc,
int (*xQueryFunc)(sqlite3_rtree_query_info*),
@@ -7721,15 +8150,17 @@ struct sqlite3_rtree_query_info {
#endif
/*
-** The maximum number of in-memory pages to use for the main database
-** table and for temporary tables. The SQLITE_DEFAULT_CACHE_SIZE
+** The suggested maximum number of in-memory pages to use for
+** the main database table and for temporary tables.
+**
+** IMPLEMENTATION-OF: R-31093-59126 The default suggested cache size
+** is 2000 pages.
+** IMPLEMENTATION-OF: R-48205-43578 The default suggested cache size can be
+** altered using the SQLITE_DEFAULT_CACHE_SIZE compile-time options.
*/
#ifndef SQLITE_DEFAULT_CACHE_SIZE
# define SQLITE_DEFAULT_CACHE_SIZE 2000
#endif
-#ifndef SQLITE_DEFAULT_TEMP_CACHE_SIZE
-# define SQLITE_DEFAULT_TEMP_CACHE_SIZE 500
-#endif
/*
** The default number of frames to accumulate in the log file before
@@ -7842,15 +8273,6 @@ struct sqlite3_rtree_query_info {
#pragma warn -spa /* Suspicious pointer arithmetic */
#endif
-/* Needed for various definitions... */
-#ifndef _GNU_SOURCE
-# define _GNU_SOURCE
-#endif
-
-#if defined(__OpenBSD__) && !defined(_BSD_SOURCE)
-# define _BSD_SOURCE
-#endif
-
/*
** Include standard header files as necessary
*/
@@ -7892,6 +8314,18 @@ struct sqlite3_rtree_query_info {
#endif
/*
+** A macro to hint to the compiler that a function should not be
+** inlined.
+*/
+#if defined(__GNUC__)
+# define SQLITE_NOINLINE __attribute__((noinline))
+#elif defined(_MSC_VER) && _MSC_VER>=1310
+# define SQLITE_NOINLINE __declspec(noinline)
+#else
+# define SQLITE_NOINLINE
+#endif
+
+/*
** The SQLITE_THREADSAFE macro must be defined as 0, 1, or 2.
** 0 means mutexes are permanently disable and the library is never
** threadsafe. 1 means the library is serialized which is the highest
@@ -7919,10 +8353,9 @@ struct sqlite3_rtree_query_info {
#endif
/*
-** The SQLITE_DEFAULT_MEMSTATUS macro must be defined as either 0 or 1.
-** It determines whether or not the features related to
-** SQLITE_CONFIG_MEMSTATUS are available by default or not. This value can
-** be overridden at runtime using the sqlite3_config() API.
+** EVIDENCE-OF: R-25715-37072 Memory allocation statistics are enabled by
+** default unless SQLite is compiled with SQLITE_DEFAULT_MEMSTATUS=0 in
+** which case memory allocation statistics are disabled by default.
*/
#if !defined(SQLITE_DEFAULT_MEMSTATUS)
# define SQLITE_DEFAULT_MEMSTATUS 1
@@ -8077,7 +8510,33 @@ SQLITE_PRIVATE void sqlite3Coverage(int);
#endif
/*
-** Return true (non-zero) if the input is a integer that is too large
+** Declarations used for tracing the operating system interfaces.
+*/
+#if defined(SQLITE_FORCE_OS_TRACE) || defined(SQLITE_TEST) || \
+ (defined(SQLITE_DEBUG) && SQLITE_OS_WIN)
+ extern int sqlite3OSTrace;
+# define OSTRACE(X) if( sqlite3OSTrace ) sqlite3DebugPrintf X
+# define SQLITE_HAVE_OS_TRACE
+#else
+# define OSTRACE(X)
+# undef SQLITE_HAVE_OS_TRACE
+#endif
+
+/*
+** Is the sqlite3ErrName() function needed in the build? Currently,
+** it is needed by "mutex_w32.c" (when debugging), "os_win.c" (when
+** OSTRACE is enabled), and by several "test*.c" files (which are
+** compiled using SQLITE_TEST).
+*/
+#if defined(SQLITE_HAVE_OS_TRACE) || defined(SQLITE_TEST) || \
+ (defined(SQLITE_DEBUG) && SQLITE_OS_WIN)
+# define SQLITE_NEED_ERR_NAME
+#else
+# undef SQLITE_NEED_ERR_NAME
+#endif
+
+/*
+** Return true (non-zero) if the input is an integer that is too large
** to fit in 32-bits. This macro is used inside of various testcase()
** macros to verify that we have tested SQLite for large-file support.
*/
@@ -8156,15 +8615,15 @@ struct Hash {
struct HashElem {
HashElem *next, *prev; /* Next and previous elements in the table */
void *data; /* Data associated with this element */
- const char *pKey; int nKey; /* Key associated with this element */
+ const char *pKey; /* Key associated with this element */
};
/*
** Access routines. To delete, insert a NULL pointer.
*/
SQLITE_PRIVATE void sqlite3HashInit(Hash*);
-SQLITE_PRIVATE void *sqlite3HashInsert(Hash*, const char *pKey, int nKey, void *pData);
-SQLITE_PRIVATE void *sqlite3HashFind(const Hash*, const char *pKey, int nKey);
+SQLITE_PRIVATE void *sqlite3HashInsert(Hash*, const char *pKey, void *pData);
+SQLITE_PRIVATE void *sqlite3HashFind(const Hash*, const char *pKey);
SQLITE_PRIVATE void sqlite3HashClear(Hash*);
/*
@@ -8424,6 +8883,27 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
#endif
/*
+** If no value has been provided for SQLITE_MAX_WORKER_THREADS, or if
+** SQLITE_TEMP_STORE is set to 3 (never use temporary files), set it
+** to zero.
+*/
+#if SQLITE_TEMP_STORE==3 || SQLITE_THREADSAFE==0
+# undef SQLITE_MAX_WORKER_THREADS
+# define SQLITE_MAX_WORKER_THREADS 0
+#endif
+#ifndef SQLITE_MAX_WORKER_THREADS
+# define SQLITE_MAX_WORKER_THREADS 8
+#endif
+#ifndef SQLITE_DEFAULT_WORKER_THREADS
+# define SQLITE_DEFAULT_WORKER_THREADS 0
+#endif
+#if SQLITE_DEFAULT_WORKER_THREADS>SQLITE_MAX_WORKER_THREADS
+# undef SQLITE_MAX_WORKER_THREADS
+# define SQLITE_MAX_WORKER_THREADS SQLITE_DEFAULT_WORKER_THREADS
+#endif
+
+
+/*
** GCC does not define the offsetof() macro so we'll have to do it
** ourselves.
*/
@@ -8438,6 +8918,11 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
#define MAX(A,B) ((A)>(B)?(A):(B))
/*
+** Swap two objects of type TYPE.
+*/
+#define SWAP(TYPE,A,B) {TYPE t=A; A=B; B=t;}
+
+/*
** Check to see if this machine uses EBCDIC. (Yes, believe it or
** not, there are still machines out there that use EBCDIC.)
*/
@@ -8526,7 +9011,7 @@ typedef INT8_TYPE i8; /* 1-byte signed integer */
** gives a possible range of values of approximately 1.0e986 to 1e-986.
** But the allowed values are "grainy". Not every value is representable.
** For example, quantities 16 and 17 are both represented by a LogEst
-** of 40. However, since LogEst quantaties are suppose to be estimates,
+** of 40. However, since LogEst quantities are suppose to be estimates,
** not exact values, this imprecision is not a problem.
**
** "LogEst" is short for "Logarithmic Estimate".
@@ -8546,6 +9031,20 @@ typedef INT8_TYPE i8; /* 1-byte signed integer */
typedef INT16_TYPE LogEst;
/*
+** Set the SQLITE_PTRSIZE macro to the number of bytes in a pointer
+*/
+#ifndef SQLITE_PTRSIZE
+# if defined(__SIZEOF_POINTER__)
+# define SQLITE_PTRSIZE __SIZEOF_POINTER__
+# elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \
+ defined(_M_ARM) || defined(__arm__) || defined(__x86)
+# define SQLITE_PTRSIZE 4
+# else
+# define SQLITE_PTRSIZE 8
+# endif
+#endif
+
+/*
** Macros to determine whether the machine is big or little endian,
** and whether or not that determination is run-time or compile-time.
**
@@ -8607,7 +9106,7 @@ SQLITE_PRIVATE const int sqlite3one;
** all alignment restrictions correct.
**
** Except, if SQLITE_4_BYTE_ALIGNED_MALLOC is defined, then the
-** underlying malloc() implemention might return us 4-byte aligned
+** underlying malloc() implementation might return us 4-byte aligned
** pointers. In that case, only verify 4-byte alignment.
*/
#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC
@@ -8675,6 +9174,16 @@ SQLITE_PRIVATE const int sqlite3one;
#endif
/*
+** SELECTTRACE_ENABLED will be either 1 or 0 depending on whether or not
+** the Select query generator tracing logic is turned on.
+*/
+#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_SELECTTRACE)
+# define SELECTTRACE_ENABLED 1
+#else
+# define SELECTTRACE_ENABLED 0
+#endif
+
+/*
** An instance of the following structure is used to store the busy-handler
** callback for a given sqlite handle.
**
@@ -8747,8 +9256,8 @@ struct BusyHandler {
#define SQLITE_WSD const
#define GLOBAL(t,v) (*(t*)sqlite3_wsd_find((void*)&(v), sizeof(v)))
#define sqlite3GlobalConfig GLOBAL(struct Sqlite3Config, sqlite3Config)
-SQLITE_API int sqlite3_wsd_init(int N, int J);
-SQLITE_API void *sqlite3_wsd_find(void *K, int L);
+SQLITE_API int SQLITE_STDCALL sqlite3_wsd_init(int N, int J);
+SQLITE_API void *SQLITE_STDCALL sqlite3_wsd_find(void *K, int L);
#else
#define SQLITE_WSD
#define GLOBAL(t,v) v
@@ -8806,12 +9315,14 @@ typedef struct PrintfArguments PrintfArguments;
typedef struct RowSet RowSet;
typedef struct Savepoint Savepoint;
typedef struct Select Select;
+typedef struct SQLiteThread SQLiteThread;
typedef struct SelectDest SelectDest;
typedef struct SrcList SrcList;
typedef struct StrAccum StrAccum;
typedef struct Table Table;
typedef struct TableLock TableLock;
typedef struct Token Token;
+typedef struct TreeView TreeView;
typedef struct Trigger Trigger;
typedef struct TriggerPrg TriggerPrg;
typedef struct TriggerStep TriggerStep;
@@ -8850,7 +9361,7 @@ typedef struct With With;
/* TODO: This definition is just included so other modules compile. It
** needs to be revisited.
*/
-#define SQLITE_N_BTREE_META 10
+#define SQLITE_N_BTREE_META 16
/*
** If defined as non-zero, auto-vacuum is enabled by default. Otherwise
@@ -8904,17 +9415,15 @@ SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree*);
SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree*,int);
SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree*);
SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree*,int);
-SQLITE_PRIVATE int sqlite3BtreeGetReserve(Btree*);
-#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_DEBUG)
+SQLITE_PRIVATE int sqlite3BtreeGetOptimalReserve(Btree*);
SQLITE_PRIVATE int sqlite3BtreeGetReserveNoMutex(Btree *p);
-#endif
SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *, int);
SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *);
SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree*,int);
SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster);
SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree*, int);
SQLITE_PRIVATE int sqlite3BtreeCommit(Btree*);
-SQLITE_PRIVATE int sqlite3BtreeRollback(Btree*,int);
+SQLITE_PRIVATE int sqlite3BtreeRollback(Btree*,int,int);
SQLITE_PRIVATE int sqlite3BtreeBeginStmt(Btree*,int);
SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree*, int*, int flags);
SQLITE_PRIVATE int sqlite3BtreeIsInTrans(Btree*);
@@ -8947,7 +9456,7 @@ SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *);
SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree*, int, int*);
SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree*, int, int*);
SQLITE_PRIVATE int sqlite3BtreeClearTableOfCursor(BtCursor*);
-SQLITE_PRIVATE void sqlite3BtreeTripAllCursors(Btree*, int);
+SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree*, int, int);
SQLITE_PRIVATE void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue);
SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
@@ -8965,6 +9474,11 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p);
** For example, the free-page-count field is located at byte offset 36 of
** the database file header. The incr-vacuum-flag field is located at
** byte offset 64 (== 36+4*7).
+**
+** The BTREE_DATA_VERSION value is not really a value stored in the header.
+** It is a read-only number computed by the pager. But we merge it with
+** the header value access routines since its access pattern is the same.
+** Call it a "virtual meta value".
*/
#define BTREE_FREE_PAGE_COUNT 0
#define BTREE_SCHEMA_VERSION 1
@@ -8975,12 +9489,23 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p);
#define BTREE_USER_VERSION 6
#define BTREE_INCR_VACUUM 7
#define BTREE_APPLICATION_ID 8
+#define BTREE_DATA_VERSION 15 /* A virtual meta-value */
/*
** Values that may be OR'd together to form the second argument of an
** sqlite3BtreeCursorHints() call.
+**
+** The BTREE_BULKLOAD flag is set on index cursors when the index is going
+** to be filled with content that is already in sorted order.
+**
+** The BTREE_SEEK_EQ flag is set on cursors that will get OP_SeekGE or
+** OP_SeekLE opcodes for a range search, but where the range of entries
+** selected will all have the same key. In other words, the cursor will
+** be used only for equality key searches.
+**
*/
-#define BTREE_BULKLOAD 0x00000001
+#define BTREE_BULKLOAD 0x00000001 /* Used to full index in sorted order */
+#define BTREE_SEEK_EQ 0x00000002 /* EQ seeks only - no range seeks */
SQLITE_PRIVATE int sqlite3BtreeCursor(
Btree*, /* BTree containing table to open */
@@ -9000,7 +9525,8 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
int bias,
int *pRes
);
-SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor*, int*);
+SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor*);
+SQLITE_PRIVATE int sqlite3BtreeCursorRestore(BtCursor*, int*);
SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor*);
SQLITE_PRIVATE int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey,
const void *pData, int nData,
@@ -9025,7 +9551,11 @@ SQLITE_PRIVATE void sqlite3BtreeIncrblobCursor(BtCursor *);
SQLITE_PRIVATE void sqlite3BtreeClearCursor(BtCursor *);
SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBt, int iVersion);
SQLITE_PRIVATE void sqlite3BtreeCursorHints(BtCursor *, unsigned int mask);
+#ifdef SQLITE_DEBUG
+SQLITE_PRIVATE int sqlite3BtreeCursorHasHint(BtCursor*, unsigned int mask);
+#endif
SQLITE_PRIVATE int sqlite3BtreeIsReadonly(Btree *pBt);
+SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void);
#ifndef NDEBUG
SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor*);
@@ -9291,42 +9821,42 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_AddImm 37 /* synopsis: r[P1]=r[P1]+P2 */
#define OP_MustBeInt 38
#define OP_RealAffinity 39
-#define OP_Permutation 40
-#define OP_Compare 41 /* synopsis: r[P1 P3] <-> r[P2 P3] */
-#define OP_Jump 42
-#define OP_Once 43
-#define OP_If 44
-#define OP_IfNot 45
-#define OP_Column 46 /* synopsis: r[P3]=PX */
-#define OP_Affinity 47 /* synopsis: affinity(r[P1 P2]) */
-#define OP_MakeRecord 48 /* synopsis: r[P3]=mkrec(r[P1 P2]) */
-#define OP_Count 49 /* synopsis: r[P2]=count() */
-#define OP_ReadCookie 50
-#define OP_SetCookie 51
-#define OP_ReopenIdx 52 /* synopsis: root=P2 iDb=P3 */
-#define OP_OpenRead 53 /* synopsis: root=P2 iDb=P3 */
-#define OP_OpenWrite 54 /* synopsis: root=P2 iDb=P3 */
-#define OP_OpenAutoindex 55 /* synopsis: nColumn=P2 */
-#define OP_OpenEphemeral 56 /* synopsis: nColumn=P2 */
-#define OP_SorterOpen 57
-#define OP_OpenPseudo 58 /* synopsis: P3 columns in r[P2] */
-#define OP_Close 59
-#define OP_SeekLT 60 /* synopsis: key=r[P3 P4] */
-#define OP_SeekLE 61 /* synopsis: key=r[P3 P4] */
-#define OP_SeekGE 62 /* synopsis: key=r[P3 P4] */
-#define OP_SeekGT 63 /* synopsis: key=r[P3 P4] */
-#define OP_Seek 64 /* synopsis: intkey=r[P2] */
-#define OP_NoConflict 65 /* synopsis: key=r[P3 P4] */
-#define OP_NotFound 66 /* synopsis: key=r[P3 P4] */
-#define OP_Found 67 /* synopsis: key=r[P3 P4] */
-#define OP_NotExists 68 /* synopsis: intkey=r[P3] */
-#define OP_Sequence 69 /* synopsis: r[P2]=cursor[P1].ctr++ */
-#define OP_NewRowid 70 /* synopsis: r[P2]=rowid */
+#define OP_Cast 40 /* synopsis: affinity(r[P1]) */
+#define OP_Permutation 41
+#define OP_Compare 42 /* synopsis: r[P1 P3] <-> r[P2 P3] */
+#define OP_Jump 43
+#define OP_Once 44
+#define OP_If 45
+#define OP_IfNot 46
+#define OP_Column 47 /* synopsis: r[P3]=PX */
+#define OP_Affinity 48 /* synopsis: affinity(r[P1 P2]) */
+#define OP_MakeRecord 49 /* synopsis: r[P3]=mkrec(r[P1 P2]) */
+#define OP_Count 50 /* synopsis: r[P2]=count() */
+#define OP_ReadCookie 51
+#define OP_SetCookie 52
+#define OP_ReopenIdx 53 /* synopsis: root=P2 iDb=P3 */
+#define OP_OpenRead 54 /* synopsis: root=P2 iDb=P3 */
+#define OP_OpenWrite 55 /* synopsis: root=P2 iDb=P3 */
+#define OP_OpenAutoindex 56 /* synopsis: nColumn=P2 */
+#define OP_OpenEphemeral 57 /* synopsis: nColumn=P2 */
+#define OP_SorterOpen 58
+#define OP_SequenceTest 59 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */
+#define OP_OpenPseudo 60 /* synopsis: P3 columns in r[P2] */
+#define OP_Close 61
+#define OP_SeekLT 62 /* synopsis: key=r[P3 P4] */
+#define OP_SeekLE 63 /* synopsis: key=r[P3 P4] */
+#define OP_SeekGE 64 /* synopsis: key=r[P3 P4] */
+#define OP_SeekGT 65 /* synopsis: key=r[P3 P4] */
+#define OP_Seek 66 /* synopsis: intkey=r[P2] */
+#define OP_NoConflict 67 /* synopsis: key=r[P3 P4] */
+#define OP_NotFound 68 /* synopsis: key=r[P3 P4] */
+#define OP_Found 69 /* synopsis: key=r[P3 P4] */
+#define OP_NotExists 70 /* synopsis: intkey=r[P3] */
#define OP_Or 71 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */
#define OP_And 72 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */
-#define OP_Insert 73 /* synopsis: intkey=r[P3] data=r[P2] */
-#define OP_InsertInt 74 /* synopsis: intkey=P3 data=r[P2] */
-#define OP_Delete 75
+#define OP_Sequence 73 /* synopsis: r[P2]=cursor[P1].ctr++ */
+#define OP_NewRowid 74 /* synopsis: r[P2]=rowid */
+#define OP_Insert 75 /* synopsis: intkey=r[P3] data=r[P2] */
#define OP_IsNull 76 /* same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */
#define OP_NotNull 77 /* same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */
#define OP_Ne 78 /* same as TK_NE, synopsis: if r[P1]!=r[P3] goto P2 */
@@ -9335,7 +9865,7 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_Le 81 /* same as TK_LE, synopsis: if r[P1]<=r[P3] goto P2 */
#define OP_Lt 82 /* same as TK_LT, synopsis: if r[P1]<r[P3] goto P2 */
#define OP_Ge 83 /* same as TK_GE, synopsis: if r[P1]>=r[P3] goto P2 */
-#define OP_ResetCount 84
+#define OP_InsertInt 84 /* synopsis: intkey=P3 data=r[P2] */
#define OP_BitAnd 85 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */
#define OP_BitOr 86 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */
#define OP_ShiftLeft 87 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<<r[P1] */
@@ -9346,70 +9876,69 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_Divide 92 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */
#define OP_Remainder 93 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */
#define OP_Concat 94 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */
-#define OP_SorterCompare 95 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */
+#define OP_Delete 95
#define OP_BitNot 96 /* same as TK_BITNOT, synopsis: r[P1]= ~r[P1] */
#define OP_String8 97 /* same as TK_STRING, synopsis: r[P2]='P4' */
-#define OP_SorterData 98 /* synopsis: r[P2]=data */
-#define OP_RowKey 99 /* synopsis: r[P2]=key */
-#define OP_RowData 100 /* synopsis: r[P2]=data */
-#define OP_Rowid 101 /* synopsis: r[P2]=rowid */
-#define OP_NullRow 102
-#define OP_Last 103
-#define OP_SorterSort 104
-#define OP_Sort 105
-#define OP_Rewind 106
-#define OP_SorterInsert 107
-#define OP_IdxInsert 108 /* synopsis: key=r[P2] */
-#define OP_IdxDelete 109 /* synopsis: key=r[P2 P3] */
-#define OP_IdxRowid 110 /* synopsis: r[P2]=rowid */
-#define OP_IdxLE 111 /* synopsis: key=r[P3 P4] */
-#define OP_IdxGT 112 /* synopsis: key=r[P3 P4] */
-#define OP_IdxLT 113 /* synopsis: key=r[P3 P4] */
-#define OP_IdxGE 114 /* synopsis: key=r[P3 P4] */
-#define OP_Destroy 115
-#define OP_Clear 116
-#define OP_ResetSorter 117
-#define OP_CreateIndex 118 /* synopsis: r[P2]=root iDb=P1 */
-#define OP_CreateTable 119 /* synopsis: r[P2]=root iDb=P1 */
-#define OP_ParseSchema 120
-#define OP_LoadAnalysis 121
-#define OP_DropTable 122
-#define OP_DropIndex 123
-#define OP_DropTrigger 124
-#define OP_IntegrityCk 125
-#define OP_RowSetAdd 126 /* synopsis: rowset(P1)=r[P2] */
-#define OP_RowSetRead 127 /* synopsis: r[P3]=rowset(P1) */
-#define OP_RowSetTest 128 /* synopsis: if r[P3] in rowset(P1) goto P2 */
-#define OP_Program 129
-#define OP_Param 130
-#define OP_FkCounter 131 /* synopsis: fkctr[P1]+=P2 */
-#define OP_FkIfZero 132 /* synopsis: if fkctr[P1]==0 goto P2 */
+#define OP_ResetCount 98
+#define OP_SorterCompare 99 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */
+#define OP_SorterData 100 /* synopsis: r[P2]=data */
+#define OP_RowKey 101 /* synopsis: r[P2]=key */
+#define OP_RowData 102 /* synopsis: r[P2]=data */
+#define OP_Rowid 103 /* synopsis: r[P2]=rowid */
+#define OP_NullRow 104
+#define OP_Last 105
+#define OP_SorterSort 106
+#define OP_Sort 107
+#define OP_Rewind 108
+#define OP_SorterInsert 109
+#define OP_IdxInsert 110 /* synopsis: key=r[P2] */
+#define OP_IdxDelete 111 /* synopsis: key=r[P2 P3] */
+#define OP_IdxRowid 112 /* synopsis: r[P2]=rowid */
+#define OP_IdxLE 113 /* synopsis: key=r[P3 P4] */
+#define OP_IdxGT 114 /* synopsis: key=r[P3 P4] */
+#define OP_IdxLT 115 /* synopsis: key=r[P3 P4] */
+#define OP_IdxGE 116 /* synopsis: key=r[P3 P4] */
+#define OP_Destroy 117
+#define OP_Clear 118
+#define OP_ResetSorter 119
+#define OP_CreateIndex 120 /* synopsis: r[P2]=root iDb=P1 */
+#define OP_CreateTable 121 /* synopsis: r[P2]=root iDb=P1 */
+#define OP_ParseSchema 122
+#define OP_LoadAnalysis 123
+#define OP_DropTable 124
+#define OP_DropIndex 125
+#define OP_DropTrigger 126
+#define OP_IntegrityCk 127
+#define OP_RowSetAdd 128 /* synopsis: rowset(P1)=r[P2] */
+#define OP_RowSetRead 129 /* synopsis: r[P3]=rowset(P1) */
+#define OP_RowSetTest 130 /* synopsis: if r[P3] in rowset(P1) goto P2 */
+#define OP_Program 131
+#define OP_Param 132
#define OP_Real 133 /* same as TK_FLOAT, synopsis: r[P2]=P4 */
-#define OP_MemMax 134 /* synopsis: r[P1]=max(r[P1],r[P2]) */
-#define OP_IfPos 135 /* synopsis: if r[P1]>0 goto P2 */
-#define OP_IfNeg 136 /* synopsis: r[P1]+=P3, if r[P1]<0 goto P2 */
-#define OP_IfZero 137 /* synopsis: r[P1]+=P3, if r[P1]==0 goto P2 */
-#define OP_AggFinal 138 /* synopsis: accum=r[P1] N=P2 */
-#define OP_IncrVacuum 139
-#define OP_Expire 140
-#define OP_TableLock 141 /* synopsis: iDb=P1 root=P2 write=P3 */
-#define OP_VBegin 142
-#define OP_ToText 143 /* same as TK_TO_TEXT */
-#define OP_ToBlob 144 /* same as TK_TO_BLOB */
-#define OP_ToNumeric 145 /* same as TK_TO_NUMERIC */
-#define OP_ToInt 146 /* same as TK_TO_INT */
-#define OP_ToReal 147 /* same as TK_TO_REAL */
-#define OP_VCreate 148
-#define OP_VDestroy 149
-#define OP_VOpen 150
-#define OP_VColumn 151 /* synopsis: r[P3]=vcolumn(P2) */
-#define OP_VNext 152
-#define OP_VRename 153
-#define OP_Pagecount 154
-#define OP_MaxPgcnt 155
-#define OP_Init 156 /* synopsis: Start at P2 */
-#define OP_Noop 157
-#define OP_Explain 158
+#define OP_FkCounter 134 /* synopsis: fkctr[P1]+=P2 */
+#define OP_FkIfZero 135 /* synopsis: if fkctr[P1]==0 goto P2 */
+#define OP_MemMax 136 /* synopsis: r[P1]=max(r[P1],r[P2]) */
+#define OP_IfPos 137 /* synopsis: if r[P1]>0 goto P2 */
+#define OP_IfNeg 138 /* synopsis: r[P1]+=P3, if r[P1]<0 goto P2 */
+#define OP_IfNotZero 139 /* synopsis: if r[P1]!=0 then r[P1]+=P3, goto P2 */
+#define OP_DecrJumpZero 140 /* synopsis: if (--r[P1])==0 goto P2 */
+#define OP_JumpZeroIncr 141 /* synopsis: if (r[P1]++)==0 ) goto P2 */
+#define OP_AggFinal 142 /* synopsis: accum=r[P1] N=P2 */
+#define OP_IncrVacuum 143
+#define OP_Expire 144
+#define OP_TableLock 145 /* synopsis: iDb=P1 root=P2 write=P3 */
+#define OP_VBegin 146
+#define OP_VCreate 147
+#define OP_VDestroy 148
+#define OP_VOpen 149
+#define OP_VColumn 150 /* synopsis: r[P3]=vcolumn(P2) */
+#define OP_VNext 151
+#define OP_VRename 152
+#define OP_Pagecount 153
+#define OP_MaxPgcnt 154
+#define OP_Init 155 /* synopsis: Start at P2 */
+#define OP_Noop 156
+#define OP_Explain 157
/* Properties such as "out2" or "jump" that are specified in
@@ -9417,33 +9946,32 @@ typedef struct VdbeOpList VdbeOpList;
** are encoded into bitvectors as follows:
*/
#define OPFLG_JUMP 0x0001 /* jump: P2 holds jmp target */
-#define OPFLG_OUT2_PRERELEASE 0x0002 /* out2-prerelease: */
-#define OPFLG_IN1 0x0004 /* in1: P1 is an input */
-#define OPFLG_IN2 0x0008 /* in2: P2 is an input */
-#define OPFLG_IN3 0x0010 /* in3: P3 is an input */
-#define OPFLG_OUT2 0x0020 /* out2: P2 is an output */
-#define OPFLG_OUT3 0x0040 /* out3: P3 is an output */
+#define OPFLG_IN1 0x0002 /* in1: P1 is an input */
+#define OPFLG_IN2 0x0004 /* in2: P2 is an input */
+#define OPFLG_IN3 0x0008 /* in3: P3 is an input */
+#define OPFLG_OUT2 0x0010 /* out2: P2 is an output */
+#define OPFLG_OUT3 0x0020 /* out3: P3 is an output */
#define OPFLG_INITIALIZER {\
/* 0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,\
-/* 8 */ 0x01, 0x01, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,\
-/* 16 */ 0x01, 0x01, 0x04, 0x24, 0x01, 0x04, 0x05, 0x10,\
-/* 24 */ 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02,\
-/* 32 */ 0x00, 0x00, 0x20, 0x00, 0x00, 0x04, 0x05, 0x04,\
-/* 40 */ 0x00, 0x00, 0x01, 0x01, 0x05, 0x05, 0x00, 0x00,\
-/* 48 */ 0x00, 0x02, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00,\
-/* 56 */ 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,\
-/* 64 */ 0x08, 0x11, 0x11, 0x11, 0x11, 0x02, 0x02, 0x4c,\
-/* 72 */ 0x4c, 0x00, 0x00, 0x00, 0x05, 0x05, 0x15, 0x15,\
-/* 80 */ 0x15, 0x15, 0x15, 0x15, 0x00, 0x4c, 0x4c, 0x4c,\
-/* 88 */ 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x00,\
-/* 96 */ 0x24, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01,\
-/* 104 */ 0x01, 0x01, 0x01, 0x08, 0x08, 0x00, 0x02, 0x01,\
-/* 112 */ 0x01, 0x01, 0x01, 0x02, 0x00, 0x00, 0x02, 0x02,\
-/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x45,\
-/* 128 */ 0x15, 0x01, 0x02, 0x00, 0x01, 0x02, 0x08, 0x05,\
-/* 136 */ 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04,\
-/* 144 */ 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00,\
-/* 152 */ 0x01, 0x00, 0x02, 0x02, 0x01, 0x00, 0x00,}
+/* 8 */ 0x01, 0x01, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,\
+/* 16 */ 0x01, 0x01, 0x02, 0x12, 0x01, 0x02, 0x03, 0x08,\
+/* 24 */ 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10,\
+/* 32 */ 0x00, 0x00, 0x10, 0x00, 0x00, 0x02, 0x03, 0x02,\
+/* 40 */ 0x02, 0x00, 0x00, 0x01, 0x01, 0x03, 0x03, 0x00,\
+/* 48 */ 0x00, 0x00, 0x10, 0x10, 0x08, 0x00, 0x00, 0x00,\
+/* 56 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09,\
+/* 64 */ 0x09, 0x09, 0x04, 0x09, 0x09, 0x09, 0x09, 0x26,\
+/* 72 */ 0x26, 0x10, 0x10, 0x00, 0x03, 0x03, 0x0b, 0x0b,\
+/* 80 */ 0x0b, 0x0b, 0x0b, 0x0b, 0x00, 0x26, 0x26, 0x26,\
+/* 88 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x00,\
+/* 96 */ 0x12, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\
+/* 104 */ 0x00, 0x01, 0x01, 0x01, 0x01, 0x04, 0x04, 0x00,\
+/* 112 */ 0x10, 0x01, 0x01, 0x01, 0x01, 0x10, 0x00, 0x00,\
+/* 120 */ 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+/* 128 */ 0x06, 0x23, 0x0b, 0x01, 0x10, 0x10, 0x00, 0x01,\
+/* 136 */ 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x01,\
+/* 144 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,\
+/* 152 */ 0x00, 0x10, 0x10, 0x01, 0x00, 0x00,}
/************** End of opcodes.h *********************************************/
/************** Continuing where we left off in vdbe.h ***********************/
@@ -9501,10 +10029,11 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(Vdbe*, const char*);
SQLITE_PRIVATE int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*);
-SQLITE_PRIVATE int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*,int);
+SQLITE_PRIVATE int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*);
+SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(int, const void *, UnpackedRecord *, int);
SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *, char *, int, char **);
-typedef int (*RecordCompare)(int,const void*,UnpackedRecord*,int);
+typedef int (*RecordCompare)(int,const void*,UnpackedRecord*);
SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*);
#ifndef SQLITE_OMIT_TRIGGER
@@ -9571,6 +10100,12 @@ SQLITE_PRIVATE void sqlite3VdbeSetLineNumber(Vdbe*,int);
# define VDBE_OFFSET_LINENO(x) 0
#endif
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+SQLITE_PRIVATE void sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const char*);
+#else
+# define sqlite3VdbeScanStatus(a,b,c,d,e)
+#endif
+
#endif
/************** End of vdbe.h ************************************************/
@@ -9751,6 +10286,7 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager);
/* Functions used to query pager state and configuration. */
SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager*);
+SQLITE_PRIVATE u32 sqlite3PagerDataVersion(Pager*);
SQLITE_PRIVATE int sqlite3PagerRefcount(Pager*);
SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*);
SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager*, int);
@@ -9767,6 +10303,8 @@ SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *);
/* Functions used to truncate the database file. */
SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno);
+SQLITE_PRIVATE void sqlite3PagerRekey(DbPage*, Pgno, u16);
+
#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL)
SQLITE_PRIVATE void *sqlite3PagerCodec(DbPage *);
#endif
@@ -9862,7 +10400,7 @@ SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *, int sz, int n);
** Under memory stress, invoke xStress to try to make pages clean.
** Only clean and unpinned pages can be reclaimed.
*/
-SQLITE_PRIVATE void sqlite3PcacheOpen(
+SQLITE_PRIVATE int sqlite3PcacheOpen(
int szPage, /* Size of every page */
int szExtra, /* Extra space associated with each page */
int bPurgeable, /* True if pages are on backing store */
@@ -9872,7 +10410,7 @@ SQLITE_PRIVATE void sqlite3PcacheOpen(
);
/* Modify the page-size after the cache has been created. */
-SQLITE_PRIVATE void sqlite3PcacheSetPageSize(PCache *, int);
+SQLITE_PRIVATE int sqlite3PcacheSetPageSize(PCache *, int);
/* Return the size in bytes of a PCache object. Used to preallocate
** storage space.
@@ -9882,7 +10420,9 @@ SQLITE_PRIVATE int sqlite3PcacheSize(void);
/* One release per successful fetch. Page is pinned until released.
** Reference counted.
*/
-SQLITE_PRIVATE int sqlite3PcacheFetch(PCache*, Pgno, int createFlag, PgHdr**);
+SQLITE_PRIVATE sqlite3_pcache_page *sqlite3PcacheFetch(PCache*, Pgno, int createFlag);
+SQLITE_PRIVATE int sqlite3PcacheFetchStress(PCache*, Pgno, sqlite3_pcache_page**);
+SQLITE_PRIVATE PgHdr *sqlite3PcacheFetchFinish(PCache*, Pgno, sqlite3_pcache_page *pPage);
SQLITE_PRIVATE void sqlite3PcacheRelease(PgHdr*);
SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr*); /* Remove page from cache */
@@ -9952,6 +10492,10 @@ SQLITE_PRIVATE void sqlite3PcacheStats(int*,int*,int*,int*);
SQLITE_PRIVATE void sqlite3PCacheSetDefault(void);
+/* Return the header size */
+SQLITE_PRIVATE int sqlite3HeaderSizePcache(void);
+SQLITE_PRIVATE int sqlite3HeaderSizePcache1(void);
+
#endif /* _PCACHE_H_ */
/************** End of pcache.h **********************************************/
@@ -10142,7 +10686,7 @@ SQLITE_PRIVATE void sqlite3PCacheSetDefault(void);
** shared locks begins at SHARED_FIRST.
**
** The same locking strategy and
-** byte ranges are used for Unix. This leaves open the possiblity of having
+** byte ranges are used for Unix. This leaves open the possibility of having
** clients on win95, winNT, and unix all talking to the same shared file
** and all locking correctly. To do so would require that samba (or whatever
** tool is being used for file sharing) implements locks correctly between
@@ -10261,7 +10805,7 @@ SQLITE_PRIVATE int sqlite3OsCloseFree(sqlite3_file *);
** Figure out what version of the code to use. The choices are
**
** SQLITE_MUTEX_OMIT No mutex logic. Not even stubs. The
-** mutexes implemention cannot be overridden
+** mutexes implementation cannot be overridden
** at start-time.
**
** SQLITE_MUTEX_NOOP For single-threaded applications. No
@@ -10381,7 +10925,7 @@ struct Schema {
** The number of different kinds of things that can be limited
** using the sqlite3_limit() interface.
*/
-#define SQLITE_N_LIMIT (SQLITE_LIMIT_TRIGGER_DEPTH+1)
+#define SQLITE_N_LIMIT (SQLITE_LIMIT_WORKER_THREADS+1)
/*
** Lookaside malloc is a set of fixed-size buffers that can be used
@@ -10428,6 +10972,45 @@ struct FuncDefHash {
FuncDef *a[23]; /* Hash table for functions */
};
+#ifdef SQLITE_USER_AUTHENTICATION
+/*
+** Information held in the "sqlite3" database connection object and used
+** to manage user authentication.
+*/
+typedef struct sqlite3_userauth sqlite3_userauth;
+struct sqlite3_userauth {
+ u8 authLevel; /* Current authentication level */
+ int nAuthPW; /* Size of the zAuthPW in bytes */
+ char *zAuthPW; /* Password used to authenticate */
+ char *zAuthUser; /* User name used to authenticate */
+};
+
+/* Allowed values for sqlite3_userauth.authLevel */
+#define UAUTH_Unknown 0 /* Authentication not yet checked */
+#define UAUTH_Fail 1 /* User authentication failed */
+#define UAUTH_User 2 /* Authenticated as a normal user */
+#define UAUTH_Admin 3 /* Authenticated as an administrator */
+
+/* Functions used only by user authorization logic */
+SQLITE_PRIVATE int sqlite3UserAuthTable(const char*);
+SQLITE_PRIVATE int sqlite3UserAuthCheckLogin(sqlite3*,const char*,u8*);
+SQLITE_PRIVATE void sqlite3UserAuthInit(sqlite3*);
+SQLITE_PRIVATE void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**);
+
+#endif /* SQLITE_USER_AUTHENTICATION */
+
+/*
+** typedef for the authorization callback function.
+*/
+#ifdef SQLITE_USER_AUTHENTICATION
+ typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*,
+ const char*, const char*);
+#else
+ typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*,
+ const char*);
+#endif
+
+
/*
** Each database connection is an instance of the following structure.
*/
@@ -10445,6 +11028,7 @@ struct sqlite3 {
int errCode; /* Most recent error code (SQLITE_*) */
int errMask; /* & result codes with this before returning */
u16 dbOptFlags; /* Flags to enable/disable optimizations */
+ u8 enc; /* Text encoding */
u8 autoCommit; /* The auto-commit flag. */
u8 temp_store; /* 1: file 2: memory 0: default */
u8 mallocFailed; /* True if we have seen a malloc failure */
@@ -10458,16 +11042,19 @@ struct sqlite3 {
int nChange; /* Value returned by sqlite3_changes() */
int nTotalChange; /* Value returned by sqlite3_total_changes() */
int aLimit[SQLITE_N_LIMIT]; /* Limits */
+ int nMaxSorterMmap; /* Maximum size of regions mapped by sorter */
struct sqlite3InitInfo { /* Information used during initialization */
int newTnum; /* Rootpage of table being initialized */
u8 iDb; /* Which db file is being initialized */
u8 busy; /* TRUE if currently initializing */
u8 orphanTrigger; /* Last statement is orphaned TEMP trigger */
+ u8 imposterTable; /* Building an imposter table */
} init;
int nVdbeActive; /* Number of VDBEs currently running */
int nVdbeRead; /* Number of active VDBEs that read or write */
int nVdbeWrite; /* Number of active VDBEs that read and write */
int nVdbeExec; /* Number of nested calls to VdbeExec() */
+ int nVDestroy; /* Number of active OP_VDestroy operations */
int nExtension; /* Number of loaded extensions */
void **aExtension; /* Array of shared library handles */
void (*xTrace)(void*,const char*); /* Trace function */
@@ -10494,8 +11081,7 @@ struct sqlite3 {
} u1;
Lookaside lookaside; /* Lookaside malloc configuration */
#ifndef SQLITE_OMIT_AUTHORIZATION
- int (*xAuth)(void*,int,const char*,const char*,const char*,const char*);
- /* Access authorization function */
+ sqlite3_xauth xAuth; /* Access authorization function */
void *pAuthArg; /* 1st argument to the access auth function */
#endif
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
@@ -10521,7 +11107,6 @@ struct sqlite3 {
i64 nDeferredCons; /* Net deferred constraints this transaction. */
i64 nDeferredImmCons; /* Net deferred immediate constraints */
int *pnBytesFreed; /* If not NULL, increment this in DbFree() */
-
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
/* The following variables are all protected by the STATIC_MASTER
** mutex, not by sqlite3.mutex. They are used by code in notify.c.
@@ -10539,12 +11124,16 @@ struct sqlite3 {
void (*xUnlockNotify)(void **, int); /* Unlock notify callback */
sqlite3 *pNextBlocked; /* Next in list of all blocked connections */
#endif
+#ifdef SQLITE_USER_AUTHENTICATION
+ sqlite3_userauth auth; /* User authentication information */
+#endif
};
/*
** A macro to discover the encoding of a database.
*/
-#define ENC(db) ((db)->aDb[0].pSchema->enc)
+#define SCHEMA_ENC(db) ((db)->aDb[0].pSchema->enc)
+#define ENC(db) ((db)->enc)
/*
** Possible values for the sqlite3.flags.
@@ -10579,6 +11168,7 @@ struct sqlite3 {
#define SQLITE_DeferFKs 0x01000000 /* Defer all FK constraints */
#define SQLITE_QueryOnly 0x02000000 /* Disable database changes */
#define SQLITE_VdbeEQP 0x04000000 /* Debug EXPLAIN QUERY PLAN */
+#define SQLITE_Vacuum 0x08000000 /* Currently in a VACUUM */
/*
@@ -10597,8 +11187,7 @@ struct sqlite3 {
#define SQLITE_SubqCoroutine 0x0100 /* Evaluate subqueries as coroutines */
#define SQLITE_Transitive 0x0200 /* Transitive constraints */
#define SQLITE_OmitNoopJoin 0x0400 /* Omit unused tables in joins */
-#define SQLITE_Stat3 0x0800 /* Use the SQLITE_STAT3 table */
-#define SQLITE_AdjustOutEst 0x1000 /* Adjust output estimates using WHERE */
+#define SQLITE_Stat34 0x0800 /* Use STAT3 or STAT4 data */
#define SQLITE_AllOpts 0xffff /* All optimizations */
/*
@@ -10685,6 +11274,7 @@ struct FuncDestructor {
#define SQLITE_FUNC_COALESCE 0x200 /* Built-in coalesce() or ifnull() */
#define SQLITE_FUNC_UNLIKELY 0x400 /* Built-in unlikely() function */
#define SQLITE_FUNC_CONSTANT 0x800 /* Constant inputs give a constant output */
+#define SQLITE_FUNC_MINMAX 0x1000 /* True for min() and max() aggregates */
/*
** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
@@ -10732,6 +11322,9 @@ struct FuncDestructor {
#define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \
{nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \
SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0,0}
+#define AGGREGATE2(zName, nArg, arg, nc, xStep, xFinal, extraFlags) \
+ {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|extraFlags, \
+ SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0,0}
/*
** All current savepoints are stored in a linked list starting at
@@ -10818,18 +11411,18 @@ struct CollSeq {
** 't' for SQLITE_AFF_TEXT. But we can save a little space and improve
** the speed a little by numbering the values consecutively.
**
-** But rather than start with 0 or 1, we begin with 'a'. That way,
+** But rather than start with 0 or 1, we begin with 'A'. That way,
** when multiple affinity types are concatenated into a string and
** used as the P4 operand, they will be more readable.
**
** Note also that the numeric types are grouped together so that testing
-** for a numeric type is a single comparison.
+** for a numeric type is a single comparison. And the NONE type is first.
*/
-#define SQLITE_AFF_TEXT 'a'
-#define SQLITE_AFF_NONE 'b'
-#define SQLITE_AFF_NUMERIC 'c'
-#define SQLITE_AFF_INTEGER 'd'
-#define SQLITE_AFF_REAL 'e'
+#define SQLITE_AFF_NONE 'A'
+#define SQLITE_AFF_TEXT 'B'
+#define SQLITE_AFF_NUMERIC 'C'
+#define SQLITE_AFF_INTEGER 'D'
+#define SQLITE_AFF_REAL 'E'
#define sqlite3IsNumericAffinity(X) ((X)>=SQLITE_AFF_NUMERIC)
@@ -10837,7 +11430,7 @@ struct CollSeq {
** The SQLITE_AFF_MASK values masks off the significant bits of an
** affinity value.
*/
-#define SQLITE_AFF_MASK 0x67
+#define SQLITE_AFF_MASK 0x47
/*
** Additional bit values that can be ORed with an affinity without
@@ -10848,10 +11441,10 @@ struct CollSeq {
** operator is NULL. It is added to certain comparison operators to
** prove that the operands are always NOT NULL.
*/
-#define SQLITE_JUMPIFNULL 0x08 /* jumps if either operand is NULL */
-#define SQLITE_STOREP2 0x10 /* Store result in reg[P2] rather than jump */
+#define SQLITE_JUMPIFNULL 0x10 /* jumps if either operand is NULL */
+#define SQLITE_STOREP2 0x20 /* Store result in reg[P2] rather than jump */
#define SQLITE_NULLEQ 0x80 /* NULL=NULL */
-#define SQLITE_NOTNULL 0x88 /* Assert that operands are never NULL */
+#define SQLITE_NOTNULL 0x90 /* Assert that operands are never NULL */
/*
** An object of this type is created for each virtual table present in
@@ -10906,34 +11499,8 @@ struct VTable {
};
/*
-** Each SQL table is represented in memory by an instance of the
-** following structure.
-**
-** Table.zName is the name of the table. The case of the original
-** CREATE TABLE statement is stored, but case is not significant for
-** comparisons.
-**
-** Table.nCol is the number of columns in this table. Table.aCol is a
-** pointer to an array of Column structures, one for each column.
-**
-** If the table has an INTEGER PRIMARY KEY, then Table.iPKey is the index of
-** the column that is that key. Otherwise Table.iPKey is negative. Note
-** that the datatype of the PRIMARY KEY must be INTEGER for this field to
-** be set. An INTEGER PRIMARY KEY is used as the rowid for each row of
-** the table. If a table has no INTEGER PRIMARY KEY, then a random rowid
-** is generated for each row of the table. TF_HasPrimaryKey is set if
-** the table has any PRIMARY KEY, INTEGER or otherwise.
-**
-** Table.tnum is the page number for the root BTree page of the table in the
-** database file. If Table.iDb is the index of the database table backend
-** in sqlite.aDb[]. 0 is for the main database and 1 is for the file that
-** holds temporary tables and indices. If TF_Ephemeral is set
-** then the table is stored in a file that is automatically deleted
-** when the VDBE cursor to the table is closed. In this case Table.tnum
-** refers VDBE cursor number that holds the table open, not to the root
-** page number. Transient tables are used to hold the results of a
-** sub-query that appears instead of a real table name in the FROM clause
-** of a SELECT statement.
+** The schema for each SQL table and view is represented in memory
+** by an instance of the following structure.
*/
struct Table {
char *zName; /* Name of the table or view */
@@ -10945,11 +11512,11 @@ struct Table {
#ifndef SQLITE_OMIT_CHECK
ExprList *pCheck; /* All CHECK constraints */
#endif
- LogEst nRowLogEst; /* Estimated rows in table - from sqlite_stat1 table */
- int tnum; /* Root BTree node for this table (see note above) */
- i16 iPKey; /* If not negative, use aCol[iPKey] as the primary key */
+ int tnum; /* Root BTree page for this table */
+ i16 iPKey; /* If not negative, use aCol[iPKey] as the rowid */
i16 nCol; /* Number of columns in this table */
u16 nRef; /* Number of pointers to this Table */
+ LogEst nRowLogEst; /* Estimated rows in table - from sqlite_stat1 table */
LogEst szTabRow; /* Estimated size of each table row in bytes */
#ifdef SQLITE_ENABLE_COSTMULT
LogEst costMult; /* Cost multiplier for using this table */
@@ -10971,6 +11538,12 @@ struct Table {
/*
** Allowed values for Table.tabFlags.
+**
+** TF_OOOHidden applies to virtual tables that have hidden columns that are
+** followed by non-hidden columns. Example: "CREATE VIRTUAL TABLE x USING
+** vtab1(a HIDDEN, b);". Since "b" is a non-hidden column but "a" is hidden,
+** the TF_OOOHidden attribute would apply in this case. Such tables require
+** special handling during INSERT processing.
*/
#define TF_Readonly 0x01 /* Read-only system table */
#define TF_Ephemeral 0x02 /* An ephemeral table */
@@ -10978,6 +11551,7 @@ struct Table {
#define TF_Autoincrement 0x08 /* Integer primary key is autoincrement */
#define TF_Virtual 0x10 /* Is a virtual table */
#define TF_WithoutRowid 0x20 /* No rowid used. PRIMARY KEY is the key */
+#define TF_OOOHidden 0x40 /* Out-of-Order hidden columns */
/*
@@ -11121,7 +11695,7 @@ struct UnpackedRecord {
KeyInfo *pKeyInfo; /* Collation and sort-order information */
u16 nField; /* Number of entries in apMem[] */
i8 default_rc; /* Comparison result if keys are equal */
- u8 isCorrupt; /* Corruption detected by xRecordCompare() */
+ u8 errCode; /* Error detected by xRecordCompare (CORRUPT or NOMEM) */
Mem *aMem; /* Values */
int r1; /* Value to return if (lhs > rhs) */
int r2; /* Value to return if (rhs < lhs) */
@@ -11165,7 +11739,6 @@ struct Index {
u8 *aSortOrder; /* for each column: True==DESC, False==ASC */
char **azColl; /* Array of collation sequence names for index */
Expr *pPartIdxWhere; /* WHERE clause for partial indices */
- KeyInfo *pKeyInfo; /* A KeyInfo object suitable for this index */
int tnum; /* DB Page containing root of this index */
LogEst szIdxRow; /* Estimated average row size in bytes */
u16 nKeyCol; /* Number of columns forming the key */
@@ -11176,11 +11749,14 @@ struct Index {
unsigned uniqNotNull:1; /* True if UNIQUE and NOT NULL for all columns */
unsigned isResized:1; /* True if resizeIndexObject() has been called */
unsigned isCovering:1; /* True if this is a covering index */
+ unsigned noSkipScan:1; /* Do not try to use skip-scan if true */
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
int nSample; /* Number of elements in aSample[] */
int nSampleCol; /* Size of IndexSample.anEq[] and so on */
tRowcnt *aAvgEq; /* Average nEq values for keys not in aSample */
IndexSample *aSample; /* Samples of the left-most key */
+ tRowcnt *aiRowEst; /* Non-logarithmic stat1 data for this index */
+ tRowcnt nRowEst0; /* Non-logarithmic number of rows in the index */
#endif
};
@@ -11378,7 +11954,7 @@ struct Expr {
int iTable; /* TK_COLUMN: cursor number of table holding column
** TK_REGISTER: register number
** TK_TRIGGER: 1 -> new, 0 -> old
- ** EP_Unlikely: 1000 times likelihood */
+ ** EP_Unlikely: 134217728 times likelihood */
ynVar iColumn; /* TK_COLUMN: column index. -1 for rowid.
** TK_VARIABLE: variable number (always >= 1). */
i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
@@ -11393,7 +11969,7 @@ struct Expr {
/*
** The following are the meanings of bits in the Expr.flags field.
*/
-#define EP_FromJoin 0x000001 /* Originated in ON or USING clause of a join */
+#define EP_FromJoin 0x000001 /* Originates in ON/USING clause of outer join */
#define EP_Agg 0x000002 /* Contains one or more aggregate functions */
#define EP_Resolved 0x000004 /* IDs have been resolved to COLUMNs */
#define EP_Error 0x000008 /* Expression contains one or more errors */
@@ -11412,7 +11988,14 @@ struct Expr {
#define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */
#define EP_NoReduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */
#define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */
-#define EP_Constant 0x080000 /* Node is a constant */
+#define EP_ConstFunc 0x080000 /* Node is a SQLITE_FUNC_CONSTANT function */
+#define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */
+#define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */
+
+/*
+** Combinations of two or more EP_* flags
+*/
+#define EP_Propagate (EP_Collate|EP_Subquery) /* Propagate these bits up tree */
/*
** These macros can be used to test, set, or clear bits in the
@@ -11611,7 +12194,7 @@ struct SrcList {
#define WHERE_OMIT_OPEN_CLOSE 0x0010 /* Table cursors are already open */
#define WHERE_FORCE_TABLE 0x0020 /* Do not use an index-only search */
#define WHERE_ONETABLE_ONLY 0x0040 /* Only code the 1st table in pTabList */
-#define WHERE_AND_ONLY 0x0080 /* Don't use indices for OR terms */
+#define WHERE_NO_AUTOINDEX 0x0080 /* Disallow automatic indexes */
#define WHERE_GROUPBY 0x0100 /* pOrderBy is really a GROUP BY */
#define WHERE_DISTINCTBY 0x0200 /* pOrderby is really a DISTINCT clause */
#define WHERE_WANT_DISTINCT 0x0400 /* All output needs to be distinct */
@@ -11654,17 +12237,22 @@ struct NameContext {
NameContext *pNext; /* Next outer name context. NULL for outermost */
int nRef; /* Number of names resolved by this context */
int nErr; /* Number of errors encountered while resolving names */
- u8 ncFlags; /* Zero or more NC_* flags defined below */
+ u16 ncFlags; /* Zero or more NC_* flags defined below */
};
/*
** Allowed values for the NameContext, ncFlags field.
+**
+** Note: NC_MinMaxAgg must have the same value as SF_MinMaxAgg and
+** SQLITE_FUNC_MINMAX.
+**
*/
-#define NC_AllowAgg 0x01 /* Aggregate functions are allowed here */
-#define NC_HasAgg 0x02 /* One or more aggregate functions seen */
-#define NC_IsCheck 0x04 /* True if resolving names in a CHECK constraint */
-#define NC_InAggFunc 0x08 /* True if analyzing arguments to an agg func */
-#define NC_PartIdx 0x10 /* True if resolving a partial index WHERE */
+#define NC_AllowAgg 0x0001 /* Aggregate functions are allowed here */
+#define NC_HasAgg 0x0002 /* One or more aggregate functions seen */
+#define NC_IsCheck 0x0004 /* True if resolving names in a CHECK constraint */
+#define NC_InAggFunc 0x0008 /* True if analyzing arguments to an agg func */
+#define NC_PartIdx 0x0010 /* True if resolving a partial index WHERE */
+#define NC_MinMaxAgg 0x1000 /* min/max aggregates seen. See note above */
/*
** An instance of the following structure contains all information
@@ -11691,6 +12279,9 @@ struct Select {
u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
u16 selFlags; /* Various SF_* values */
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
+#if SELECTTRACE_ENABLED
+ char zSelName[12]; /* Symbolic name of this SELECT use for debugging */
+#endif
int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */
u64 nSelectRow; /* Estimated number of result rows */
SrcList *pSrc; /* The FROM clause */
@@ -11715,13 +12306,14 @@ struct Select {
#define SF_UsesEphemeral 0x0008 /* Uses the OpenEphemeral opcode */
#define SF_Expanded 0x0010 /* sqlite3SelectExpand() called on this */
#define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */
- /* 0x0040 NOT USED */
+#define SF_Compound 0x0040 /* Part of a compound query */
#define SF_Values 0x0080 /* Synthesized from VALUES clause */
- /* 0x0100 NOT USED */
+#define SF_MultiValue 0x0100 /* Single VALUES term with multiple rows */
#define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */
#define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */
#define SF_Recursive 0x0800 /* The recursive part of a recursive CTE */
-#define SF_Compound 0x1000 /* Part of a compound query */
+#define SF_MinMaxAgg 0x1000 /* Aggregate containing min() or max() */
+#define SF_Converted 0x2000 /* By convertCompoundSelectToSubquery() */
/*
@@ -11949,6 +12541,10 @@ struct Parse {
int regRowid; /* Register holding rowid of CREATE TABLE entry */
int regRoot; /* Register holding root page number for new objects */
int nMaxArg; /* Max args passed to user function by sub-program */
+#if SELECTTRACE_ENABLED
+ int nSelect; /* Number of SELECT statements seen */
+ int nSelectIndent; /* How far to indent SELECTTRACE() output */
+#endif
#ifndef SQLITE_OMIT_SHARED_CACHE
int nTableLock; /* Number of locks in aTableLock */
TableLock *aTableLock; /* Required table locks for shared-cache mode */
@@ -12028,15 +12624,16 @@ struct AuthContext {
** Bitfield flags for P5 value in various opcodes.
*/
#define OPFLAG_NCHANGE 0x01 /* Set to update db->nChange */
+#define OPFLAG_EPHEM 0x01 /* OP_Column: Ephemeral output is ok */
#define OPFLAG_LASTROWID 0x02 /* Set to update db->lastRowid */
#define OPFLAG_ISUPDATE 0x04 /* This OP_Insert is an sql UPDATE */
#define OPFLAG_APPEND 0x08 /* This is likely to be an append */
#define OPFLAG_USESEEKRESULT 0x10 /* Try to avoid a seek in BtreeInsert() */
-#define OPFLAG_CLEARCACHE 0x20 /* Clear pseudo-table cache in OP_Column */
#define OPFLAG_LENGTHARG 0x40 /* OP_Column only used for length() */
#define OPFLAG_TYPEOFARG 0x80 /* OP_Column only used for typeof() */
#define OPFLAG_BULKCSR 0x01 /* OP_Open** used to open bulk cursor */
-#define OPFLAG_P2ISREG 0x02 /* P2 to OP_Open** is a register number */
+#define OPFLAG_SEEKEQ 0x02 /* OP_Open** cursor uses EQ seek only */
+#define OPFLAG_P2ISREG 0x04 /* P2 to OP_Open** is a register number */
#define OPFLAG_PERMUTE 0x01 /* OP_Compare: use the permutation */
/*
@@ -12095,7 +12692,7 @@ struct Trigger {
* orconf -> stores the ON CONFLICT algorithm
* pSelect -> If this is an INSERT INTO ... SELECT ... statement, then
* this stores a pointer to the SELECT statement. Otherwise NULL.
- * target -> A token holding the quoted name of the table to insert into.
+ * zTarget -> Dequoted name of the table to insert into.
* pExprList -> If this is an INSERT INTO ... VALUES ... statement, then
* this stores values to be inserted. Otherwise NULL.
* pIdList -> If this is an INSERT INTO ... (<column-names>) VALUES ...
@@ -12103,12 +12700,12 @@ struct Trigger {
* inserted into.
*
* (op == TK_DELETE)
- * target -> A token holding the quoted name of the table to delete from.
+ * zTarget -> Dequoted name of the table to delete from.
* pWhere -> The WHERE clause of the DELETE statement if one is specified.
* Otherwise NULL.
*
* (op == TK_UPDATE)
- * target -> A token holding the quoted name of the table to update rows of.
+ * zTarget -> Dequoted name of the table to update.
* pWhere -> The WHERE clause of the UPDATE statement if one is specified.
* Otherwise NULL.
* pExprList -> A list of the columns to update and the expressions to update
@@ -12120,8 +12717,8 @@ struct TriggerStep {
u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT, TK_SELECT */
u8 orconf; /* OE_Rollback etc. */
Trigger *pTrig; /* The trigger that this step is a part of */
- Select *pSelect; /* SELECT statment or RHS of INSERT INTO .. SELECT ... */
- Token target; /* Target table for DELETE, UPDATE, INSERT */
+ Select *pSelect; /* SELECT statement or RHS of INSERT INTO SELECT ... */
+ char *zTarget; /* Target table for DELETE, UPDATE, INSERT */
Expr *pWhere; /* The WHERE clause for DELETE or UPDATE steps */
ExprList *pExprList; /* SET clause for UPDATE. */
IdList *pIdList; /* Column names for INSERT */
@@ -12154,8 +12751,7 @@ struct StrAccum {
char *zText; /* The string collected so far */
int nChar; /* Length of the string so far */
int nAlloc; /* Amount of space allocated in zText */
- int mxAlloc; /* Maximum allowed string length */
- u8 useMalloc; /* 0: none, 1: sqlite3DbMalloc, 2: sqlite3_malloc */
+ int mxAlloc; /* Maximum allowed allocation. 0 for no malloc usage */
u8 accError; /* STRACCUM_NOMEM or STRACCUM_TOOBIG */
};
#define STRACCUM_NOMEM 1
@@ -12203,6 +12799,7 @@ struct Sqlite3Config {
int nPage; /* Number of pages in pPage[] */
int mxParserStack; /* maximum depth of the parser stack */
int sharedCacheEnabled; /* true if shared-cache mode enabled */
+ u32 szPma; /* Maximum Sorter PMA size */
/* The above might be initialized to non-zero. The following need to always
** initially be zero, however. */
int isInit; /* True after initialization has finished */
@@ -12258,9 +12855,11 @@ struct Walker {
void (*xSelectCallback2)(Walker*,Select*);/* Second callback for SELECTs */
Parse *pParse; /* Parser context. */
int walkerDepth; /* Number of subqueries */
+ u8 eCode; /* A small processing code */
union { /* Extra data for callback */
NameContext *pNC; /* Naming context */
- int i; /* Integer value */
+ int n; /* A counter */
+ int iCur; /* A cursor number */
SrcList *pSrcList; /* FROM clause */
struct SrcCount *pSrcCount; /* Counting column references */
} u;
@@ -12296,6 +12895,17 @@ struct With {
} a[1];
};
+#ifdef SQLITE_DEBUG
+/*
+** An instance of the TreeView object is used for printing the content of
+** data structures on sqlite3DebugPrintf() using a tree-like view.
+*/
+struct TreeView {
+ int iLevel; /* Which level of the tree we are on */
+ u8 bLine[100]; /* Draw vertical in column i if bLine[i] is true */
+};
+#endif /* SQLITE_DEBUG */
+
/*
** Assuming zIn points to the first byte of a UTF-8 character,
** advance zIn to point to the first byte of the next UTF-8 character.
@@ -12323,11 +12933,11 @@ SQLITE_PRIVATE int sqlite3CantopenError(int);
/*
** FTS4 is really an extension for FTS3. It is enabled using the
-** SQLITE_ENABLE_FTS3 macro. But to avoid confusion we also all
-** the SQLITE_ENABLE_FTS4 macro to serve as an alisse for SQLITE_ENABLE_FTS3.
+** SQLITE_ENABLE_FTS3 macro. But to avoid confusion we also call
+** the SQLITE_ENABLE_FTS4 macro to serve as an alias for SQLITE_ENABLE_FTS3.
*/
#if defined(SQLITE_ENABLE_FTS4) && !defined(SQLITE_ENABLE_FTS3)
-# define SQLITE_ENABLE_FTS3
+# define SQLITE_ENABLE_FTS3 1
#endif
/*
@@ -12361,6 +12971,7 @@ SQLITE_PRIVATE int sqlite3CantopenError(int);
# define sqlite3Isxdigit(x) isxdigit((unsigned char)(x))
# define sqlite3Tolower(x) tolower((unsigned char)(x))
#endif
+SQLITE_PRIVATE int sqlite3IsIdChar(u8);
/*
** Internal function prototypes
@@ -12371,15 +12982,15 @@ SQLITE_PRIVATE int sqlite3Strlen30(const char*);
SQLITE_PRIVATE int sqlite3MallocInit(void);
SQLITE_PRIVATE void sqlite3MallocEnd(void);
-SQLITE_PRIVATE void *sqlite3Malloc(int);
-SQLITE_PRIVATE void *sqlite3MallocZero(int);
-SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3*, int);
-SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3*, int);
+SQLITE_PRIVATE void *sqlite3Malloc(u64);
+SQLITE_PRIVATE void *sqlite3MallocZero(u64);
+SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3*, u64);
+SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3*, u64);
SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3*,const char*);
-SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3*,const char*, int);
-SQLITE_PRIVATE void *sqlite3Realloc(void*, int);
-SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *, void *, int);
-SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *, void *, int);
+SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3*,const char*, u64);
+SQLITE_PRIVATE void *sqlite3Realloc(void*, u64);
+SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *, void *, u64);
+SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *, void *, u64);
SQLITE_PRIVATE void sqlite3DbFree(sqlite3*, void*);
SQLITE_PRIVATE int sqlite3MallocSize(void*);
SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3*, void*);
@@ -12425,10 +13036,15 @@ SQLITE_PRIVATE int sqlite3MutexInit(void);
SQLITE_PRIVATE int sqlite3MutexEnd(void);
#endif
-SQLITE_PRIVATE int sqlite3StatusValue(int);
-SQLITE_PRIVATE void sqlite3StatusAdd(int, int);
+SQLITE_PRIVATE sqlite3_int64 sqlite3StatusValue(int);
+SQLITE_PRIVATE void sqlite3StatusUp(int, int);
+SQLITE_PRIVATE void sqlite3StatusDown(int, int);
SQLITE_PRIVATE void sqlite3StatusSet(int, int);
+/* Access to mutexes used by sqlite3_status() */
+SQLITE_PRIVATE sqlite3_mutex *sqlite3Pcache1Mutex(void);
+SQLITE_PRIVATE sqlite3_mutex *sqlite3MallocMutex(void);
+
#ifndef SQLITE_OMIT_FLOATING_POINT
SQLITE_PRIVATE int sqlite3IsNaN(double);
#else
@@ -12452,32 +13068,21 @@ SQLITE_PRIVATE void sqlite3XPrintf(StrAccum*, u32, const char*, ...);
SQLITE_PRIVATE char *sqlite3MPrintf(sqlite3*,const char*, ...);
SQLITE_PRIVATE char *sqlite3VMPrintf(sqlite3*,const char*, va_list);
SQLITE_PRIVATE char *sqlite3MAppendf(sqlite3*,char*,const char*,...);
-#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
+#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
SQLITE_PRIVATE void sqlite3DebugPrintf(const char*, ...);
#endif
#if defined(SQLITE_TEST)
SQLITE_PRIVATE void *sqlite3TestTextToPtr(const char*);
#endif
-/* Output formatting for SQLITE_TESTCTRL_EXPLAIN */
-#if defined(SQLITE_ENABLE_TREE_EXPLAIN)
-SQLITE_PRIVATE void sqlite3ExplainBegin(Vdbe*);
-SQLITE_PRIVATE void sqlite3ExplainPrintf(Vdbe*, const char*, ...);
-SQLITE_PRIVATE void sqlite3ExplainNL(Vdbe*);
-SQLITE_PRIVATE void sqlite3ExplainPush(Vdbe*);
-SQLITE_PRIVATE void sqlite3ExplainPop(Vdbe*);
-SQLITE_PRIVATE void sqlite3ExplainFinish(Vdbe*);
-SQLITE_PRIVATE void sqlite3ExplainSelect(Vdbe*, Select*);
-SQLITE_PRIVATE void sqlite3ExplainExpr(Vdbe*, Expr*);
-SQLITE_PRIVATE void sqlite3ExplainExprList(Vdbe*, ExprList*);
-SQLITE_PRIVATE const char *sqlite3VdbeExplanation(Vdbe*);
-#else
-# define sqlite3ExplainBegin(X)
-# define sqlite3ExplainSelect(A,B)
-# define sqlite3ExplainExpr(A,B)
-# define sqlite3ExplainExprList(A,B)
-# define sqlite3ExplainFinish(X)
-# define sqlite3VdbeExplanation(X) 0
+#if defined(SQLITE_DEBUG)
+SQLITE_PRIVATE TreeView *sqlite3TreeViewPush(TreeView*,u8);
+SQLITE_PRIVATE void sqlite3TreeViewPop(TreeView*);
+SQLITE_PRIVATE void sqlite3TreeViewLine(TreeView*, const char*, ...);
+SQLITE_PRIVATE void sqlite3TreeViewItem(TreeView*, const char*, u8);
+SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView*, const Expr*, u8);
+SQLITE_PRIVATE void sqlite3TreeViewExprList(TreeView*, const ExprList*, u8, const char*);
+SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView*, const Select*, u8);
#endif
@@ -12504,6 +13109,7 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*);
SQLITE_PRIVATE void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int);
SQLITE_PRIVATE void sqlite3ExprListSetSpan(Parse*,ExprList*,ExprSpan*);
SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3*, ExprList*);
+SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList*);
SQLITE_PRIVATE int sqlite3Init(sqlite3*, char**);
SQLITE_PRIVATE int sqlite3InitCallback(void*, int, char**, char**);
SQLITE_PRIVATE void sqlite3Pragma(Parse*,Token*,Token*,Token*,int);
@@ -12659,7 +13265,8 @@ SQLITE_PRIVATE void sqlite3CloseSavepoints(sqlite3 *);
SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3*);
SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr*);
SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr*);
-SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr*);
+SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr*, u8);
+SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr*,int);
SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr*, int*);
SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr*);
SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
@@ -12683,6 +13290,11 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int);
SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int);
SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3*,IdList*);
SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3*,Select*,int);
+#if SELECTTRACE_ENABLED
+SQLITE_PRIVATE void sqlite3SelectSetName(Select*,const char*);
+#else
+# define sqlite3SelectSetName(A,B)
+#endif
SQLITE_PRIVATE void sqlite3FuncDefInsert(FuncDefHash*, FuncDef*);
SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,int,u8,u8);
SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(sqlite3*);
@@ -12769,38 +13381,23 @@ SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst);
/*
** Routines to read and write variable-length integers. These used to
** be defined locally, but now we use the varint routines in the util.c
-** file. Code should use the MACRO forms below, as the Varint32 versions
-** are coded to assume the single byte case is already handled (which
-** the MACRO form does).
+** file.
*/
SQLITE_PRIVATE int sqlite3PutVarint(unsigned char*, u64);
-SQLITE_PRIVATE int sqlite3PutVarint32(unsigned char*, u32);
SQLITE_PRIVATE u8 sqlite3GetVarint(const unsigned char *, u64 *);
SQLITE_PRIVATE u8 sqlite3GetVarint32(const unsigned char *, u32 *);
SQLITE_PRIVATE int sqlite3VarintLen(u64 v);
/*
-** The header of a record consists of a sequence variable-length integers.
-** These integers are almost always small and are encoded as a single byte.
-** The following macros take advantage this fact to provide a fast encode
-** and decode of the integers in a record header. It is faster for the common
-** case where the integer is a single byte. It is a little slower when the
-** integer is two or more bytes. But overall it is faster.
-**
-** The following expressions are equivalent:
-**
-** x = sqlite3GetVarint32( A, &B );
-** x = sqlite3PutVarint32( A, B );
-**
-** x = getVarint32( A, B );
-** x = putVarint32( A, B );
-**
+** The common case is for a varint to be a single byte. They following
+** macros handle the common case without a procedure call, but then call
+** the procedure for larger varints.
*/
#define getVarint32(A,B) \
(u8)((*(A)<(u8)0x80)?((B)=(u32)*(A)),1:sqlite3GetVarint32((A),(u32 *)&(B)))
#define putVarint32(A,B) \
(u8)(((u32)(B)<(u32)0x80)?(*(A)=(unsigned char)(B)),1:\
- sqlite3PutVarint32((A),(B)))
+ sqlite3PutVarint((A),(B)))
#define getVarint sqlite3GetVarint
#define putVarint sqlite3PutVarint
@@ -12812,12 +13409,13 @@ SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity);
SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr);
SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8);
SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char*, i64*);
-SQLITE_PRIVATE void sqlite3Error(sqlite3*, int, const char*,...);
+SQLITE_PRIVATE void sqlite3ErrorWithMsg(sqlite3*, int, const char*,...);
+SQLITE_PRIVATE void sqlite3Error(sqlite3*,int);
SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n);
SQLITE_PRIVATE u8 sqlite3HexToInt(int h);
SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **);
-#if defined(SQLITE_TEST)
+#if defined(SQLITE_NEED_ERR_NAME)
SQLITE_PRIVATE const char *sqlite3ErrName(int);
#endif
@@ -12826,7 +13424,7 @@ SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse);
SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int);
SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName);
SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr);
-SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*);
+SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*, int);
SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*);
SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr*);
SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *, CollSeq *);
@@ -12911,10 +13509,10 @@ SQLITE_PRIVATE int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *,
SQLITE_PRIVATE int sqlite3ApiExit(sqlite3 *db, int);
SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *);
-SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum*, char*, int, int);
+SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int);
SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum*,const char*,int);
SQLITE_PRIVATE void sqlite3StrAccumAppendAll(StrAccum*,const char*);
-SQLITE_PRIVATE void sqlite3AppendSpace(StrAccum*,int);
+SQLITE_PRIVATE void sqlite3AppendChar(StrAccum*,int,char);
SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum*);
SQLITE_PRIVATE void sqlite3StrAccumReset(StrAccum*);
SQLITE_PRIVATE void sqlite3SelectDestInit(SelectDest*,int,int);
@@ -12934,7 +13532,7 @@ SQLITE_PRIVATE int sqlite3Stat4Column(sqlite3*, const void*, int, int, sqlite3_v
/*
** The interface to the LEMON-generated parser
*/
-SQLITE_PRIVATE void *sqlite3ParserAlloc(void*(*)(size_t));
+SQLITE_PRIVATE void *sqlite3ParserAlloc(void*(*)(u64));
SQLITE_PRIVATE void sqlite3ParserFree(void*, void(*)(void*));
SQLITE_PRIVATE void sqlite3Parser(void*, int, Token, Parse*);
#ifdef YYTRACKMAXSTACKDEPTH
@@ -13095,12 +13693,11 @@ SQLITE_PRIVATE void sqlite3MemJournalOpen(sqlite3_file *);
SQLITE_PRIVATE int sqlite3MemJournalSize(void);
SQLITE_PRIVATE int sqlite3IsMemJournal(sqlite3_file *);
+SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p);
#if SQLITE_MAX_EXPR_DEPTH>0
-SQLITE_PRIVATE void sqlite3ExprSetHeight(Parse *pParse, Expr *p);
SQLITE_PRIVATE int sqlite3SelectExprHeight(Select *);
SQLITE_PRIVATE int sqlite3ExprCheckHeight(Parse*, int);
#else
- #define sqlite3ExprSetHeight(x,y)
#define sqlite3SelectExprHeight(x) 0
#define sqlite3ExprCheckHeight(x,y)
#endif
@@ -13130,7 +13727,7 @@ SQLITE_PRIVATE void sqlite3ParserTrace(FILE*, char *);
#ifdef SQLITE_ENABLE_IOTRACE
# define IOTRACE(A) if( sqlite3IoTrace ){ sqlite3IoTrace A; }
SQLITE_PRIVATE void sqlite3VdbeIOTraceSql(Vdbe*);
-SQLITE_PRIVATE void (*sqlite3IoTrace)(const char*,...);
+SQLITE_API SQLITE_EXTERN void (SQLITE_CDECL *sqlite3IoTrace)(const char*,...);
#else
# define IOTRACE(A)
# define sqlite3VdbeIOTraceSql(X)
@@ -13174,10 +13771,17 @@ SQLITE_PRIVATE int sqlite3MemdebugNoType(void*,u8);
# define sqlite3MemdebugNoType(X,Y) 1
#endif
#define MEMTYPE_HEAP 0x01 /* General heap allocations */
-#define MEMTYPE_LOOKASIDE 0x02 /* Might have been lookaside memory */
+#define MEMTYPE_LOOKASIDE 0x02 /* Heap that might have been lookaside */
#define MEMTYPE_SCRATCH 0x04 /* Scratch allocations */
#define MEMTYPE_PCACHE 0x08 /* Page cache allocations */
-#define MEMTYPE_DB 0x10 /* Uses sqlite3DbMalloc, not sqlite_malloc */
+
+/*
+** Threading interface
+*/
+#if SQLITE_MAX_WORKER_THREADS>0
+SQLITE_PRIVATE int sqlite3ThreadCreate(SQLiteThread**,void*(*)(void*),void*);
+SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread*, void**);
+#endif
#endif /* _SQLITEINT_H_ */
@@ -13195,7 +13799,7 @@ SQLITE_PRIVATE int sqlite3MemdebugNoType(void*,u8);
**
*************************************************************************
**
-** This file contains definitions of global variables and contants.
+** This file contains definitions of global variables and constants.
*/
/* An array to map all upper-case characters into their corresponding
@@ -13230,16 +13834,16 @@ SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[] = {
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 3x */
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, /* 4x */
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, /* 5x */
- 96, 97, 66, 67, 68, 69, 70, 71, 72, 73,106,107,108,109,110,111, /* 6x */
- 112, 81, 82, 83, 84, 85, 86, 87, 88, 89,122,123,124,125,126,127, /* 7x */
+ 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, /* 6x */
+ 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, /* 7x */
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, /* 8x */
- 144,145,146,147,148,149,150,151,152,153,154,155,156,157,156,159, /* 9x */
+ 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, /* 9x */
160,161,162,163,164,165,166,167,168,169,170,171,140,141,142,175, /* Ax */
176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, /* Bx */
192,129,130,131,132,133,134,135,136,137,202,203,204,205,206,207, /* Cx */
208,145,146,147,148,149,150,151,152,153,218,219,220,221,222,223, /* Dx */
- 224,225,162,163,164,165,166,167,168,169,232,203,204,205,206,207, /* Ex */
- 239,240,241,242,243,244,245,246,247,248,249,219,220,221,222,255, /* Fx */
+ 224,225,162,163,164,165,166,167,168,169,234,235,236,237,238,239, /* Ex */
+ 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, /* Fx */
#endif
};
@@ -13313,14 +13917,36 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
};
#endif
+/* EVIDENCE-OF: R-02982-34736 In order to maintain full backwards
+** compatibility for legacy applications, the URI filename capability is
+** disabled by default.
+**
+** EVIDENCE-OF: R-38799-08373 URI filenames can be enabled or disabled
+** using the SQLITE_USE_URI=1 or SQLITE_USE_URI=0 compile-time options.
+**
+** EVIDENCE-OF: R-43642-56306 By default, URI handling is globally
+** disabled. The default value may be changed by compiling with the
+** SQLITE_USE_URI symbol defined.
+*/
#ifndef SQLITE_USE_URI
# define SQLITE_USE_URI 0
#endif
+/* EVIDENCE-OF: R-38720-18127 The default setting is determined by the
+** SQLITE_ALLOW_COVERING_INDEX_SCAN compile-time option, or is "on" if
+** that compile-time option is omitted.
+*/
#ifndef SQLITE_ALLOW_COVERING_INDEX_SCAN
# define SQLITE_ALLOW_COVERING_INDEX_SCAN 1
#endif
+/* The minimum PMA size is set to this value multiplied by the database
+** page size in bytes.
+*/
+#ifndef SQLITE_SORTER_PMASZ
+# define SQLITE_SORTER_PMASZ 250
+#endif
+
/*
** The following singleton contains the global configuration for
** the SQLite library.
@@ -13351,6 +13977,7 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
0, /* nPage */
0, /* mxParserStack */
0, /* sharedCacheEnabled */
+ SQLITE_SORTER_PMASZ, /* szPma */
/* All the rest should always be initialized to zero */
0, /* isInit */
0, /* inProgress */
@@ -13406,8 +14033,8 @@ SQLITE_PRIVATE const Token sqlite3IntTokens[] = {
**
** IMPORTANT: Changing the pending byte to any value other than
** 0x40000000 results in an incompatible database file format!
-** Changing the pending byte during operating results in undefined
-** and dileterious behavior.
+** Changing the pending byte during operation will result in undefined
+** and incorrect behavior.
*/
#ifndef SQLITE_OMIT_WSD
SQLITE_PRIVATE int sqlite3PendingByte = 0x40000000;
@@ -13457,88 +14084,94 @@ static const char * const azCompileOpt[] = {
#define CTIMEOPT_VAL_(opt) #opt
#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
-#ifdef SQLITE_32BIT_ROWID
+#if SQLITE_32BIT_ROWID
"32BIT_ROWID",
#endif
-#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC
+#if SQLITE_4_BYTE_ALIGNED_MALLOC
"4_BYTE_ALIGNED_MALLOC",
#endif
-#ifdef SQLITE_CASE_SENSITIVE_LIKE
+#if SQLITE_CASE_SENSITIVE_LIKE
"CASE_SENSITIVE_LIKE",
#endif
-#ifdef SQLITE_CHECK_PAGES
+#if SQLITE_CHECK_PAGES
"CHECK_PAGES",
#endif
-#ifdef SQLITE_COVERAGE_TEST
+#if SQLITE_COVERAGE_TEST
"COVERAGE_TEST",
#endif
-#ifdef SQLITE_DEBUG
+#if SQLITE_DEBUG
"DEBUG",
#endif
-#ifdef SQLITE_DEFAULT_LOCKING_MODE
+#if SQLITE_DEFAULT_LOCKING_MODE
"DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE),
#endif
#if defined(SQLITE_DEFAULT_MMAP_SIZE) && !defined(SQLITE_DEFAULT_MMAP_SIZE_xc)
"DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE),
#endif
-#ifdef SQLITE_DISABLE_DIRSYNC
+#if SQLITE_DISABLE_DIRSYNC
"DISABLE_DIRSYNC",
#endif
-#ifdef SQLITE_DISABLE_LFS
+#if SQLITE_DISABLE_LFS
"DISABLE_LFS",
#endif
-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+#if SQLITE_ENABLE_API_ARMOR
+ "ENABLE_API_ARMOR",
+#endif
+#if SQLITE_ENABLE_ATOMIC_WRITE
"ENABLE_ATOMIC_WRITE",
#endif
-#ifdef SQLITE_ENABLE_CEROD
+#if SQLITE_ENABLE_CEROD
"ENABLE_CEROD",
#endif
-#ifdef SQLITE_ENABLE_COLUMN_METADATA
+#if SQLITE_ENABLE_COLUMN_METADATA
"ENABLE_COLUMN_METADATA",
#endif
-#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
+#if SQLITE_ENABLE_DBSTAT_VTAB
+ "ENABLE_DBSTAT_VTAB",
+#endif
+#if SQLITE_ENABLE_EXPENSIVE_ASSERT
"ENABLE_EXPENSIVE_ASSERT",
#endif
-#ifdef SQLITE_ENABLE_FTS1
+#if SQLITE_ENABLE_FTS1
"ENABLE_FTS1",
#endif
-#ifdef SQLITE_ENABLE_FTS2
+#if SQLITE_ENABLE_FTS2
"ENABLE_FTS2",
#endif
-#ifdef SQLITE_ENABLE_FTS3
+#if SQLITE_ENABLE_FTS3
"ENABLE_FTS3",
#endif
-#ifdef SQLITE_ENABLE_FTS3_PARENTHESIS
+#if SQLITE_ENABLE_FTS3_PARENTHESIS
"ENABLE_FTS3_PARENTHESIS",
#endif
-#ifdef SQLITE_ENABLE_FTS4
+#if SQLITE_ENABLE_FTS4
"ENABLE_FTS4",
#endif
-#ifdef SQLITE_ENABLE_ICU
+#if SQLITE_ENABLE_ICU
"ENABLE_ICU",
#endif
-#ifdef SQLITE_ENABLE_IOTRACE
+#if SQLITE_ENABLE_IOTRACE
"ENABLE_IOTRACE",
#endif
-#ifdef SQLITE_ENABLE_LOAD_EXTENSION
+#if SQLITE_ENABLE_LOAD_EXTENSION
"ENABLE_LOAD_EXTENSION",
#endif
-#ifdef SQLITE_ENABLE_LOCKING_STYLE
+#if SQLITE_ENABLE_LOCKING_STYLE
"ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE),
#endif
-#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+#if SQLITE_ENABLE_MEMORY_MANAGEMENT
"ENABLE_MEMORY_MANAGEMENT",
#endif
-#ifdef SQLITE_ENABLE_MEMSYS3
+#if SQLITE_ENABLE_MEMSYS3
"ENABLE_MEMSYS3",
#endif
-#ifdef SQLITE_ENABLE_MEMSYS5
+#if SQLITE_ENABLE_MEMSYS5
"ENABLE_MEMSYS5",
#endif
-#ifdef SQLITE_ENABLE_OVERSIZE_CELL_CHECK
+#if SQLITE_ENABLE_OVERSIZE_CELL_CHECK
"ENABLE_OVERSIZE_CELL_CHECK",
#endif
-#ifdef SQLITE_ENABLE_RTREE
+#if SQLITE_ENABLE_RTREE
"ENABLE_RTREE",
#endif
#if defined(SQLITE_ENABLE_STAT4)
@@ -13546,31 +14179,31 @@ static const char * const azCompileOpt[] = {
#elif defined(SQLITE_ENABLE_STAT3)
"ENABLE_STAT3",
#endif
-#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
+#if SQLITE_ENABLE_UNLOCK_NOTIFY
"ENABLE_UNLOCK_NOTIFY",
#endif
-#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
+#if SQLITE_ENABLE_UPDATE_DELETE_LIMIT
"ENABLE_UPDATE_DELETE_LIMIT",
#endif
-#ifdef SQLITE_HAS_CODEC
+#if SQLITE_HAS_CODEC
"HAS_CODEC",
#endif
-#ifdef SQLITE_HAVE_ISNAN
+#if HAVE_ISNAN || SQLITE_HAVE_ISNAN
"HAVE_ISNAN",
#endif
-#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
+#if SQLITE_HOMEGROWN_RECURSIVE_MUTEX
"HOMEGROWN_RECURSIVE_MUTEX",
#endif
-#ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS
+#if SQLITE_IGNORE_AFP_LOCK_ERRORS
"IGNORE_AFP_LOCK_ERRORS",
#endif
-#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
+#if SQLITE_IGNORE_FLOCK_LOCK_ERRORS
"IGNORE_FLOCK_LOCK_ERRORS",
#endif
#ifdef SQLITE_INT64_TYPE
"INT64_TYPE",
#endif
-#ifdef SQLITE_LOCK_TRACE
+#if SQLITE_LOCK_TRACE
"LOCK_TRACE",
#endif
#if defined(SQLITE_MAX_MMAP_SIZE) && !defined(SQLITE_MAX_MMAP_SIZE_xc)
@@ -13579,223 +14212,226 @@ static const char * const azCompileOpt[] = {
#ifdef SQLITE_MAX_SCHEMA_RETRY
"MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY),
#endif
-#ifdef SQLITE_MEMDEBUG
+#if SQLITE_MEMDEBUG
"MEMDEBUG",
#endif
-#ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT
+#if SQLITE_MIXED_ENDIAN_64BIT_FLOAT
"MIXED_ENDIAN_64BIT_FLOAT",
#endif
-#ifdef SQLITE_NO_SYNC
+#if SQLITE_NO_SYNC
"NO_SYNC",
#endif
-#ifdef SQLITE_OMIT_ALTERTABLE
+#if SQLITE_OMIT_ALTERTABLE
"OMIT_ALTERTABLE",
#endif
-#ifdef SQLITE_OMIT_ANALYZE
+#if SQLITE_OMIT_ANALYZE
"OMIT_ANALYZE",
#endif
-#ifdef SQLITE_OMIT_ATTACH
+#if SQLITE_OMIT_ATTACH
"OMIT_ATTACH",
#endif
-#ifdef SQLITE_OMIT_AUTHORIZATION
+#if SQLITE_OMIT_AUTHORIZATION
"OMIT_AUTHORIZATION",
#endif
-#ifdef SQLITE_OMIT_AUTOINCREMENT
+#if SQLITE_OMIT_AUTOINCREMENT
"OMIT_AUTOINCREMENT",
#endif
-#ifdef SQLITE_OMIT_AUTOINIT
+#if SQLITE_OMIT_AUTOINIT
"OMIT_AUTOINIT",
#endif
-#ifdef SQLITE_OMIT_AUTOMATIC_INDEX
+#if SQLITE_OMIT_AUTOMATIC_INDEX
"OMIT_AUTOMATIC_INDEX",
#endif
-#ifdef SQLITE_OMIT_AUTORESET
+#if SQLITE_OMIT_AUTORESET
"OMIT_AUTORESET",
#endif
-#ifdef SQLITE_OMIT_AUTOVACUUM
+#if SQLITE_OMIT_AUTOVACUUM
"OMIT_AUTOVACUUM",
#endif
-#ifdef SQLITE_OMIT_BETWEEN_OPTIMIZATION
+#if SQLITE_OMIT_BETWEEN_OPTIMIZATION
"OMIT_BETWEEN_OPTIMIZATION",
#endif
-#ifdef SQLITE_OMIT_BLOB_LITERAL
+#if SQLITE_OMIT_BLOB_LITERAL
"OMIT_BLOB_LITERAL",
#endif
-#ifdef SQLITE_OMIT_BTREECOUNT
+#if SQLITE_OMIT_BTREECOUNT
"OMIT_BTREECOUNT",
#endif
-#ifdef SQLITE_OMIT_BUILTIN_TEST
+#if SQLITE_OMIT_BUILTIN_TEST
"OMIT_BUILTIN_TEST",
#endif
-#ifdef SQLITE_OMIT_CAST
+#if SQLITE_OMIT_CAST
"OMIT_CAST",
#endif
-#ifdef SQLITE_OMIT_CHECK
+#if SQLITE_OMIT_CHECK
"OMIT_CHECK",
#endif
-#ifdef SQLITE_OMIT_COMPLETE
+#if SQLITE_OMIT_COMPLETE
"OMIT_COMPLETE",
#endif
-#ifdef SQLITE_OMIT_COMPOUND_SELECT
+#if SQLITE_OMIT_COMPOUND_SELECT
"OMIT_COMPOUND_SELECT",
#endif
-#ifdef SQLITE_OMIT_CTE
+#if SQLITE_OMIT_CTE
"OMIT_CTE",
#endif
-#ifdef SQLITE_OMIT_DATETIME_FUNCS
+#if SQLITE_OMIT_DATETIME_FUNCS
"OMIT_DATETIME_FUNCS",
#endif
-#ifdef SQLITE_OMIT_DECLTYPE
+#if SQLITE_OMIT_DECLTYPE
"OMIT_DECLTYPE",
#endif
-#ifdef SQLITE_OMIT_DEPRECATED
+#if SQLITE_OMIT_DEPRECATED
"OMIT_DEPRECATED",
#endif
-#ifdef SQLITE_OMIT_DISKIO
+#if SQLITE_OMIT_DISKIO
"OMIT_DISKIO",
#endif
-#ifdef SQLITE_OMIT_EXPLAIN
+#if SQLITE_OMIT_EXPLAIN
"OMIT_EXPLAIN",
#endif
-#ifdef SQLITE_OMIT_FLAG_PRAGMAS
+#if SQLITE_OMIT_FLAG_PRAGMAS
"OMIT_FLAG_PRAGMAS",
#endif
-#ifdef SQLITE_OMIT_FLOATING_POINT
+#if SQLITE_OMIT_FLOATING_POINT
"OMIT_FLOATING_POINT",
#endif
-#ifdef SQLITE_OMIT_FOREIGN_KEY
+#if SQLITE_OMIT_FOREIGN_KEY
"OMIT_FOREIGN_KEY",
#endif
-#ifdef SQLITE_OMIT_GET_TABLE
+#if SQLITE_OMIT_GET_TABLE
"OMIT_GET_TABLE",
#endif
-#ifdef SQLITE_OMIT_INCRBLOB
+#if SQLITE_OMIT_INCRBLOB
"OMIT_INCRBLOB",
#endif
-#ifdef SQLITE_OMIT_INTEGRITY_CHECK
+#if SQLITE_OMIT_INTEGRITY_CHECK
"OMIT_INTEGRITY_CHECK",
#endif
-#ifdef SQLITE_OMIT_LIKE_OPTIMIZATION
+#if SQLITE_OMIT_LIKE_OPTIMIZATION
"OMIT_LIKE_OPTIMIZATION",
#endif
-#ifdef SQLITE_OMIT_LOAD_EXTENSION
+#if SQLITE_OMIT_LOAD_EXTENSION
"OMIT_LOAD_EXTENSION",
#endif
-#ifdef SQLITE_OMIT_LOCALTIME
+#if SQLITE_OMIT_LOCALTIME
"OMIT_LOCALTIME",
#endif
-#ifdef SQLITE_OMIT_LOOKASIDE
+#if SQLITE_OMIT_LOOKASIDE
"OMIT_LOOKASIDE",
#endif
-#ifdef SQLITE_OMIT_MEMORYDB
+#if SQLITE_OMIT_MEMORYDB
"OMIT_MEMORYDB",
#endif
-#ifdef SQLITE_OMIT_OR_OPTIMIZATION
+#if SQLITE_OMIT_OR_OPTIMIZATION
"OMIT_OR_OPTIMIZATION",
#endif
-#ifdef SQLITE_OMIT_PAGER_PRAGMAS
+#if SQLITE_OMIT_PAGER_PRAGMAS
"OMIT_PAGER_PRAGMAS",
#endif
-#ifdef SQLITE_OMIT_PRAGMA
+#if SQLITE_OMIT_PRAGMA
"OMIT_PRAGMA",
#endif
-#ifdef SQLITE_OMIT_PROGRESS_CALLBACK
+#if SQLITE_OMIT_PROGRESS_CALLBACK
"OMIT_PROGRESS_CALLBACK",
#endif
-#ifdef SQLITE_OMIT_QUICKBALANCE
+#if SQLITE_OMIT_QUICKBALANCE
"OMIT_QUICKBALANCE",
#endif
-#ifdef SQLITE_OMIT_REINDEX
+#if SQLITE_OMIT_REINDEX
"OMIT_REINDEX",
#endif
-#ifdef SQLITE_OMIT_SCHEMA_PRAGMAS
+#if SQLITE_OMIT_SCHEMA_PRAGMAS
"OMIT_SCHEMA_PRAGMAS",
#endif
-#ifdef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
+#if SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
"OMIT_SCHEMA_VERSION_PRAGMAS",
#endif
-#ifdef SQLITE_OMIT_SHARED_CACHE
+#if SQLITE_OMIT_SHARED_CACHE
"OMIT_SHARED_CACHE",
#endif
-#ifdef SQLITE_OMIT_SUBQUERY
+#if SQLITE_OMIT_SUBQUERY
"OMIT_SUBQUERY",
#endif
-#ifdef SQLITE_OMIT_TCL_VARIABLE
+#if SQLITE_OMIT_TCL_VARIABLE
"OMIT_TCL_VARIABLE",
#endif
-#ifdef SQLITE_OMIT_TEMPDB
+#if SQLITE_OMIT_TEMPDB
"OMIT_TEMPDB",
#endif
-#ifdef SQLITE_OMIT_TRACE
+#if SQLITE_OMIT_TRACE
"OMIT_TRACE",
#endif
-#ifdef SQLITE_OMIT_TRIGGER
+#if SQLITE_OMIT_TRIGGER
"OMIT_TRIGGER",
#endif
-#ifdef SQLITE_OMIT_TRUNCATE_OPTIMIZATION
+#if SQLITE_OMIT_TRUNCATE_OPTIMIZATION
"OMIT_TRUNCATE_OPTIMIZATION",
#endif
-#ifdef SQLITE_OMIT_UTF16
+#if SQLITE_OMIT_UTF16
"OMIT_UTF16",
#endif
-#ifdef SQLITE_OMIT_VACUUM
+#if SQLITE_OMIT_VACUUM
"OMIT_VACUUM",
#endif
-#ifdef SQLITE_OMIT_VIEW
+#if SQLITE_OMIT_VIEW
"OMIT_VIEW",
#endif
-#ifdef SQLITE_OMIT_VIRTUALTABLE
+#if SQLITE_OMIT_VIRTUALTABLE
"OMIT_VIRTUALTABLE",
#endif
-#ifdef SQLITE_OMIT_WAL
+#if SQLITE_OMIT_WAL
"OMIT_WAL",
#endif
-#ifdef SQLITE_OMIT_WSD
+#if SQLITE_OMIT_WSD
"OMIT_WSD",
#endif
-#ifdef SQLITE_OMIT_XFER_OPT
+#if SQLITE_OMIT_XFER_OPT
"OMIT_XFER_OPT",
#endif
-#ifdef SQLITE_PERFORMANCE_TRACE
+#if SQLITE_PERFORMANCE_TRACE
"PERFORMANCE_TRACE",
#endif
-#ifdef SQLITE_PROXY_DEBUG
+#if SQLITE_PROXY_DEBUG
"PROXY_DEBUG",
#endif
-#ifdef SQLITE_RTREE_INT_ONLY
+#if SQLITE_RTREE_INT_ONLY
"RTREE_INT_ONLY",
#endif
-#ifdef SQLITE_SECURE_DELETE
+#if SQLITE_SECURE_DELETE
"SECURE_DELETE",
#endif
-#ifdef SQLITE_SMALL_STACK
+#if SQLITE_SMALL_STACK
"SMALL_STACK",
#endif
-#ifdef SQLITE_SOUNDEX
+#if SQLITE_SOUNDEX
"SOUNDEX",
#endif
-#ifdef SQLITE_SYSTEM_MALLOC
+#if SQLITE_SYSTEM_MALLOC
"SYSTEM_MALLOC",
#endif
-#ifdef SQLITE_TCL
+#if SQLITE_TCL
"TCL",
#endif
#if defined(SQLITE_TEMP_STORE) && !defined(SQLITE_TEMP_STORE_xc)
"TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE),
#endif
-#ifdef SQLITE_TEST
+#if SQLITE_TEST
"TEST",
#endif
#if defined(SQLITE_THREADSAFE)
"THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE),
#endif
-#ifdef SQLITE_USE_ALLOCA
+#if SQLITE_USE_ALLOCA
"USE_ALLOCA",
#endif
-#ifdef SQLITE_WIN32_MALLOC
+#if SQLITE_USER_AUTHENTICATION
+ "USER_AUTHENTICATION",
+#endif
+#if SQLITE_WIN32_MALLOC
"WIN32_MALLOC",
#endif
-#ifdef SQLITE_ZERO_MALLOC
+#if SQLITE_ZERO_MALLOC
"ZERO_MALLOC"
#endif
};
@@ -13807,8 +14443,15 @@ static const char * const azCompileOpt[] = {
** The name can optionally begin with "SQLITE_" but the "SQLITE_" prefix
** is not required for a match.
*/
-SQLITE_API int sqlite3_compileoption_used(const char *zOptName){
+SQLITE_API int SQLITE_STDCALL sqlite3_compileoption_used(const char *zOptName){
int i, n;
+
+#if SQLITE_ENABLE_API_ARMOR
+ if( zOptName==0 ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
if( sqlite3StrNICmp(zOptName, "SQLITE_", 7)==0 ) zOptName += 7;
n = sqlite3Strlen30(zOptName);
@@ -13816,7 +14459,7 @@ SQLITE_API int sqlite3_compileoption_used(const char *zOptName){
** linear search is adequate. No need for a binary search. */
for(i=0; i<ArraySize(azCompileOpt); i++){
if( sqlite3StrNICmp(zOptName, azCompileOpt[i], n)==0
- && sqlite3CtypeMap[(unsigned char)azCompileOpt[i][n]]==0
+ && sqlite3IsIdChar((unsigned char)azCompileOpt[i][n])==0
){
return 1;
}
@@ -13828,7 +14471,7 @@ SQLITE_API int sqlite3_compileoption_used(const char *zOptName){
** Return the N-th compile-time option string. If N is out of range,
** return a NULL pointer.
*/
-SQLITE_API const char *sqlite3_compileoption_get(int N){
+SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N){
if( N>=0 && N<ArraySize(azCompileOpt) ){
return azCompileOpt[N];
}
@@ -13931,7 +14574,6 @@ struct VdbeCursor {
#endif
i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */
u8 nullRow; /* True if pointing to a row with no data */
- u8 rowidIsValid; /* True if lastRowid is valid */
u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
Bool isEphemeral:1; /* True for an ephemeral table */
Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */
@@ -13941,7 +14583,6 @@ struct VdbeCursor {
sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */
i64 seqCount; /* Sequence counter */
i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
- i64 lastRowid; /* Rowid being deleted by OP_Delete */
VdbeSorter *pSorter; /* Sorter object for OP_SorterOpen cursors */
/* Cached information about the header for the data record that the
@@ -13958,6 +14599,7 @@ struct VdbeCursor {
u32 szRow; /* Byte available in aRow */
u32 iHdrOffset; /* Offset to next unparsed byte of the header */
const u8 *aRow; /* Data for the current row, if all on one page */
+ u32 *aOffset; /* Pointer to aType[nField] */
u32 aType[1]; /* Type values for all entries in the record */
/* 2*nField extra array elements allocated for aType[], beyond the one
** static element declared in the structure. nField total array slots for
@@ -13991,6 +14633,7 @@ struct VdbeFrame {
Vdbe *v; /* VM this frame belongs to */
VdbeFrame *pParent; /* Parent of this frame, or NULL if parent is main */
Op *aOp; /* Program instructions for parent frame */
+ i64 *anExec; /* Event counters from parent frame */
Mem *aMem; /* Array of memory cells for parent frame */
u8 *aOnceFlag; /* Array of OP_Once flags for parent frame */
VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */
@@ -14003,7 +14646,8 @@ struct VdbeFrame {
int nOnceFlag; /* Number of entries in aOnceFlag */
int nChildMem; /* Number of memory cells for child frame */
int nChildCsr; /* Number of cursors for child frame */
- int nChange; /* Statement changes (Vdbe.nChanges) */
+ int nChange; /* Statement changes (Vdbe.nChange) */
+ int nDbChange; /* Value of db->nChange */
};
#define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))])
@@ -14019,25 +14663,28 @@ struct VdbeFrame {
** integer etc.) of the same value.
*/
struct Mem {
- sqlite3 *db; /* The associated database connection */
- char *z; /* String or BLOB value */
- double r; /* Real value */
- union {
+ union MemValue {
+ double r; /* Real value used when MEM_Real is set in flags */
i64 i; /* Integer value used when MEM_Int is set in flags */
int nZero; /* Used when bit MEM_Zero is set in flags */
FuncDef *pDef; /* Used only when flags==MEM_Agg */
RowSet *pRowSet; /* Used only when flags==MEM_RowSet */
VdbeFrame *pFrame; /* Used when flags==MEM_Frame */
} u;
- int n; /* Number of characters in string value, excluding '\0' */
u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */
+ int n; /* Number of characters in string value, excluding '\0' */
+ char *z; /* String or BLOB value */
+ /* ShallowCopy only needs to copy the information above */
+ char *zMalloc; /* Space to hold MEM_Str or MEM_Blob if szMalloc>0 */
+ int szMalloc; /* Size of the zMalloc allocation */
+ u32 uTemp; /* Transient storage for serial_type in OP_MakeRecord */
+ sqlite3 *db; /* The associated database connection */
+ void (*xDel)(void*);/* Destructor for Mem.z - only valid if MEM_Dyn */
#ifdef SQLITE_DEBUG
Mem *pScopyFrom; /* This Mem is a shallow copy of pScopyFrom */
void *pFiller; /* So that sizeof(Mem) is a multiple of 8 */
#endif
- void (*xDel)(void *); /* If not null, call this function to delete Mem.z */
- char *zMalloc; /* Dynamic buffer allocated by sqlite3_malloc() */
};
/* One or more of the following flags are set to indicate the validOK
@@ -14096,7 +14743,7 @@ struct Mem {
#endif
/*
-** Each auxilliary data pointer stored by a user defined function
+** Each auxiliary data pointer stored by a user defined function
** implementation calling sqlite3_set_auxdata() is stored in an instance
** of this structure. All such structures associated with a single VM
** are stored in a linked list headed at Vdbe.pAuxData. All are destroyed
@@ -14111,7 +14758,7 @@ struct AuxData {
};
/*
-** The "context" argument for a installable function. A pointer to an
+** The "context" argument for an installable function. A pointer to an
** instance of this structure is the first argument to the routines used
** implement the SQL functions.
**
@@ -14124,14 +14771,13 @@ struct AuxData {
** (Mem) which are only defined there.
*/
struct sqlite3_context {
- FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */
- Mem s; /* The return value is stored here */
+ Mem *pOut; /* The return value is stored here */
+ FuncDef *pFunc; /* Pointer to function information */
Mem *pMem; /* Memory cell used to store aggregate context */
- CollSeq *pColl; /* Collating sequence */
Vdbe *pVdbe; /* The VM that owns this context */
int iOp; /* Instruction number of OP_Function */
int isError; /* Error code returned by the function. */
- u8 skipFlag; /* Skip skip accumulator loading if true */
+ u8 skipFlag; /* Skip accumulator loading if true */
u8 fErrorOrAux; /* isError!=0 or pVdbe->pAuxData modified */
};
@@ -14152,20 +14798,22 @@ struct Explain {
*/
typedef unsigned bft; /* Bit Field Type */
+typedef struct ScanStatus ScanStatus;
+struct ScanStatus {
+ int addrExplain; /* OP_Explain for loop */
+ int addrLoop; /* Address of "loops" counter */
+ int addrVisit; /* Address of "rows visited" counter */
+ int iSelectID; /* The "Select-ID" for this loop */
+ LogEst nEst; /* Estimated output rows per loop */
+ char *zName; /* Name of table or index */
+};
+
/*
** An instance of the virtual machine. This structure contains the complete
** state of the virtual machine.
**
** The "sqlite3_stmt" structure pointer that is returned by sqlite3_prepare()
** is really a pointer to an instance of this structure.
-**
-** The Vdbe.inVtabMethod variable is set to non-zero for the duration of
-** any virtual table method invocations made by the vdbe program. It is
-** set to 2 for xDestroy method calls and 1 for all other methods. This
-** variable is used for two purposes: to allow xDestroy methods to execute
-** "DROP TABLE" statements and to prevent some nasty side effects of
-** malloc failure when SQLite is invoked recursively by a virtual table
-** method function.
*/
struct Vdbe {
sqlite3 *db; /* The database connection that owns this statement */
@@ -14189,11 +14837,13 @@ struct Vdbe {
u32 cacheCtr; /* VdbeCursor row cache generation counter */
int pc; /* The program counter */
int rc; /* Value to return */
+#ifdef SQLITE_DEBUG
+ int rcApp; /* errcode set by sqlite3_result_error_code() */
+#endif
u16 nResColumn; /* Number of columns in one row of the result set */
u8 errorAction; /* Recovery action to do in case of an error */
u8 minWriteFileFormat; /* Minimum file format for writable database files */
bft explain:2; /* True if EXPLAIN present on SQL command */
- bft inVtabMethod:2; /* See comments above */
bft changeCntOn:1; /* True to update the change-counter */
bft expired:1; /* True if the VM needs to be recompiled */
bft runOnlyOnce:1; /* Automatically expire on reset */
@@ -14216,10 +14866,6 @@ struct Vdbe {
i64 nStmtDefImmCons; /* Number of def. imm constraints when stmt started */
char *zSql; /* Text of the SQL statement that generated this */
void *pFree; /* Free this when deleting the vdbe */
-#ifdef SQLITE_ENABLE_TREE_EXPLAIN
- Explain *pExplain; /* The explainer */
- char *zExplain; /* Explanation of data structures */
-#endif
VdbeFrame *pFrame; /* Parent frame */
VdbeFrame *pDelFrame; /* List of frame objects to free on VM reset */
int nFrame; /* Number of frames in pFrame list */
@@ -14228,6 +14874,11 @@ struct Vdbe {
int nOnceFlag; /* Size of array aOnceFlag[] */
u8 *aOnceFlag; /* Flags for OP_Once */
AuxData *pAuxData; /* Linked list of auxdata allocations */
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ i64 *anExec; /* Number of times each op has been executed */
+ int nScan; /* Entries in aScan[] */
+ ScanStatus *aScan; /* Scan definitions for sqlite3_stmt_scanstatus() */
+#endif
};
/*
@@ -14244,6 +14895,7 @@ struct Vdbe {
SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*);
void sqliteVdbePopStack(Vdbe*,int);
SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor*);
+SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor*);
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE*, int, Op*);
#endif
@@ -14254,8 +14906,8 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(Vdbe*, int, int);
int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
-SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(VdbeCursor*,UnpackedRecord*,int*);
-SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3*, BtCursor *, i64 *);
+SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(sqlite3*,VdbeCursor*,UnpackedRecord*,int*);
+SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3*, BtCursor*, i64*);
SQLITE_PRIVATE int sqlite3VdbeExec(Vdbe*);
SQLITE_PRIVATE int sqlite3VdbeList(Vdbe*);
SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe*);
@@ -14272,39 +14924,39 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem*, i64);
#else
SQLITE_PRIVATE void sqlite3VdbeMemSetDouble(Mem*, double);
#endif
+SQLITE_PRIVATE void sqlite3VdbeMemInit(Mem*,sqlite3*,u16);
SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem*);
SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem*,int);
SQLITE_PRIVATE void sqlite3VdbeMemSetRowSet(Mem*);
SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem*);
-SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem*, int);
+SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem*, u8, u8);
SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem*);
SQLITE_PRIVATE int sqlite3VdbeMemIntegerify(Mem*);
SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem*);
SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem*);
SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem*);
SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem*);
+SQLITE_PRIVATE void sqlite3VdbeMemCast(Mem*,u8,u8);
SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,int,Mem*);
SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p);
-SQLITE_PRIVATE void sqlite3VdbeMemReleaseExternal(Mem *p);
#define VdbeMemDynamic(X) \
(((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))!=0)
-#define VdbeMemRelease(X) \
- if( VdbeMemDynamic(X) ) sqlite3VdbeMemReleaseExternal(X);
SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
SQLITE_PRIVATE const char *sqlite3OpcodeName(int);
SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve);
+SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int n);
SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *, int);
SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*);
SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *);
SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p);
-SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *, VdbeCursor *);
+SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *, int, VdbeCursor *);
SQLITE_PRIVATE void sqlite3VdbeSorterReset(sqlite3 *, VdbeSorter *);
SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *);
SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *);
SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *);
-SQLITE_PRIVATE int sqlite3VdbeSorterRewind(sqlite3 *, const VdbeCursor *, int *);
-SQLITE_PRIVATE int sqlite3VdbeSorterWrite(sqlite3 *, const VdbeCursor *, Mem *);
+SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *, int *);
+SQLITE_PRIVATE int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *);
SQLITE_PRIVATE int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *);
#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0
@@ -14351,10 +15003,32 @@ SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *);
*/
typedef struct sqlite3StatType sqlite3StatType;
static SQLITE_WSD struct sqlite3StatType {
- int nowValue[10]; /* Current value */
- int mxValue[10]; /* Maximum value */
+#if SQLITE_PTRSIZE>4
+ sqlite3_int64 nowValue[10]; /* Current value */
+ sqlite3_int64 mxValue[10]; /* Maximum value */
+#else
+ u32 nowValue[10]; /* Current value */
+ u32 mxValue[10]; /* Maximum value */
+#endif
} sqlite3Stat = { {0,}, {0,} };
+/*
+** Elements of sqlite3Stat[] are protected by either the memory allocator
+** mutex, or by the pcache1 mutex. The following array determines which.
+*/
+static const char statMutex[] = {
+ 0, /* SQLITE_STATUS_MEMORY_USED */
+ 1, /* SQLITE_STATUS_PAGECACHE_USED */
+ 1, /* SQLITE_STATUS_PAGECACHE_OVERFLOW */
+ 0, /* SQLITE_STATUS_SCRATCH_USED */
+ 0, /* SQLITE_STATUS_SCRATCH_OVERFLOW */
+ 0, /* SQLITE_STATUS_MALLOC_SIZE */
+ 0, /* SQLITE_STATUS_PARSER_STACK */
+ 1, /* SQLITE_STATUS_PAGECACHE_SIZE */
+ 0, /* SQLITE_STATUS_SCRATCH_SIZE */
+ 0, /* SQLITE_STATUS_MALLOC_COUNT */
+};
+
/* The "wsdStat" macro will resolve to the status information
** state vector. If writable static data is unsupported on the target,
@@ -14371,33 +15045,60 @@ static SQLITE_WSD struct sqlite3StatType {
#endif
/*
-** Return the current value of a status parameter.
+** Return the current value of a status parameter. The caller must
+** be holding the appropriate mutex.
*/
-SQLITE_PRIVATE int sqlite3StatusValue(int op){
+SQLITE_PRIVATE sqlite3_int64 sqlite3StatusValue(int op){
wsdStatInit;
assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
+ assert( op>=0 && op<ArraySize(statMutex) );
+ assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
+ : sqlite3MallocMutex()) );
return wsdStat.nowValue[op];
}
/*
-** Add N to the value of a status record. It is assumed that the
-** caller holds appropriate locks.
+** Add N to the value of a status record. The caller must hold the
+** appropriate mutex. (Locking is checked by assert()).
+**
+** The StatusUp() routine can accept positive or negative values for N.
+** The value of N is added to the current status value and the high-water
+** mark is adjusted if necessary.
+**
+** The StatusDown() routine lowers the current value by N. The highwater
+** mark is unchanged. N must be non-negative for StatusDown().
*/
-SQLITE_PRIVATE void sqlite3StatusAdd(int op, int N){
+SQLITE_PRIVATE void sqlite3StatusUp(int op, int N){
wsdStatInit;
assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
+ assert( op>=0 && op<ArraySize(statMutex) );
+ assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
+ : sqlite3MallocMutex()) );
wsdStat.nowValue[op] += N;
if( wsdStat.nowValue[op]>wsdStat.mxValue[op] ){
wsdStat.mxValue[op] = wsdStat.nowValue[op];
}
}
+SQLITE_PRIVATE void sqlite3StatusDown(int op, int N){
+ wsdStatInit;
+ assert( N>=0 );
+ assert( op>=0 && op<ArraySize(statMutex) );
+ assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
+ : sqlite3MallocMutex()) );
+ assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
+ wsdStat.nowValue[op] -= N;
+}
/*
-** Set the value of a status to X.
+** Set the value of a status to X. The highwater mark is adjusted if
+** necessary. The caller must hold the appropriate mutex.
*/
SQLITE_PRIVATE void sqlite3StatusSet(int op, int X){
wsdStatInit;
assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
+ assert( op>=0 && op<ArraySize(statMutex) );
+ assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
+ : sqlite3MallocMutex()) );
wsdStat.nowValue[op] = X;
if( wsdStat.nowValue[op]>wsdStat.mxValue[op] ){
wsdStat.mxValue[op] = wsdStat.nowValue[op];
@@ -14406,28 +15107,50 @@ SQLITE_PRIVATE void sqlite3StatusSet(int op, int X){
/*
** Query status information.
-**
-** This implementation assumes that reading or writing an aligned
-** 32-bit integer is an atomic operation. If that assumption is not true,
-** then this routine is not threadsafe.
*/
-SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){
+SQLITE_API int SQLITE_STDCALL sqlite3_status64(
+ int op,
+ sqlite3_int64 *pCurrent,
+ sqlite3_int64 *pHighwater,
+ int resetFlag
+){
+ sqlite3_mutex *pMutex;
wsdStatInit;
if( op<0 || op>=ArraySize(wsdStat.nowValue) ){
return SQLITE_MISUSE_BKPT;
}
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT;
+#endif
+ pMutex = statMutex[op] ? sqlite3Pcache1Mutex() : sqlite3MallocMutex();
+ sqlite3_mutex_enter(pMutex);
*pCurrent = wsdStat.nowValue[op];
*pHighwater = wsdStat.mxValue[op];
if( resetFlag ){
wsdStat.mxValue[op] = wsdStat.nowValue[op];
}
+ sqlite3_mutex_leave(pMutex);
+ (void)pMutex; /* Prevent warning when SQLITE_THREADSAFE=0 */
return SQLITE_OK;
}
+SQLITE_API int SQLITE_STDCALL sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){
+ sqlite3_int64 iCur, iHwtr;
+ int rc;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT;
+#endif
+ rc = sqlite3_status64(op, &iCur, &iHwtr, resetFlag);
+ if( rc==0 ){
+ *pCurrent = (int)iCur;
+ *pHighwater = (int)iHwtr;
+ }
+ return rc;
+}
/*
** Query status information for a single database connection
*/
-SQLITE_API int sqlite3_db_status(
+SQLITE_API int SQLITE_STDCALL sqlite3_db_status(
sqlite3 *db, /* The database connection whose status is desired */
int op, /* Status verb */
int *pCurrent, /* Write current value here */
@@ -14435,6 +15158,11 @@ SQLITE_API int sqlite3_db_status(
int resetFlag /* Reset high-water mark if true */
){
int rc = SQLITE_OK; /* Return code */
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) || pCurrent==0|| pHighwater==0 ){
+ return SQLITE_MISUSE_BKPT;
+ }
+#endif
sqlite3_mutex_enter(db->mutex);
switch( op ){
case SQLITE_DBSTATUS_LOOKASIDE_USED: {
@@ -14543,7 +15271,7 @@ SQLITE_API int sqlite3_db_status(
}
db->pnBytesFreed = 0;
- *pHighwater = 0;
+ *pHighwater = 0; /* IMP: R-64479-57858 */
*pCurrent = nByte;
break;
@@ -14568,7 +15296,9 @@ SQLITE_API int sqlite3_db_status(
sqlite3PagerCacheStat(pPager, op, resetFlag, &nRet);
}
}
- *pHighwater = 0;
+ *pHighwater = 0; /* IMP: R-42420-56072 */
+ /* IMP: R-54100-20147 */
+ /* IMP: R-29431-39229 */
*pCurrent = nRet;
break;
}
@@ -14578,7 +15308,7 @@ SQLITE_API int sqlite3_db_status(
** have been satisfied. The *pHighwater is always set to zero.
*/
case SQLITE_DBSTATUS_DEFERRED_FKS: {
- *pHighwater = 0;
+ *pHighwater = 0; /* IMP: R-11967-56545 */
*pCurrent = db->nDeferredImmCons>0 || db->nDeferredCons>0;
break;
}
@@ -14611,7 +15341,7 @@ SQLITE_API int sqlite3_db_status(
** sqlite3RegisterDateTimeFunctions() found at the bottom of the file.
** All other code has file scope.
**
-** SQLite processes all times and dates as Julian Day numbers. The
+** SQLite processes all times and dates as julian day numbers. The
** dates and times are stored as the number of days since noon
** in Greenwich on November 24, 4714 B.C. according to the Gregorian
** calendar system.
@@ -14619,14 +15349,14 @@ SQLITE_API int sqlite3_db_status(
** 1970-01-01 00:00:00 is JD 2440587.5
** 2000-01-01 00:00:00 is JD 2451544.5
**
-** This implemention requires years to be expressed as a 4-digit number
+** This implementation requires years to be expressed as a 4-digit number
** which means that only dates between 0000-01-01 and 9999-12-31 can
** be represented, even though julian day numbers allow a much wider
** range of dates.
**
** The Gregorian calendar system is used for all dates and times,
** even those that predate the Gregorian calendar. Historians usually
-** use the Julian calendar for dates prior to 1582-10-15 and for some
+** use the julian calendar for dates prior to 1582-10-15 and for some
** dates afterwards, depending on locale. Beware of this difference.
**
** The conversion algorithms are implemented based on descriptions
@@ -14898,7 +15628,7 @@ static int setDateTimeToCurrent(sqlite3_context *context, DateTime *p){
}
/*
-** Attempt to parse the given string into a Julian Day Number. Return
+** Attempt to parse the given string into a julian day number. Return
** the number of errors.
**
** The following are acceptable forms for the input string:
@@ -15006,8 +15736,9 @@ static void clearYMD_HMS_TZ(DateTime *p){
** already, check for an MSVC build environment that provides
** localtime_s().
*/
-#if !defined(HAVE_LOCALTIME_R) && !defined(HAVE_LOCALTIME_S) && \
- defined(_MSC_VER) && defined(_CRT_INSECURE_DEPRECATE)
+#if !HAVE_LOCALTIME_R && !HAVE_LOCALTIME_S \
+ && defined(_MSC_VER) && defined(_CRT_INSECURE_DEPRECATE)
+#undef HAVE_LOCALTIME_S
#define HAVE_LOCALTIME_S 1
#endif
@@ -15027,8 +15758,7 @@ static void clearYMD_HMS_TZ(DateTime *p){
*/
static int osLocaltime(time_t *t, struct tm *pTm){
int rc;
-#if (!defined(HAVE_LOCALTIME_R) || !HAVE_LOCALTIME_R) \
- && (!defined(HAVE_LOCALTIME_S) || !HAVE_LOCALTIME_S)
+#if !HAVE_LOCALTIME_R && !HAVE_LOCALTIME_S
struct tm *pX;
#if SQLITE_THREADSAFE>0
sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
@@ -15045,7 +15775,7 @@ static int osLocaltime(time_t *t, struct tm *pTm){
#ifndef SQLITE_OMIT_BUILTIN_TEST
if( sqlite3GlobalConfig.bLocaltimeFault ) return 1;
#endif
-#if defined(HAVE_LOCALTIME_R) && HAVE_LOCALTIME_R
+#if HAVE_LOCALTIME_R
rc = localtime_r(t, pTm)==0;
#else
rc = localtime_s(pTm, t);
@@ -15469,7 +16199,7 @@ static void dateFunc(
** %f ** fractional seconds SS.SSS
** %H hour 00-24
** %j day of year 000-366
-** %J ** Julian day number
+** %J ** julian day number
** %m month 01-12
** %M minute 00-59
** %s seconds since 1970-01-01
@@ -15489,8 +16219,10 @@ static void strftimeFunc(
size_t i,j;
char *z;
sqlite3 *db;
- const char *zFmt = (const char*)sqlite3_value_text(argv[0]);
+ const char *zFmt;
char zBuf[100];
+ if( argc==0 ) return;
+ zFmt = (const char*)sqlite3_value_text(argv[0]);
if( zFmt==0 || isDate(context, argc-1, argv+1, &x) ) return;
db = sqlite3_context_db_handle(context);
for(i=0, n=1; zFmt[i]; i++, n++){
@@ -15684,7 +16416,7 @@ static void currentTimeFunc(
iT = sqlite3StmtCurrentTime(context);
if( iT<=0 ) return;
t = iT/1000 - 10000*(sqlite3_int64)21086676;
-#ifdef HAVE_GMTIME_R
+#if HAVE_GMTIME_R
pTm = gmtime_r(&t, &sNow);
#else
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
@@ -16042,7 +16774,7 @@ static sqlite3_vfs * SQLITE_WSD vfsList = 0;
** Locate a VFS by name. If no name is given, simply return the
** first VFS on the list.
*/
-SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfs){
+SQLITE_API sqlite3_vfs *SQLITE_STDCALL sqlite3_vfs_find(const char *zVfs){
sqlite3_vfs *pVfs = 0;
#if SQLITE_THREADSAFE
sqlite3_mutex *mutex;
@@ -16088,12 +16820,16 @@ static void vfsUnlink(sqlite3_vfs *pVfs){
** VFS multiple times. The new VFS becomes the default if makeDflt is
** true.
*/
-SQLITE_API int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){
+SQLITE_API int SQLITE_STDCALL sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){
MUTEX_LOGIC(sqlite3_mutex *mutex;)
#ifndef SQLITE_OMIT_AUTOINIT
int rc = sqlite3_initialize();
if( rc ) return rc;
#endif
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pVfs==0 ) return SQLITE_MISUSE_BKPT;
+#endif
+
MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
sqlite3_mutex_enter(mutex);
vfsUnlink(pVfs);
@@ -16112,7 +16848,7 @@ SQLITE_API int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){
/*
** Unregister a VFS so that it is no longer accessible.
*/
-SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs *pVfs){
+SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs *pVfs){
#if SQLITE_THREADSAFE
sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
#endif
@@ -16354,9 +17090,9 @@ static malloc_zone_t* _sqliteZone_;
** The malloc.h header file is needed for malloc_usable_size() function
** on some systems (e.g. Linux).
*/
-#if defined(HAVE_MALLOC_H) && defined(HAVE_MALLOC_USABLE_SIZE)
-# define SQLITE_USE_MALLOC_H
-# define SQLITE_USE_MALLOC_USABLE_SIZE
+#if HAVE_MALLOC_H && HAVE_MALLOC_USABLE_SIZE
+# define SQLITE_USE_MALLOC_H 1
+# define SQLITE_USE_MALLOC_USABLE_SIZE 1
/*
** The MSVCRT has malloc_usable_size(), but it is called _msize(). The
** use of _msize() is automatic, but can be disabled by compiling with
@@ -16463,7 +17199,7 @@ static int sqlite3MemSize(void *pPrior){
**
** For this low-level interface, we know that pPrior!=0. Cases where
** pPrior==0 while have been intercepted by higher-level routine and
-** redirected to xMalloc. Similarly, we know that nByte>0 becauses
+** redirected to xMalloc. Similarly, we know that nByte>0 because
** cases where nByte<=0 will have been intercepted by higher-level
** routines and redirected to xFree.
*/
@@ -16966,7 +17702,7 @@ SQLITE_PRIVATE void sqlite3MemdebugSetType(void *p, u8 eType){
** This routine is designed for use within an assert() statement, to
** verify the type of an allocation. For example:
**
-** assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) );
+** assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
*/
SQLITE_PRIVATE int sqlite3MemdebugHasType(void *p, u8 eType){
int rc = 1;
@@ -16988,7 +17724,7 @@ SQLITE_PRIVATE int sqlite3MemdebugHasType(void *p, u8 eType){
** This routine is designed for use within an assert() statement, to
** verify the type of an allocation. For example:
**
-** assert( sqlite3MemdebugNoType(p, MEMTYPE_DB) );
+** assert( sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) );
*/
SQLITE_PRIVATE int sqlite3MemdebugNoType(void *p, u8 eType){
int rc = 1;
@@ -17820,7 +18556,7 @@ SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void){
** 1. All memory allocations sizes are rounded up to a power of 2.
**
** 2. If two adjacent free blocks are the halves of a larger block,
-** then the two blocks are coalesed into the single larger block.
+** then the two blocks are coalesced into the single larger block.
**
** 3. New memory is allocated from the first available free block.
**
@@ -18448,9 +19184,10 @@ SQLITE_PRIVATE int sqlite3MutexEnd(void){
/*
** Retrieve a pointer to a static mutex or allocate a new dynamic one.
*/
-SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int id){
+SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_mutex_alloc(int id){
#ifndef SQLITE_OMIT_AUTOINIT
if( id<=SQLITE_MUTEX_RECURSIVE && sqlite3_initialize() ) return 0;
+ if( id>SQLITE_MUTEX_RECURSIVE && sqlite3MutexInit() ) return 0;
#endif
return sqlite3GlobalConfig.mutex.xMutexAlloc(id);
}
@@ -18466,7 +19203,7 @@ SQLITE_PRIVATE sqlite3_mutex *sqlite3MutexAlloc(int id){
/*
** Free a dynamic mutex.
*/
-SQLITE_API void sqlite3_mutex_free(sqlite3_mutex *p){
+SQLITE_API void SQLITE_STDCALL sqlite3_mutex_free(sqlite3_mutex *p){
if( p ){
sqlite3GlobalConfig.mutex.xMutexFree(p);
}
@@ -18476,7 +19213,7 @@ SQLITE_API void sqlite3_mutex_free(sqlite3_mutex *p){
** Obtain the mutex p. If some other thread already has the mutex, block
** until it can be obtained.
*/
-SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex *p){
+SQLITE_API void SQLITE_STDCALL sqlite3_mutex_enter(sqlite3_mutex *p){
if( p ){
sqlite3GlobalConfig.mutex.xMutexEnter(p);
}
@@ -18486,7 +19223,7 @@ SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex *p){
** Obtain the mutex p. If successful, return SQLITE_OK. Otherwise, if another
** thread holds the mutex and it cannot be obtained, return SQLITE_BUSY.
*/
-SQLITE_API int sqlite3_mutex_try(sqlite3_mutex *p){
+SQLITE_API int SQLITE_STDCALL sqlite3_mutex_try(sqlite3_mutex *p){
int rc = SQLITE_OK;
if( p ){
return sqlite3GlobalConfig.mutex.xMutexTry(p);
@@ -18500,7 +19237,7 @@ SQLITE_API int sqlite3_mutex_try(sqlite3_mutex *p){
** is not currently entered. If a NULL pointer is passed as an argument
** this function is a no-op.
*/
-SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex *p){
+SQLITE_API void SQLITE_STDCALL sqlite3_mutex_leave(sqlite3_mutex *p){
if( p ){
sqlite3GlobalConfig.mutex.xMutexLeave(p);
}
@@ -18511,10 +19248,10 @@ SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex *p){
** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
** intended for use inside assert() statements.
*/
-SQLITE_API int sqlite3_mutex_held(sqlite3_mutex *p){
+SQLITE_API int SQLITE_STDCALL sqlite3_mutex_held(sqlite3_mutex *p){
return p==0 || sqlite3GlobalConfig.mutex.xMutexHeld(p);
}
-SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex *p){
+SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex *p){
return p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld(p);
}
#endif
@@ -18644,8 +19381,12 @@ static sqlite3_mutex *debugMutexAlloc(int id){
break;
}
default: {
- assert( id-2 >= 0 );
- assert( id-2 < (int)(sizeof(aStatic)/sizeof(aStatic[0])) );
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( id-2<0 || id-2>=ArraySize(aStatic) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
pNew = &aStatic[id-2];
pNew->id = id;
break;
@@ -18660,8 +19401,13 @@ static sqlite3_mutex *debugMutexAlloc(int id){
static void debugMutexFree(sqlite3_mutex *pX){
sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
assert( p->cnt==0 );
- assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
- sqlite3_free(p);
+ if( p->id==SQLITE_MUTEX_RECURSIVE || p->id==SQLITE_MUTEX_FAST ){
+ sqlite3_free(p);
+ }else{
+#ifdef SQLITE_ENABLE_API_ARMOR
+ (void)SQLITE_MISUSE_BKPT;
+#endif
+ }
}
/*
@@ -18772,8 +19518,10 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
*/
struct sqlite3_mutex {
pthread_mutex_t mutex; /* Mutex controlling the lock */
-#if SQLITE_MUTEX_NREF
+#if SQLITE_MUTEX_NREF || defined(SQLITE_ENABLE_API_ARMOR)
int id; /* Mutex type */
+#endif
+#if SQLITE_MUTEX_NREF
volatile int nRef; /* Number of entrances */
volatile pthread_t owner; /* Thread that is within this mutex */
int trace; /* True to trace changes */
@@ -18890,32 +19638,30 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){
pthread_mutex_init(&p->mutex, &recursiveAttr);
pthread_mutexattr_destroy(&recursiveAttr);
#endif
-#if SQLITE_MUTEX_NREF
- p->id = iType;
-#endif
}
break;
}
case SQLITE_MUTEX_FAST: {
p = sqlite3MallocZero( sizeof(*p) );
if( p ){
-#if SQLITE_MUTEX_NREF
- p->id = iType;
-#endif
pthread_mutex_init(&p->mutex, 0);
}
break;
}
default: {
- assert( iType-2 >= 0 );
- assert( iType-2 < ArraySize(staticMutexes) );
- p = &staticMutexes[iType-2];
-#if SQLITE_MUTEX_NREF
- p->id = iType;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( iType-2<0 || iType-2>=ArraySize(staticMutexes) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
#endif
+ p = &staticMutexes[iType-2];
break;
}
}
+#if SQLITE_MUTEX_NREF || defined(SQLITE_ENABLE_API_ARMOR)
+ if( p ) p->id = iType;
+#endif
return p;
}
@@ -18927,9 +19673,18 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){
*/
static void pthreadMutexFree(sqlite3_mutex *p){
assert( p->nRef==0 );
- assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
- pthread_mutex_destroy(&p->mutex);
- sqlite3_free(p);
+#if SQLITE_ENABLE_API_ARMOR
+ if( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE )
+#endif
+ {
+ pthread_mutex_destroy(&p->mutex);
+ sqlite3_free(p);
+ }
+#ifdef SQLITE_ENABLE_API_ARMOR
+ else{
+ (void)SQLITE_MISUSE_BKPT;
+ }
+#endif
}
/*
@@ -19141,16 +19896,6 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead."
#endif
-#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
-# ifndef SQLITE_DEBUG_OS_TRACE
-# define SQLITE_DEBUG_OS_TRACE 0
-# endif
- int sqlite3OSTrace = SQLITE_DEBUG_OS_TRACE;
-# define OSTRACE(X) if( sqlite3OSTrace ) sqlite3DebugPrintf X
-#else
-# define OSTRACE(X)
-#endif
-
/*
** Macros for performance tracing. Normally turned off. Only works
** on i486 hardware.
@@ -19389,6 +20134,27 @@ SQLITE_API int sqlite3_open_file_count = 0;
# define SQLITE_OS_WINRT 0
#endif
+/*
+** For WinCE, some API function parameters do not appear to be declared as
+** volatile.
+*/
+#if SQLITE_OS_WINCE
+# define SQLITE_WIN32_VOLATILE
+#else
+# define SQLITE_WIN32_VOLATILE volatile
+#endif
+
+/*
+** For some Windows sub-platforms, the _beginthreadex() / _endthreadex()
+** functions are not available (e.g. those not using MSVC, Cygwin, etc).
+*/
+#if SQLITE_OS_WIN && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \
+ SQLITE_THREADSAFE>0 && !defined(__CYGWIN__)
+# define SQLITE_OS_WIN_THREADS 1
+#else
+# define SQLITE_OS_WIN_THREADS 0
+#endif
+
#endif /* _OS_WIN_H_ */
/************** End of os_win.h **********************************************/
@@ -19469,10 +20235,10 @@ static int winMutex_isNt = -1; /* <0 means "need to query" */
** of the sqlite3_initialize() and sqlite3_shutdown() processing, the
** "interlocked" magic used here is probably not strictly necessary.
*/
-static LONG volatile winMutex_lock = 0;
+static LONG SQLITE_WIN32_VOLATILE winMutex_lock = 0;
-SQLITE_API int sqlite3_win32_is_nt(void); /* os_win.c */
-SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds); /* os_win.c */
+SQLITE_API int SQLITE_STDCALL sqlite3_win32_is_nt(void); /* os_win.c */
+SQLITE_API void SQLITE_STDCALL sqlite3_win32_sleep(DWORD milliseconds); /* os_win.c */
static int winMutexInit(void){
/* The first to increment to 1 does actual initialization */
@@ -19564,8 +20330,8 @@ static sqlite3_mutex *winMutexAlloc(int iType){
case SQLITE_MUTEX_RECURSIVE: {
p = sqlite3MallocZero( sizeof(*p) );
if( p ){
-#ifdef SQLITE_DEBUG
p->id = iType;
+#ifdef SQLITE_DEBUG
#ifdef SQLITE_WIN32_MUTEX_TRACE_DYNAMIC
p->trace = 1;
#endif
@@ -19579,12 +20345,15 @@ static sqlite3_mutex *winMutexAlloc(int iType){
break;
}
default: {
- assert( iType-2 >= 0 );
- assert( iType-2 < ArraySize(winMutex_staticMutexes) );
- assert( winMutex_isInit==1 );
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( iType-2<0 || iType-2>=ArraySize(winMutex_staticMutexes) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
p = &winMutex_staticMutexes[iType-2];
-#ifdef SQLITE_DEBUG
p->id = iType;
+#ifdef SQLITE_DEBUG
#ifdef SQLITE_WIN32_MUTEX_TRACE_STATIC
p->trace = 1;
#endif
@@ -19603,13 +20372,15 @@ static sqlite3_mutex *winMutexAlloc(int iType){
*/
static void winMutexFree(sqlite3_mutex *p){
assert( p );
-#ifdef SQLITE_DEBUG
assert( p->nRef==0 && p->owner==0 );
- assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
+ if( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ){
+ DeleteCriticalSection(&p->mutex);
+ sqlite3_free(p);
+ }else{
+#ifdef SQLITE_ENABLE_API_ARMOR
+ (void)SQLITE_MISUSE_BKPT;
#endif
- assert( winMutex_isInit==1 );
- DeleteCriticalSection(&p->mutex);
- sqlite3_free(p);
+ }
}
/*
@@ -19763,7 +20534,7 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
** held by SQLite. An example of non-essential memory is memory used to
** cache database pages that are not currently in use.
*/
-SQLITE_API int sqlite3_release_memory(int n){
+SQLITE_API int SQLITE_STDCALL sqlite3_release_memory(int n){
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
return sqlite3PcacheReleaseMemory(n);
#else
@@ -19819,6 +20590,13 @@ static SQLITE_WSD struct Mem0Global {
#define mem0 GLOBAL(struct Mem0Global, mem0)
/*
+** Return the memory allocator mutex. sqlite3_status() needs it.
+*/
+SQLITE_PRIVATE sqlite3_mutex *sqlite3MallocMutex(void){
+ return mem0.mutex;
+}
+
+/*
** This routine runs when the memory allocator sees that the
** total memory allocation is about to exceed the soft heap
** limit.
@@ -19840,7 +20618,7 @@ static int sqlite3MemoryAlarm(
void *pArg,
sqlite3_int64 iThreshold
){
- int nUsed;
+ sqlite3_int64 nUsed;
sqlite3_mutex_enter(mem0.mutex);
mem0.alarmCallback = xCallback;
mem0.alarmArg = pArg;
@@ -19856,7 +20634,7 @@ static int sqlite3MemoryAlarm(
** Deprecated external interface. Internal/core SQLite code
** should call sqlite3MemoryAlarm.
*/
-SQLITE_API int sqlite3_memory_alarm(
+SQLITE_API int SQLITE_STDCALL sqlite3_memory_alarm(
void(*xCallback)(void *pArg, sqlite3_int64 used,int N),
void *pArg,
sqlite3_int64 iThreshold
@@ -19869,7 +20647,7 @@ SQLITE_API int sqlite3_memory_alarm(
** Set the soft heap-size limit for the library. Passing a zero or
** negative value indicates no limit.
*/
-SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 n){
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_soft_heap_limit64(sqlite3_int64 n){
sqlite3_int64 priorLimit;
sqlite3_int64 excess;
#ifndef SQLITE_OMIT_AUTOINIT
@@ -19889,7 +20667,7 @@ SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 n){
if( excess>0 ) sqlite3_release_memory((int)(excess & 0x7fffffff));
return priorLimit;
}
-SQLITE_API void sqlite3_soft_heap_limit(int n){
+SQLITE_API void SQLITE_STDCALL sqlite3_soft_heap_limit(int n){
if( n<0 ) n = 0;
sqlite3_soft_heap_limit64(n);
}
@@ -19898,6 +20676,7 @@ SQLITE_API void sqlite3_soft_heap_limit(int n){
** Initialize the memory allocation subsystem.
*/
SQLITE_PRIVATE int sqlite3MallocInit(void){
+ int rc;
if( sqlite3GlobalConfig.m.xMalloc==0 ){
sqlite3MemSetDefault();
}
@@ -19933,7 +20712,9 @@ SQLITE_PRIVATE int sqlite3MallocInit(void){
sqlite3GlobalConfig.szPage = 0;
sqlite3GlobalConfig.nPage = 0;
}
- return sqlite3GlobalConfig.m.xInit(sqlite3GlobalConfig.m.pAppData);
+ rc = sqlite3GlobalConfig.m.xInit(sqlite3GlobalConfig.m.pAppData);
+ if( rc!=SQLITE_OK ) memset(&mem0, 0, sizeof(mem0));
+ return rc;
}
/*
@@ -19958,7 +20739,7 @@ SQLITE_PRIVATE void sqlite3MallocEnd(void){
/*
** Return the amount of memory currently checked out.
*/
-SQLITE_API sqlite3_int64 sqlite3_memory_used(void){
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_used(void){
int n, mx;
sqlite3_int64 res;
sqlite3_status(SQLITE_STATUS_MEMORY_USED, &n, &mx, 0);
@@ -19971,7 +20752,7 @@ SQLITE_API sqlite3_int64 sqlite3_memory_used(void){
** checked out since either the beginning of this process
** or since the most recent reset.
*/
-SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag){
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_highwater(int resetFlag){
int n, mx;
sqlite3_int64 res;
sqlite3_status(SQLITE_STATUS_MEMORY_USED, &n, &mx, resetFlag);
@@ -20009,7 +20790,7 @@ static int mallocWithAlarm(int n, void **pp){
nFull = sqlite3GlobalConfig.m.xRoundup(n);
sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, n);
if( mem0.alarmCallback!=0 ){
- int nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
+ sqlite3_int64 nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
if( nUsed >= mem0.alarmThreshold - nFull ){
mem0.nearlyFull = 1;
sqlite3MallocAlarm(nFull);
@@ -20026,8 +20807,8 @@ static int mallocWithAlarm(int n, void **pp){
#endif
if( p ){
nFull = sqlite3MallocSize(p);
- sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nFull);
- sqlite3StatusAdd(SQLITE_STATUS_MALLOC_COUNT, 1);
+ sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nFull);
+ sqlite3StatusUp(SQLITE_STATUS_MALLOC_COUNT, 1);
}
*pp = p;
return nFull;
@@ -20037,11 +20818,9 @@ static int mallocWithAlarm(int n, void **pp){
** Allocate memory. This routine is like sqlite3_malloc() except that it
** assumes the memory subsystem has already been initialized.
*/
-SQLITE_PRIVATE void *sqlite3Malloc(int n){
+SQLITE_PRIVATE void *sqlite3Malloc(u64 n){
void *p;
- if( n<=0 /* IMP: R-65312-04917 */
- || n>=0x7fffff00
- ){
+ if( n==0 || n>=0x7fffff00 ){
/* A memory allocation of a number of bytes which is near the maximum
** signed integer value might cause an integer overflow inside of the
** xMalloc(). Hence we limit the maximum size to 0x7fffff00, giving
@@ -20050,12 +20829,12 @@ SQLITE_PRIVATE void *sqlite3Malloc(int n){
p = 0;
}else if( sqlite3GlobalConfig.bMemstat ){
sqlite3_mutex_enter(mem0.mutex);
- mallocWithAlarm(n, &p);
+ mallocWithAlarm((int)n, &p);
sqlite3_mutex_leave(mem0.mutex);
}else{
- p = sqlite3GlobalConfig.m.xMalloc(n);
+ p = sqlite3GlobalConfig.m.xMalloc((int)n);
}
- assert( EIGHT_BYTE_ALIGNMENT(p) ); /* IMP: R-04675-44850 */
+ assert( EIGHT_BYTE_ALIGNMENT(p) ); /* IMP: R-11148-40995 */
return p;
}
@@ -20064,7 +20843,13 @@ SQLITE_PRIVATE void *sqlite3Malloc(int n){
** First make sure the memory subsystem is initialized, then do the
** allocation.
*/
-SQLITE_API void *sqlite3_malloc(int n){
+SQLITE_API void *SQLITE_STDCALL sqlite3_malloc(int n){
+#ifndef SQLITE_OMIT_AUTOINIT
+ if( sqlite3_initialize() ) return 0;
+#endif
+ return n<=0 ? 0 : sqlite3Malloc(n);
+}
+SQLITE_API void *SQLITE_STDCALL sqlite3_malloc64(sqlite3_uint64 n){
#ifndef SQLITE_OMIT_AUTOINIT
if( sqlite3_initialize() ) return 0;
#endif
@@ -20095,22 +20880,20 @@ SQLITE_PRIVATE void *sqlite3ScratchMalloc(int n){
assert( n>0 );
sqlite3_mutex_enter(mem0.mutex);
+ sqlite3StatusSet(SQLITE_STATUS_SCRATCH_SIZE, n);
if( mem0.nScratchFree && sqlite3GlobalConfig.szScratch>=n ){
p = mem0.pScratchFree;
mem0.pScratchFree = mem0.pScratchFree->pNext;
mem0.nScratchFree--;
- sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_USED, 1);
- sqlite3StatusSet(SQLITE_STATUS_SCRATCH_SIZE, n);
+ sqlite3StatusUp(SQLITE_STATUS_SCRATCH_USED, 1);
sqlite3_mutex_leave(mem0.mutex);
}else{
- if( sqlite3GlobalConfig.bMemstat ){
- sqlite3StatusSet(SQLITE_STATUS_SCRATCH_SIZE, n);
- n = mallocWithAlarm(n, &p);
- if( p ) sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_OVERFLOW, n);
- sqlite3_mutex_leave(mem0.mutex);
- }else{
+ sqlite3_mutex_leave(mem0.mutex);
+ p = sqlite3Malloc(n);
+ if( sqlite3GlobalConfig.bMemstat && p ){
+ sqlite3_mutex_enter(mem0.mutex);
+ sqlite3StatusUp(SQLITE_STATUS_SCRATCH_OVERFLOW, sqlite3MallocSize(p));
sqlite3_mutex_leave(mem0.mutex);
- p = sqlite3GlobalConfig.m.xMalloc(n);
}
sqlite3MemdebugSetType(p, MEMTYPE_SCRATCH);
}
@@ -20118,11 +20901,12 @@ SQLITE_PRIVATE void *sqlite3ScratchMalloc(int n){
#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
- /* Verify that no more than two scratch allocations per thread
- ** are outstanding at one time. (This is only checked in the
- ** single-threaded case since checking in the multi-threaded case
- ** would be much more complicated.) */
- assert( scratchAllocOut<=1 );
+ /* EVIDENCE-OF: R-12970-05880 SQLite will not use more than one scratch
+ ** buffers per thread.
+ **
+ ** This can only be checked in single-threaded mode.
+ */
+ assert( scratchAllocOut==0 );
if( p ) scratchAllocOut++;
#endif
@@ -20149,19 +20933,19 @@ SQLITE_PRIVATE void sqlite3ScratchFree(void *p){
mem0.pScratchFree = pSlot;
mem0.nScratchFree++;
assert( mem0.nScratchFree <= (u32)sqlite3GlobalConfig.nScratch );
- sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_USED, -1);
+ sqlite3StatusDown(SQLITE_STATUS_SCRATCH_USED, 1);
sqlite3_mutex_leave(mem0.mutex);
}else{
/* Release memory back to the heap */
assert( sqlite3MemdebugHasType(p, MEMTYPE_SCRATCH) );
- assert( sqlite3MemdebugNoType(p, ~MEMTYPE_SCRATCH) );
+ assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_SCRATCH) );
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
if( sqlite3GlobalConfig.bMemstat ){
int iSize = sqlite3MallocSize(p);
sqlite3_mutex_enter(mem0.mutex);
- sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_OVERFLOW, -iSize);
- sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, -iSize);
- sqlite3StatusAdd(SQLITE_STATUS_MALLOC_COUNT, -1);
+ sqlite3StatusDown(SQLITE_STATUS_SCRATCH_OVERFLOW, iSize);
+ sqlite3StatusDown(SQLITE_STATUS_MEMORY_USED, iSize);
+ sqlite3StatusDown(SQLITE_STATUS_MALLOC_COUNT, 1);
sqlite3GlobalConfig.m.xFree(p);
sqlite3_mutex_leave(mem0.mutex);
}else{
@@ -20188,33 +20972,41 @@ static int isLookaside(sqlite3 *db, void *p){
*/
SQLITE_PRIVATE int sqlite3MallocSize(void *p){
assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
- assert( sqlite3MemdebugNoType(p, MEMTYPE_DB) );
return sqlite3GlobalConfig.m.xSize(p);
}
SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){
- assert( db!=0 );
- assert( sqlite3_mutex_held(db->mutex) );
- if( isLookaside(db, p) ){
- return db->lookaside.sz;
+ if( db==0 ){
+ assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
+ assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
+ return sqlite3MallocSize(p);
}else{
- assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) );
- assert( sqlite3MemdebugHasType(p, MEMTYPE_LOOKASIDE|MEMTYPE_HEAP) );
- assert( db!=0 || sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) );
- return sqlite3GlobalConfig.m.xSize(p);
+ assert( sqlite3_mutex_held(db->mutex) );
+ if( isLookaside(db, p) ){
+ return db->lookaside.sz;
+ }else{
+ assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
+ assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
+ return sqlite3GlobalConfig.m.xSize(p);
+ }
}
}
+SQLITE_API sqlite3_uint64 SQLITE_STDCALL sqlite3_msize(void *p){
+ assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
+ assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
+ return (sqlite3_uint64)sqlite3GlobalConfig.m.xSize(p);
+}
/*
** Free memory previously obtained from sqlite3Malloc().
*/
-SQLITE_API void sqlite3_free(void *p){
+SQLITE_API void SQLITE_STDCALL sqlite3_free(void *p){
if( p==0 ) return; /* IMP: R-49053-54554 */
- assert( sqlite3MemdebugNoType(p, MEMTYPE_DB) );
assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
+ assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
if( sqlite3GlobalConfig.bMemstat ){
sqlite3_mutex_enter(mem0.mutex);
- sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, -sqlite3MallocSize(p));
- sqlite3StatusAdd(SQLITE_STATUS_MALLOC_COUNT, -1);
+ sqlite3StatusDown(SQLITE_STATUS_MEMORY_USED, sqlite3MallocSize(p));
+ sqlite3StatusDown(SQLITE_STATUS_MALLOC_COUNT, 1);
sqlite3GlobalConfig.m.xFree(p);
sqlite3_mutex_leave(mem0.mutex);
}else{
@@ -20223,6 +21015,14 @@ SQLITE_API void sqlite3_free(void *p){
}
/*
+** Add the size of memory allocation "p" to the count in
+** *db->pnBytesFreed.
+*/
+static SQLITE_NOINLINE void measureAllocationSize(sqlite3 *db, void *p){
+ *db->pnBytesFreed += sqlite3DbMallocSize(db,p);
+}
+
+/*
** Free memory that might be associated with a particular database
** connection.
*/
@@ -20231,7 +21031,7 @@ SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){
if( p==0 ) return;
if( db ){
if( db->pnBytesFreed ){
- *db->pnBytesFreed += sqlite3DbMallocSize(db, p);
+ measureAllocationSize(db, p);
return;
}
if( isLookaside(db, p) ){
@@ -20246,8 +21046,8 @@ SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){
return;
}
}
- assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) );
- assert( sqlite3MemdebugHasType(p, MEMTYPE_LOOKASIDE|MEMTYPE_HEAP) );
+ assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
+ assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
assert( db!=0 || sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) );
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
sqlite3_free(p);
@@ -20256,14 +21056,16 @@ SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){
/*
** Change the size of an existing memory allocation
*/
-SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, int nBytes){
+SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, u64 nBytes){
int nOld, nNew, nDiff;
void *pNew;
+ assert( sqlite3MemdebugHasType(pOld, MEMTYPE_HEAP) );
+ assert( sqlite3MemdebugNoType(pOld, (u8)~MEMTYPE_HEAP) );
if( pOld==0 ){
- return sqlite3Malloc(nBytes); /* IMP: R-28354-25769 */
+ return sqlite3Malloc(nBytes); /* IMP: R-04300-56712 */
}
- if( nBytes<=0 ){
- sqlite3_free(pOld); /* IMP: R-31593-10574 */
+ if( nBytes==0 ){
+ sqlite3_free(pOld); /* IMP: R-26507-47431 */
return 0;
}
if( nBytes>=0x7fffff00 ){
@@ -20274,33 +21076,31 @@ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, int nBytes){
/* IMPLEMENTATION-OF: R-46199-30249 SQLite guarantees that the second
** argument to xRealloc is always a value returned by a prior call to
** xRoundup. */
- nNew = sqlite3GlobalConfig.m.xRoundup(nBytes);
+ nNew = sqlite3GlobalConfig.m.xRoundup((int)nBytes);
if( nOld==nNew ){
pNew = pOld;
}else if( sqlite3GlobalConfig.bMemstat ){
sqlite3_mutex_enter(mem0.mutex);
- sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, nBytes);
+ sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, (int)nBytes);
nDiff = nNew - nOld;
if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >=
mem0.alarmThreshold-nDiff ){
sqlite3MallocAlarm(nDiff);
}
- assert( sqlite3MemdebugHasType(pOld, MEMTYPE_HEAP) );
- assert( sqlite3MemdebugNoType(pOld, ~MEMTYPE_HEAP) );
pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
if( pNew==0 && mem0.alarmCallback ){
- sqlite3MallocAlarm(nBytes);
+ sqlite3MallocAlarm((int)nBytes);
pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
}
if( pNew ){
nNew = sqlite3MallocSize(pNew);
- sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nNew-nOld);
+ sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nNew-nOld);
}
sqlite3_mutex_leave(mem0.mutex);
}else{
pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
}
- assert( EIGHT_BYTE_ALIGNMENT(pNew) ); /* IMP: R-04675-44850 */
+ assert( EIGHT_BYTE_ALIGNMENT(pNew) ); /* IMP: R-11148-40995 */
return pNew;
}
@@ -20308,7 +21108,14 @@ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, int nBytes){
** The public interface to sqlite3Realloc. Make sure that the memory
** subsystem is initialized prior to invoking sqliteRealloc.
*/
-SQLITE_API void *sqlite3_realloc(void *pOld, int n){
+SQLITE_API void *SQLITE_STDCALL sqlite3_realloc(void *pOld, int n){
+#ifndef SQLITE_OMIT_AUTOINIT
+ if( sqlite3_initialize() ) return 0;
+#endif
+ if( n<0 ) n = 0; /* IMP: R-26507-47431 */
+ return sqlite3Realloc(pOld, n);
+}
+SQLITE_API void *SQLITE_STDCALL sqlite3_realloc64(void *pOld, sqlite3_uint64 n){
#ifndef SQLITE_OMIT_AUTOINIT
if( sqlite3_initialize() ) return 0;
#endif
@@ -20319,10 +21126,10 @@ SQLITE_API void *sqlite3_realloc(void *pOld, int n){
/*
** Allocate and zero memory.
*/
-SQLITE_PRIVATE void *sqlite3MallocZero(int n){
+SQLITE_PRIVATE void *sqlite3MallocZero(u64 n){
void *p = sqlite3Malloc(n);
if( p ){
- memset(p, 0, n);
+ memset(p, 0, (size_t)n);
}
return p;
}
@@ -20331,10 +21138,10 @@ SQLITE_PRIVATE void *sqlite3MallocZero(int n){
** Allocate and zero memory. If the allocation fails, make
** the mallocFailed flag in the connection pointer.
*/
-SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3 *db, int n){
+SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3 *db, u64 n){
void *p = sqlite3DbMallocRaw(db, n);
if( p ){
- memset(p, 0, n);
+ memset(p, 0, (size_t)n);
}
return p;
}
@@ -20357,7 +21164,7 @@ SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3 *db, int n){
** In other words, if a subsequent malloc (ex: "b") worked, it is assumed
** that all prior mallocs (ex: "a") worked too.
*/
-SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3 *db, int n){
+SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3 *db, u64 n){
void *p;
assert( db==0 || sqlite3_mutex_held(db->mutex) );
assert( db==0 || db->pnBytesFreed==0 );
@@ -20392,8 +21199,8 @@ SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3 *db, int n){
if( !p && db ){
db->mallocFailed = 1;
}
- sqlite3MemdebugSetType(p, MEMTYPE_DB |
- ((db && db->lookaside.bEnabled) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP));
+ sqlite3MemdebugSetType(p,
+ (db && db->lookaside.bEnabled) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP);
return p;
}
@@ -20401,7 +21208,7 @@ SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3 *db, int n){
** Resize the block of memory pointed to by p to n bytes. If the
** resize fails, set the mallocFailed flag in the connection object.
*/
-SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *db, void *p, int n){
+SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *db, void *p, u64 n){
void *pNew = 0;
assert( db!=0 );
assert( sqlite3_mutex_held(db->mutex) );
@@ -20419,15 +21226,14 @@ SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *db, void *p, int n){
sqlite3DbFree(db, p);
}
}else{
- assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) );
- assert( sqlite3MemdebugHasType(p, MEMTYPE_LOOKASIDE|MEMTYPE_HEAP) );
+ assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
+ assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
- pNew = sqlite3_realloc(p, n);
+ pNew = sqlite3_realloc64(p, n);
if( !pNew ){
- sqlite3MemdebugSetType(p, MEMTYPE_DB|MEMTYPE_HEAP);
db->mallocFailed = 1;
}
- sqlite3MemdebugSetType(pNew, MEMTYPE_DB |
+ sqlite3MemdebugSetType(pNew,
(db->lookaside.bEnabled ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP));
}
}
@@ -20438,7 +21244,7 @@ SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *db, void *p, int n){
** Attempt to reallocate p. If the reallocation fails, then free p
** and set the mallocFailed flag in the database connection.
*/
-SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *db, void *p, int n){
+SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *db, void *p, u64 n){
void *pNew;
pNew = sqlite3DbRealloc(db, p, n);
if( !pNew ){
@@ -20468,7 +21274,7 @@ SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3 *db, const char *z){
}
return zNew;
}
-SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3 *db, const char *z, int n){
+SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){
char *zNew;
if( z==0 ){
return 0;
@@ -20476,7 +21282,7 @@ SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3 *db, const char *z, int n){
assert( (n&0x7fffffff)==n );
zNew = sqlite3DbMallocRaw(db, n+1);
if( zNew ){
- memcpy(zNew, z, n);
+ memcpy(zNew, z, (size_t)n);
zNew[n] = 0;
}
return zNew;
@@ -20498,6 +21304,14 @@ SQLITE_PRIVATE void sqlite3SetString(char **pz, sqlite3 *db, const char *zFormat
*pz = z;
}
+/*
+** Take actions at the end of an API call to indicate an OOM error
+*/
+static SQLITE_NOINLINE int apiOomError(sqlite3 *db){
+ db->mallocFailed = 0;
+ sqlite3Error(db, SQLITE_NOMEM);
+ return SQLITE_NOMEM;
+}
/*
** This function must be called before exiting any API function (i.e.
@@ -20518,12 +21332,11 @@ SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){
** is unsafe, as is the call to sqlite3Error().
*/
assert( !db || sqlite3_mutex_held(db->mutex) );
- if( db && (db->mallocFailed || rc==SQLITE_IOERR_NOMEM) ){
- sqlite3Error(db, SQLITE_NOMEM, 0);
- db->mallocFailed = 0;
- rc = SQLITE_NOMEM;
+ if( db==0 ) return rc & 0xff;
+ if( db->mallocFailed || rc==SQLITE_IOERR_NOMEM ){
+ return apiOomError(db);
}
- return rc & (db ? db->errMask : 0xff);
+ return rc & db->errMask;
}
/************** End of malloc.c **********************************************/
@@ -20667,6 +21480,7 @@ static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
** Set the StrAccum object to an error mode.
*/
static void setStrAccumError(StrAccum *p, u8 eError){
+ assert( eError==STRACCUM_NOMEM || eError==STRACCUM_TOOBIG );
p->accError = eError;
p->nAlloc = 0;
}
@@ -20730,7 +21544,7 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
const et_info *infop; /* Pointer to the appropriate info structure */
char *zOut; /* Rendering buffer */
int nOut; /* Size of the rendering buffer */
- char *zExtra; /* Malloced memory used by some conversion */
+ char *zExtra = 0; /* Malloced memory used by some conversion */
#ifndef SQLITE_OMIT_FLOATING_POINT
int exp, e2; /* exponent of real numbers */
int nsd; /* Number of significant digits returned */
@@ -20753,9 +21567,13 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
for(; (c=(*fmt))!=0; ++fmt){
if( c!='%' ){
bufpt = (char *)fmt;
- while( (c=(*++fmt))!='%' && c!=0 ){};
+#if HAVE_STRCHRNUL
+ fmt = strchrnul(fmt, '%');
+#else
+ do{ fmt++; }while( *fmt && *fmt != '%' );
+#endif
sqlite3StrAccumAppend(pAccum, bufpt, (int)(fmt - bufpt));
- if( c==0 ) break;
+ if( *fmt==0 ) break;
}
if( (c=(*++fmt))==0 ){
sqlite3StrAccumAppend(pAccum, "%", 1);
@@ -20777,7 +21595,6 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
}
}while( !done && (c=(*++fmt))!=0 );
/* Get the field width */
- width = 0;
if( c=='*' ){
if( bArgList ){
width = (int)getIntArg(pArgList);
@@ -20786,18 +21603,21 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
}
if( width<0 ){
flag_leftjustify = 1;
- width = -width;
+ width = width >= -2147483647 ? -width : 0;
}
c = *++fmt;
}else{
+ unsigned wx = 0;
while( c>='0' && c<='9' ){
- width = width*10 + c - '0';
+ wx = wx*10 + c - '0';
c = *++fmt;
}
+ testcase( wx>0x7fffffff );
+ width = wx & 0x7fffffff;
}
+
/* Get the precision */
if( c=='.' ){
- precision = 0;
c = *++fmt;
if( c=='*' ){
if( bArgList ){
@@ -20805,13 +21625,18 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
}else{
precision = va_arg(ap,int);
}
- if( precision<0 ) precision = -precision;
c = *++fmt;
+ if( precision<0 ){
+ precision = precision >= -2147483647 ? -precision : -1;
+ }
}else{
+ unsigned px = 0;
while( c>='0' && c<='9' ){
- precision = precision*10 + c - '0';
+ px = px*10 + c - '0';
c = *++fmt;
}
+ testcase( px>0x7fffffff );
+ precision = px & 0x7fffffff;
}
}else{
precision = -1;
@@ -20843,7 +21668,6 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
break;
}
}
- zExtra = 0;
/*
** At this point, variables are initialized as follows:
@@ -20976,7 +21800,8 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
else prefix = 0;
}
if( xtype==etGENERIC && precision>0 ) precision--;
- for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1){}
+ testcase( precision>0xfff );
+ for(idx=precision&0xfff, rounder=0.5; idx>0; idx--, rounder*=0.1){}
if( xtype==etFLOAT ) realvalue += rounder;
/* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
exp = 0;
@@ -21031,8 +21856,9 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
}else{
e2 = exp;
}
- if( MAX(e2,0)+precision+width > etBUFSIZE - 15 ){
- bufpt = zExtra = sqlite3Malloc( MAX(e2,0)+precision+width+15 );
+ if( MAX(e2,0)+(i64)precision+(i64)width > etBUFSIZE - 15 ){
+ bufpt = zExtra
+ = sqlite3Malloc( MAX(e2,0)+(i64)precision+(i64)width+15 );
if( bufpt==0 ){
setStrAccumError(pAccum, STRACCUM_NOMEM);
return;
@@ -21134,13 +21960,16 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
}else{
c = va_arg(ap,int);
}
- buf[0] = (char)c;
- if( precision>=0 ){
- for(idx=1; idx<precision; idx++) buf[idx] = (char)c;
- length = precision;
- }else{
- length =1;
+ if( precision>1 ){
+ width -= precision-1;
+ if( width>1 && !flag_leftjustify ){
+ sqlite3AppendChar(pAccum, width-1, ' ');
+ width = 0;
+ }
+ sqlite3AppendChar(pAccum, precision-1, c);
}
+ length = 1;
+ buf[0] = c;
bufpt = buf;
break;
case etSTRING:
@@ -21241,11 +22070,14 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
** the output.
*/
width -= length;
- if( width>0 && !flag_leftjustify ) sqlite3AppendSpace(pAccum, width);
+ if( width>0 && !flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' ');
sqlite3StrAccumAppend(pAccum, bufpt, length);
- if( width>0 && flag_leftjustify ) sqlite3AppendSpace(pAccum, width);
+ if( width>0 && flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' ');
- if( zExtra ) sqlite3_free(zExtra);
+ if( zExtra ){
+ sqlite3_free(zExtra);
+ zExtra = 0;
+ }
}/* End for loop over the format string */
} /* End of function */
@@ -21258,13 +22090,13 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
*/
static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
char *zNew;
- assert( p->nChar+N >= p->nAlloc ); /* Only called if really needed */
+ assert( p->nChar+(i64)N >= p->nAlloc ); /* Only called if really needed */
if( p->accError ){
testcase(p->accError==STRACCUM_TOOBIG);
testcase(p->accError==STRACCUM_NOMEM);
return 0;
}
- if( !p->useMalloc ){
+ if( p->mxAlloc==0 ){
N = p->nAlloc - p->nChar - 1;
setStrAccumError(p, STRACCUM_TOOBIG);
return N;
@@ -21272,6 +22104,11 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
char *zOld = (p->zText==p->zBase ? 0 : p->zText);
i64 szNew = p->nChar;
szNew += N + 1;
+ if( szNew+p->nChar<=p->mxAlloc ){
+ /* Force exponential buffer size growth as long as it does not overflow,
+ ** to avoid having to call this routine too often */
+ szNew += p->nChar;
+ }
if( szNew > p->mxAlloc ){
sqlite3StrAccumReset(p);
setStrAccumError(p, STRACCUM_TOOBIG);
@@ -21279,15 +22116,16 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
}else{
p->nAlloc = (int)szNew;
}
- if( p->useMalloc==1 ){
+ if( p->db ){
zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc);
}else{
- zNew = sqlite3_realloc(zOld, p->nAlloc);
+ zNew = sqlite3_realloc64(zOld, p->nAlloc);
}
if( zNew ){
assert( p->zText!=0 || p->nChar==0 );
if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar);
p->zText = zNew;
+ p->nAlloc = sqlite3DbMallocSize(p->db, zNew);
}else{
sqlite3StrAccumReset(p);
setStrAccumError(p, STRACCUM_NOMEM);
@@ -21298,11 +22136,14 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
}
/*
-** Append N space characters to the given string buffer.
+** Append N copies of character c to the given string buffer.
*/
-SQLITE_PRIVATE void sqlite3AppendSpace(StrAccum *p, int N){
- if( p->nChar+N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ) return;
- while( (N--)>0 ) p->zText[p->nChar++] = ' ';
+SQLITE_PRIVATE void sqlite3AppendChar(StrAccum *p, int N, char c){
+ testcase( p->nChar + (i64)N > 0x7fffffff );
+ if( p->nChar+(i64)N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ){
+ return;
+ }
+ while( (N--)>0 ) p->zText[p->nChar++] = c;
}
/*
@@ -21313,7 +22154,7 @@ SQLITE_PRIVATE void sqlite3AppendSpace(StrAccum *p, int N){
** work (enlarging the buffer) using tail recursion, so that the
** sqlite3StrAccumAppend() routine can use fast calling semantics.
*/
-static void enlargeAndAppend(StrAccum *p, const char *z, int N){
+static void SQLITE_NOINLINE enlargeAndAppend(StrAccum *p, const char *z, int N){
N = sqlite3StrAccumEnlarge(p, N);
if( N>0 ){
memcpy(&p->zText[p->nChar], z, N);
@@ -21326,17 +22167,17 @@ static void enlargeAndAppend(StrAccum *p, const char *z, int N){
** size of the memory allocation for StrAccum if necessary.
*/
SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
- assert( z!=0 );
+ assert( z!=0 || N==0 );
assert( p->zText!=0 || p->nChar==0 || p->accError );
assert( N>=0 );
assert( p->accError==0 || p->nAlloc==0 );
if( p->nChar+N >= p->nAlloc ){
enlargeAndAppend(p,z,N);
- return;
+ }else{
+ assert( p->zText );
+ p->nChar += N;
+ memcpy(&p->zText[p->nChar-N], z, N);
}
- assert( p->zText );
- memcpy(&p->zText[p->nChar], z, N);
- p->nChar += N;
}
/*
@@ -21355,12 +22196,8 @@ SQLITE_PRIVATE void sqlite3StrAccumAppendAll(StrAccum *p, const char *z){
SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum *p){
if( p->zText ){
p->zText[p->nChar] = 0;
- if( p->useMalloc && p->zText==p->zBase ){
- if( p->useMalloc==1 ){
- p->zText = sqlite3DbMallocRaw(p->db, p->nChar+1 );
- }else{
- p->zText = sqlite3_malloc(p->nChar+1);
- }
+ if( p->mxAlloc>0 && p->zText==p->zBase ){
+ p->zText = sqlite3DbMallocRaw(p->db, p->nChar+1 );
if( p->zText ){
memcpy(p->zText, p->zBase, p->nChar+1);
}else{
@@ -21376,25 +22213,31 @@ SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum *p){
*/
SQLITE_PRIVATE void sqlite3StrAccumReset(StrAccum *p){
if( p->zText!=p->zBase ){
- if( p->useMalloc==1 ){
- sqlite3DbFree(p->db, p->zText);
- }else{
- sqlite3_free(p->zText);
- }
+ sqlite3DbFree(p->db, p->zText);
}
p->zText = 0;
}
/*
-** Initialize a string accumulator
+** Initialize a string accumulator.
+**
+** p: The accumulator to be initialized.
+** db: Pointer to a database connection. May be NULL. Lookaside
+** memory is used if not NULL. db->mallocFailed is set appropriately
+** when not NULL.
+** zBase: An initial buffer. May be NULL in which case the initial buffer
+** is malloced.
+** n: Size of zBase in bytes. If total space requirements never exceed
+** n then no memory allocations ever occur.
+** mx: Maximum number of bytes to accumulate. If mx==0 then no memory
+** allocations will ever occur.
*/
-SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum *p, char *zBase, int n, int mx){
+SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum *p, sqlite3 *db, char *zBase, int n, int mx){
p->zText = p->zBase = zBase;
- p->db = 0;
+ p->db = db;
p->nChar = 0;
p->nAlloc = n;
p->mxAlloc = mx;
- p->useMalloc = 1;
p->accError = 0;
}
@@ -21407,9 +22250,8 @@ SQLITE_PRIVATE char *sqlite3VMPrintf(sqlite3 *db, const char *zFormat, va_list a
char zBase[SQLITE_PRINT_BUF_SIZE];
StrAccum acc;
assert( db!=0 );
- sqlite3StrAccumInit(&acc, zBase, sizeof(zBase),
+ sqlite3StrAccumInit(&acc, db, zBase, sizeof(zBase),
db->aLimit[SQLITE_LIMIT_LENGTH]);
- acc.db = db;
sqlite3VXPrintf(&acc, SQLITE_PRINTF_INTERNAL, zFormat, ap);
z = sqlite3StrAccumFinish(&acc);
if( acc.accError==STRACCUM_NOMEM ){
@@ -21433,7 +22275,7 @@ SQLITE_PRIVATE char *sqlite3MPrintf(sqlite3 *db, const char *zFormat, ...){
/*
** Like sqlite3MPrintf(), but call sqlite3DbFree() on zStr after formatting
-** the string and before returnning. This routine is intended to be used
+** the string and before returning. This routine is intended to be used
** to modify an existing string. For example:
**
** x = sqlite3MPrintf(db, x, "prefix %s suffix", x);
@@ -21453,15 +22295,21 @@ SQLITE_PRIVATE char *sqlite3MAppendf(sqlite3 *db, char *zStr, const char *zForma
** Print into memory obtained from sqlite3_malloc(). Omit the internal
** %-conversion extensions.
*/
-SQLITE_API char *sqlite3_vmprintf(const char *zFormat, va_list ap){
+SQLITE_API char *SQLITE_STDCALL sqlite3_vmprintf(const char *zFormat, va_list ap){
char *z;
char zBase[SQLITE_PRINT_BUF_SIZE];
StrAccum acc;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( zFormat==0 ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
#ifndef SQLITE_OMIT_AUTOINIT
if( sqlite3_initialize() ) return 0;
#endif
- sqlite3StrAccumInit(&acc, zBase, sizeof(zBase), SQLITE_MAX_LENGTH);
- acc.useMalloc = 2;
+ sqlite3StrAccumInit(&acc, 0, zBase, sizeof(zBase), SQLITE_MAX_LENGTH);
sqlite3VXPrintf(&acc, 0, zFormat, ap);
z = sqlite3StrAccumFinish(&acc);
return z;
@@ -21471,7 +22319,7 @@ SQLITE_API char *sqlite3_vmprintf(const char *zFormat, va_list ap){
** Print into memory obtained from sqlite3_malloc()(). Omit the internal
** %-conversion extensions.
*/
-SQLITE_API char *sqlite3_mprintf(const char *zFormat, ...){
+SQLITE_API char *SQLITE_CDECL sqlite3_mprintf(const char *zFormat, ...){
va_list ap;
char *z;
#ifndef SQLITE_OMIT_AUTOINIT
@@ -21496,15 +22344,21 @@ SQLITE_API char *sqlite3_mprintf(const char *zFormat, ...){
**
** sqlite3_vsnprintf() is the varargs version.
*/
-SQLITE_API char *sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_list ap){
+SQLITE_API char *SQLITE_STDCALL sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_list ap){
StrAccum acc;
if( n<=0 ) return zBuf;
- sqlite3StrAccumInit(&acc, zBuf, n, 0);
- acc.useMalloc = 0;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( zBuf==0 || zFormat==0 ) {
+ (void)SQLITE_MISUSE_BKPT;
+ if( zBuf ) zBuf[0] = 0;
+ return zBuf;
+ }
+#endif
+ sqlite3StrAccumInit(&acc, 0, zBuf, n, 0);
sqlite3VXPrintf(&acc, 0, zFormat, ap);
return sqlite3StrAccumFinish(&acc);
}
-SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
+SQLITE_API char *SQLITE_CDECL sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
char *z;
va_list ap;
va_start(ap,zFormat);
@@ -21526,8 +22380,7 @@ static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){
StrAccum acc; /* String accumulator */
char zMsg[SQLITE_PRINT_BUF_SIZE*3]; /* Complete log message */
- sqlite3StrAccumInit(&acc, zMsg, sizeof(zMsg), 0);
- acc.useMalloc = 0;
+ sqlite3StrAccumInit(&acc, 0, zMsg, sizeof(zMsg), 0);
sqlite3VXPrintf(&acc, 0, zFormat, ap);
sqlite3GlobalConfig.xLog(sqlite3GlobalConfig.pLogArg, iErrCode,
sqlite3StrAccumFinish(&acc));
@@ -21536,7 +22389,7 @@ static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){
/*
** Format and write a message to the log if logging is enabled.
*/
-SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...){
+SQLITE_API void SQLITE_CDECL sqlite3_log(int iErrCode, const char *zFormat, ...){
va_list ap; /* Vararg list */
if( sqlite3GlobalConfig.xLog ){
va_start(ap, zFormat);
@@ -21545,7 +22398,7 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...){
}
}
-#if defined(SQLITE_DEBUG)
+#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
/*
** A version of printf() that understands %lld. Used for debugging.
** The printf() built into some versions of windows does not understand %lld
@@ -21555,8 +22408,7 @@ SQLITE_PRIVATE void sqlite3DebugPrintf(const char *zFormat, ...){
va_list ap;
StrAccum acc;
char zBuf[500];
- sqlite3StrAccumInit(&acc, zBuf, sizeof(zBuf), 0);
- acc.useMalloc = 0;
+ sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
va_start(ap,zFormat);
sqlite3VXPrintf(&acc, 0, zFormat, ap);
va_end(ap);
@@ -21566,6 +22418,68 @@ SQLITE_PRIVATE void sqlite3DebugPrintf(const char *zFormat, ...){
}
#endif
+#ifdef SQLITE_DEBUG
+/*************************************************************************
+** Routines for implementing the "TreeView" display of hierarchical
+** data structures for debugging.
+**
+** The main entry points (coded elsewhere) are:
+** sqlite3TreeViewExpr(0, pExpr, 0);
+** sqlite3TreeViewExprList(0, pList, 0, 0);
+** sqlite3TreeViewSelect(0, pSelect, 0);
+** Insert calls to those routines while debugging in order to display
+** a diagram of Expr, ExprList, and Select objects.
+**
+*/
+/* Add a new subitem to the tree. The moreToFollow flag indicates that this
+** is not the last item in the tree. */
+SQLITE_PRIVATE TreeView *sqlite3TreeViewPush(TreeView *p, u8 moreToFollow){
+ if( p==0 ){
+ p = sqlite3_malloc64( sizeof(*p) );
+ if( p==0 ) return 0;
+ memset(p, 0, sizeof(*p));
+ }else{
+ p->iLevel++;
+ }
+ assert( moreToFollow==0 || moreToFollow==1 );
+ if( p->iLevel<sizeof(p->bLine) ) p->bLine[p->iLevel] = moreToFollow;
+ return p;
+}
+/* Finished with one layer of the tree */
+SQLITE_PRIVATE void sqlite3TreeViewPop(TreeView *p){
+ if( p==0 ) return;
+ p->iLevel--;
+ if( p->iLevel<0 ) sqlite3_free(p);
+}
+/* Generate a single line of output for the tree, with a prefix that contains
+** all the appropriate tree lines */
+SQLITE_PRIVATE void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){
+ va_list ap;
+ int i;
+ StrAccum acc;
+ char zBuf[500];
+ sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
+ if( p ){
+ for(i=0; i<p->iLevel && i<sizeof(p->bLine)-1; i++){
+ sqlite3StrAccumAppend(&acc, p->bLine[i] ? "| " : " ", 4);
+ }
+ sqlite3StrAccumAppend(&acc, p->bLine[i] ? "|-- " : "'-- ", 4);
+ }
+ va_start(ap, zFormat);
+ sqlite3VXPrintf(&acc, 0, zFormat, ap);
+ va_end(ap);
+ if( zBuf[acc.nChar-1]!='\n' ) sqlite3StrAccumAppend(&acc, "\n", 1);
+ sqlite3StrAccumFinish(&acc);
+ fprintf(stdout,"%s", zBuf);
+ fflush(stdout);
+}
+/* Shorthand for starting a new tree item that consists of a single label */
+SQLITE_PRIVATE void sqlite3TreeViewItem(TreeView *p, const char *zLabel, u8 moreToFollow){
+ p = sqlite3TreeViewPush(p, moreToFollow);
+ sqlite3TreeViewLine(p, "%s", zLabel);
+}
+#endif /* SQLITE_DEBUG */
+
/*
** variable-argument wrapper around sqlite3VXPrintf().
*/
@@ -21609,7 +22523,7 @@ static SQLITE_WSD struct sqlite3PrngType {
/*
** Return N random bytes.
*/
-SQLITE_API void sqlite3_randomness(int N, void *pBuf){
+SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *pBuf){
unsigned char t;
unsigned char *zBuf = pBuf;
@@ -21627,11 +22541,19 @@ SQLITE_API void sqlite3_randomness(int N, void *pBuf){
#endif
#if SQLITE_THREADSAFE
- sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PRNG);
- sqlite3_mutex_enter(mutex);
+ sqlite3_mutex *mutex;
+#endif
+
+#ifndef SQLITE_OMIT_AUTOINIT
+ if( sqlite3_initialize() ) return;
#endif
- if( N<=0 ){
+#if SQLITE_THREADSAFE
+ mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PRNG);
+#endif
+
+ sqlite3_mutex_enter(mutex);
+ if( N<=0 || pBuf==0 ){
wsdPrng.isInit = 0;
sqlite3_mutex_leave(mutex);
return;
@@ -21705,6 +22627,272 @@ SQLITE_PRIVATE void sqlite3PrngRestoreState(void){
#endif /* SQLITE_OMIT_BUILTIN_TEST */
/************** End of random.c **********************************************/
+/************** Begin file threads.c *****************************************/
+/*
+** 2012 July 21
+**
+** 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 presents a simple cross-platform threading interface for
+** use internally by SQLite.
+**
+** A "thread" can be created using sqlite3ThreadCreate(). This thread
+** runs independently of its creator until it is joined using
+** sqlite3ThreadJoin(), at which point it terminates.
+**
+** Threads do not have to be real. It could be that the work of the
+** "thread" is done by the main thread at either the sqlite3ThreadCreate()
+** or sqlite3ThreadJoin() call. This is, in fact, what happens in
+** single threaded systems. Nothing in SQLite requires multiple threads.
+** This interface exists so that applications that want to take advantage
+** of multiple cores can do so, while also allowing applications to stay
+** single-threaded if desired.
+*/
+#if SQLITE_OS_WIN
+#endif
+
+#if SQLITE_MAX_WORKER_THREADS>0
+
+/********************************* Unix Pthreads ****************************/
+#if SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) && SQLITE_THREADSAFE>0
+
+#define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */
+/* #include <pthread.h> */
+
+/* A running thread */
+struct SQLiteThread {
+ pthread_t tid; /* Thread ID */
+ int done; /* Set to true when thread finishes */
+ void *pOut; /* Result returned by the thread */
+ void *(*xTask)(void*); /* The thread routine */
+ void *pIn; /* Argument to the thread */
+};
+
+/* Create a new thread */
+SQLITE_PRIVATE int sqlite3ThreadCreate(
+ SQLiteThread **ppThread, /* OUT: Write the thread object here */
+ void *(*xTask)(void*), /* Routine to run in a separate thread */
+ void *pIn /* Argument passed into xTask() */
+){
+ SQLiteThread *p;
+ int rc;
+
+ assert( ppThread!=0 );
+ assert( xTask!=0 );
+ /* This routine is never used in single-threaded mode */
+ assert( sqlite3GlobalConfig.bCoreMutex!=0 );
+
+ *ppThread = 0;
+ p = sqlite3Malloc(sizeof(*p));
+ if( p==0 ) return SQLITE_NOMEM;
+ memset(p, 0, sizeof(*p));
+ p->xTask = xTask;
+ p->pIn = pIn;
+ if( sqlite3FaultSim(200) ){
+ rc = 1;
+ }else{
+ rc = pthread_create(&p->tid, 0, xTask, pIn);
+ }
+ if( rc ){
+ p->done = 1;
+ p->pOut = xTask(pIn);
+ }
+ *ppThread = p;
+ return SQLITE_OK;
+}
+
+/* Get the results of the thread */
+SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
+ int rc;
+
+ assert( ppOut!=0 );
+ if( NEVER(p==0) ) return SQLITE_NOMEM;
+ if( p->done ){
+ *ppOut = p->pOut;
+ rc = SQLITE_OK;
+ }else{
+ rc = pthread_join(p->tid, ppOut) ? SQLITE_ERROR : SQLITE_OK;
+ }
+ sqlite3_free(p);
+ return rc;
+}
+
+#endif /* SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) */
+/******************************** End Unix Pthreads *************************/
+
+
+/********************************* Win32 Threads ****************************/
+#if SQLITE_OS_WIN_THREADS
+
+#define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */
+#include <process.h>
+
+/* A running thread */
+struct SQLiteThread {
+ void *tid; /* The thread handle */
+ unsigned id; /* The thread identifier */
+ void *(*xTask)(void*); /* The routine to run as a thread */
+ void *pIn; /* Argument to xTask */
+ void *pResult; /* Result of xTask */
+};
+
+/* Thread procedure Win32 compatibility shim */
+static unsigned __stdcall sqlite3ThreadProc(
+ void *pArg /* IN: Pointer to the SQLiteThread structure */
+){
+ SQLiteThread *p = (SQLiteThread *)pArg;
+
+ assert( p!=0 );
+#if 0
+ /*
+ ** This assert appears to trigger spuriously on certain
+ ** versions of Windows, possibly due to _beginthreadex()
+ ** and/or CreateThread() not fully setting their thread
+ ** ID parameter before starting the thread.
+ */
+ assert( p->id==GetCurrentThreadId() );
+#endif
+ assert( p->xTask!=0 );
+ p->pResult = p->xTask(p->pIn);
+
+ _endthreadex(0);
+ return 0; /* NOT REACHED */
+}
+
+/* Create a new thread */
+SQLITE_PRIVATE int sqlite3ThreadCreate(
+ SQLiteThread **ppThread, /* OUT: Write the thread object here */
+ void *(*xTask)(void*), /* Routine to run in a separate thread */
+ void *pIn /* Argument passed into xTask() */
+){
+ SQLiteThread *p;
+
+ assert( ppThread!=0 );
+ assert( xTask!=0 );
+ *ppThread = 0;
+ p = sqlite3Malloc(sizeof(*p));
+ if( p==0 ) return SQLITE_NOMEM;
+ if( sqlite3GlobalConfig.bCoreMutex==0 ){
+ memset(p, 0, sizeof(*p));
+ }else{
+ p->xTask = xTask;
+ p->pIn = pIn;
+ p->tid = (void*)_beginthreadex(0, 0, sqlite3ThreadProc, p, 0, &p->id);
+ if( p->tid==0 ){
+ memset(p, 0, sizeof(*p));
+ }
+ }
+ if( p->xTask==0 ){
+ p->id = GetCurrentThreadId();
+ p->pResult = xTask(pIn);
+ }
+ *ppThread = p;
+ return SQLITE_OK;
+}
+
+SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject); /* os_win.c */
+
+/* Get the results of the thread */
+SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
+ DWORD rc;
+ BOOL bRc;
+
+ assert( ppOut!=0 );
+ if( NEVER(p==0) ) return SQLITE_NOMEM;
+ if( p->xTask==0 ){
+ assert( p->id==GetCurrentThreadId() );
+ rc = WAIT_OBJECT_0;
+ assert( p->tid==0 );
+ }else{
+ assert( p->id!=0 && p->id!=GetCurrentThreadId() );
+ rc = sqlite3Win32Wait((HANDLE)p->tid);
+ assert( rc!=WAIT_IO_COMPLETION );
+ bRc = CloseHandle((HANDLE)p->tid);
+ assert( bRc );
+ }
+ if( rc==WAIT_OBJECT_0 ) *ppOut = p->pResult;
+ sqlite3_free(p);
+ return (rc==WAIT_OBJECT_0) ? SQLITE_OK : SQLITE_ERROR;
+}
+
+#endif /* SQLITE_OS_WIN_THREADS */
+/******************************** End Win32 Threads *************************/
+
+
+/********************************* Single-Threaded **************************/
+#ifndef SQLITE_THREADS_IMPLEMENTED
+/*
+** This implementation does not actually create a new thread. It does the
+** work of the thread in the main thread, when either the thread is created
+** or when it is joined
+*/
+
+/* A running thread */
+struct SQLiteThread {
+ void *(*xTask)(void*); /* The routine to run as a thread */
+ void *pIn; /* Argument to xTask */
+ void *pResult; /* Result of xTask */
+};
+
+/* Create a new thread */
+SQLITE_PRIVATE int sqlite3ThreadCreate(
+ SQLiteThread **ppThread, /* OUT: Write the thread object here */
+ void *(*xTask)(void*), /* Routine to run in a separate thread */
+ void *pIn /* Argument passed into xTask() */
+){
+ SQLiteThread *p;
+
+ assert( ppThread!=0 );
+ assert( xTask!=0 );
+ *ppThread = 0;
+ p = sqlite3Malloc(sizeof(*p));
+ if( p==0 ) return SQLITE_NOMEM;
+ if( (SQLITE_PTR_TO_INT(p)/17)&1 ){
+ p->xTask = xTask;
+ p->pIn = pIn;
+ }else{
+ p->xTask = 0;
+ p->pResult = xTask(pIn);
+ }
+ *ppThread = p;
+ return SQLITE_OK;
+}
+
+/* Get the results of the thread */
+SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
+
+ assert( ppOut!=0 );
+ if( NEVER(p==0) ) return SQLITE_NOMEM;
+ if( p->xTask ){
+ *ppOut = p->xTask(p->pIn);
+ }else{
+ *ppOut = p->pResult;
+ }
+ sqlite3_free(p);
+
+#if defined(SQLITE_TEST)
+ {
+ void *pTstAlloc = sqlite3Malloc(10);
+ if (!pTstAlloc) return SQLITE_NOMEM;
+ sqlite3_free(pTstAlloc);
+ }
+#endif
+
+ return SQLITE_OK;
+}
+
+#endif /* !defined(SQLITE_THREADS_IMPLEMENTED) */
+/****************************** End Single-Threaded *************************/
+#endif /* SQLITE_MAX_WORKER_THREADS>0 */
+
+/************** End of threads.c *********************************************/
/************** Begin file utf.c *********************************************/
/*
** 2004 April 13
@@ -21905,7 +23093,7 @@ SQLITE_PRIVATE u32 sqlite3Utf8Read(
** desiredEnc. It is an error if the string is already of the desired
** encoding, or if *pMem does not contain a string value.
*/
-SQLITE_PRIVATE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
+SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
int len; /* Maximum length of output string in bytes */
unsigned char *zOut; /* Output buffer */
unsigned char *zIn; /* Input iterator */
@@ -22020,12 +23208,13 @@ SQLITE_PRIVATE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
*z = 0;
assert( (pMem->n+(desiredEnc==SQLITE_UTF8?1:2))<=len );
+ c = pMem->flags;
sqlite3VdbeMemRelease(pMem);
- pMem->flags &= ~(MEM_Static|MEM_Dyn|MEM_Ephem);
+ pMem->flags = MEM_Str|MEM_Term|(c&MEM_AffMask);
pMem->enc = desiredEnc;
- pMem->flags |= (MEM_Term);
pMem->z = (char*)zOut;
pMem->zMalloc = pMem->z;
+ pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->z);
translate_out:
#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG)
@@ -22254,7 +23443,7 @@ SQLITE_PRIVATE void sqlite3UtfSelfTest(void){
**
*/
/* #include <stdarg.h> */
-#ifdef SQLITE_HAVE_ISNAN
+#if HAVE_ISNAN || SQLITE_HAVE_ISNAN
# include <math.h>
#endif
@@ -22295,7 +23484,7 @@ SQLITE_PRIVATE int sqlite3FaultSim(int iTest){
*/
SQLITE_PRIVATE int sqlite3IsNaN(double x){
int rc; /* The value return */
-#if !defined(SQLITE_HAVE_ISNAN)
+#if !SQLITE_HAVE_ISNAN && !HAVE_ISNAN
/*
** Systems that support the isnan() library function should probably
** make use of it by compiling with -DSQLITE_HAVE_ISNAN. But we have
@@ -22325,9 +23514,9 @@ SQLITE_PRIVATE int sqlite3IsNaN(double x){
volatile double y = x;
volatile double z = y;
rc = (y!=z);
-#else /* if defined(SQLITE_HAVE_ISNAN) */
+#else /* if HAVE_ISNAN */
rc = isnan(x);
-#endif /* SQLITE_HAVE_ISNAN */
+#endif /* HAVE_ISNAN */
testcase( rc );
return rc;
}
@@ -22349,6 +23538,15 @@ SQLITE_PRIVATE int sqlite3Strlen30(const char *z){
}
/*
+** Set the current error code to err_code and clear any prior error message.
+*/
+SQLITE_PRIVATE void sqlite3Error(sqlite3 *db, int err_code){
+ assert( db!=0 );
+ db->errCode = err_code;
+ if( db->pErr ) sqlite3ValueSetNull(db->pErr);
+}
+
+/*
** Set the most recent error code and error string for the sqlite
** handle "db". The error code is set to "err_code".
**
@@ -22369,18 +23567,18 @@ SQLITE_PRIVATE int sqlite3Strlen30(const char *z){
** should be called with err_code set to SQLITE_OK and zFormat set
** to NULL.
*/
-SQLITE_PRIVATE void sqlite3Error(sqlite3 *db, int err_code, const char *zFormat, ...){
+SQLITE_PRIVATE void sqlite3ErrorWithMsg(sqlite3 *db, int err_code, const char *zFormat, ...){
assert( db!=0 );
db->errCode = err_code;
- if( zFormat && (db->pErr || (db->pErr = sqlite3ValueNew(db))!=0) ){
+ if( zFormat==0 ){
+ sqlite3Error(db, err_code);
+ }else if( db->pErr || (db->pErr = sqlite3ValueNew(db))!=0 ){
char *z;
va_list ap;
va_start(ap, zFormat);
z = sqlite3VMPrintf(db, zFormat, ap);
va_end(ap);
sqlite3ValueSetStr(db->pErr, -1, z, SQLITE_UTF8, SQLITE_DYNAMIC);
- }else if( db->pErr ){
- sqlite3ValueSetNull(db->pErr);
}
}
@@ -22394,12 +23592,12 @@ SQLITE_PRIVATE void sqlite3Error(sqlite3 *db, int err_code, const char *zFormat,
** %T Insert a token
** %S Insert the first element of a SrcList
**
-** This function should be used to report any error that occurs whilst
+** This function should be used to report any error that occurs while
** compiling an SQL statement (i.e. within sqlite3_prepare()). The
** last thing the sqlite3_prepare() function does is copy the error
** stored by this function into the database handle using sqlite3Error().
-** Function sqlite3Error() should be used during statement execution
-** (sqlite3_step() etc.).
+** Functions sqlite3Error() or sqlite3ErrorWithMsg() should be used
+** during statement execution (sqlite3_step() etc.).
*/
SQLITE_PRIVATE void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
char *zMsg;
@@ -22432,7 +23630,7 @@ SQLITE_PRIVATE void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
** occur.
**
** 2002-Feb-14: This routine is extended to remove MS-Access style
-** brackets from around identifers. For example: "[a-b-c]" becomes
+** brackets from around identifiers. For example: "[a-b-c]" becomes
** "a-b-c".
*/
SQLITE_PRIVATE int sqlite3Dequote(char *z){
@@ -22477,15 +23675,25 @@ SQLITE_PRIVATE int sqlite3Dequote(char *z){
** case-independent fashion, using the same definition of "case
** independence" that SQLite uses internally when comparing identifiers.
*/
-SQLITE_API int sqlite3_stricmp(const char *zLeft, const char *zRight){
+SQLITE_API int SQLITE_STDCALL sqlite3_stricmp(const char *zLeft, const char *zRight){
register unsigned char *a, *b;
+ if( zLeft==0 ){
+ return zRight ? -1 : 0;
+ }else if( zRight==0 ){
+ return 1;
+ }
a = (unsigned char *)zLeft;
b = (unsigned char *)zRight;
while( *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }
return UpperToLower[*a] - UpperToLower[*b];
}
-SQLITE_API int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){
+SQLITE_API int SQLITE_STDCALL sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){
register unsigned char *a, *b;
+ if( zLeft==0 ){
+ return zRight ? -1 : 0;
+ }else if( zRight==0 ){
+ return 1;
+ }
a = (unsigned char *)zLeft;
b = (unsigned char *)zRight;
while( N-- > 0 && *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }
@@ -22873,6 +24081,7 @@ SQLITE_PRIVATE int sqlite3GetInt32(const char *zNum, int *pValue){
}
}
#endif
+ while( zNum[0]=='0' ) zNum++;
for(i=0; i<11 && (c = zNum[i] - '0')>=0 && c<=9; i++){
v = v*10 + c;
}
@@ -22936,7 +24145,7 @@ SQLITE_PRIVATE int sqlite3Atoi(const char *z){
** bit clear. Except, if we get to the 9th byte, it stores the full
** 8 bits and is the last byte.
*/
-SQLITE_PRIVATE int sqlite3PutVarint(unsigned char *p, u64 v){
+static int SQLITE_NOINLINE putVarint64(unsigned char *p, u64 v){
int i, j, n;
u8 buf[10];
if( v & (((u64)0xff000000)<<32) ){
@@ -22960,28 +24169,17 @@ SQLITE_PRIVATE int sqlite3PutVarint(unsigned char *p, u64 v){
}
return n;
}
-
-/*
-** This routine is a faster version of sqlite3PutVarint() that only
-** works for 32-bit positive integers and which is optimized for
-** the common case of small integers. A MACRO version, putVarint32,
-** is provided which inlines the single-byte case. All code should use
-** the MACRO version as this function assumes the single-byte case has
-** already been handled.
-*/
-SQLITE_PRIVATE int sqlite3PutVarint32(unsigned char *p, u32 v){
-#ifndef putVarint32
- if( (v & ~0x7f)==0 ){
- p[0] = v;
+SQLITE_PRIVATE int sqlite3PutVarint(unsigned char *p, u64 v){
+ if( v<=0x7f ){
+ p[0] = v&0x7f;
return 1;
}
-#endif
- if( (v & ~0x3fff)==0 ){
- p[0] = (u8)((v>>7) | 0x80);
- p[1] = (u8)(v & 0x7f);
+ if( v<=0x3fff ){
+ p[0] = ((v>>7)&0x7f)|0x80;
+ p[1] = v&0x7f;
return 2;
}
- return sqlite3PutVarint(p, v);
+ return putVarint64(p,v);
}
/*
@@ -23657,12 +24855,11 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash *pH){
/*
** The hashing function.
*/
-static unsigned int strHash(const char *z, int nKey){
+static unsigned int strHash(const char *z){
unsigned int h = 0;
- assert( nKey>=0 );
- while( nKey > 0 ){
- h = (h<<3) ^ h ^ sqlite3UpperToLower[(unsigned char)*z++];
- nKey--;
+ unsigned char c;
+ while( (c = (unsigned char)*z++)!=0 ){
+ h = (h<<3) ^ h ^ sqlite3UpperToLower[c];
}
return h;
}
@@ -23734,7 +24931,7 @@ static int rehash(Hash *pH, unsigned int new_size){
pH->htsize = new_size = sqlite3MallocSize(new_ht)/sizeof(struct _ht);
memset(new_ht, 0, new_size*sizeof(struct _ht));
for(elem=pH->first, pH->first=0; elem; elem = next_elem){
- unsigned int h = strHash(elem->pKey, elem->nKey) % new_size;
+ unsigned int h = strHash(elem->pKey) % new_size;
next_elem = elem->next;
insertElement(pH, &new_ht[h], elem);
}
@@ -23742,28 +24939,33 @@ static int rehash(Hash *pH, unsigned int new_size){
}
/* This function (for internal use only) locates an element in an
-** hash table that matches the given key. The hash for this key has
-** already been computed and is passed as the 4th parameter.
+** hash table that matches the given key. The hash for this key is
+** also computed and returned in the *pH parameter.
*/
-static HashElem *findElementGivenHash(
+static HashElem *findElementWithHash(
const Hash *pH, /* The pH to be searched */
const char *pKey, /* The key we are searching for */
- int nKey, /* Bytes in key (not counting zero terminator) */
- unsigned int h /* The hash for this key. */
+ unsigned int *pHash /* Write the hash value here */
){
HashElem *elem; /* Used to loop thru the element list */
int count; /* Number of elements left to test */
+ unsigned int h; /* The computed hash */
if( pH->ht ){
- struct _ht *pEntry = &pH->ht[h];
+ struct _ht *pEntry;
+ h = strHash(pKey) % pH->htsize;
+ pEntry = &pH->ht[h];
elem = pEntry->chain;
count = pEntry->count;
}else{
+ h = 0;
elem = pH->first;
count = pH->count;
}
- while( count-- && ALWAYS(elem) ){
- if( elem->nKey==nKey && sqlite3StrNICmp(elem->pKey,pKey,nKey)==0 ){
+ *pHash = h;
+ while( count-- ){
+ assert( elem!=0 );
+ if( sqlite3StrICmp(elem->pKey,pKey)==0 ){
return elem;
}
elem = elem->next;
@@ -23806,26 +25008,20 @@ static void removeElementGivenHash(
}
/* Attempt to locate an element of the hash table pH with a key
-** that matches pKey,nKey. Return the data for this element if it is
+** that matches pKey. Return the data for this element if it is
** found, or NULL if there is no match.
*/
-SQLITE_PRIVATE void *sqlite3HashFind(const Hash *pH, const char *pKey, int nKey){
+SQLITE_PRIVATE void *sqlite3HashFind(const Hash *pH, const char *pKey){
HashElem *elem; /* The element that matches key */
unsigned int h; /* A hash on key */
assert( pH!=0 );
assert( pKey!=0 );
- assert( nKey>=0 );
- if( pH->ht ){
- h = strHash(pKey, nKey) % pH->htsize;
- }else{
- h = 0;
- }
- elem = findElementGivenHash(pH, pKey, nKey, h);
+ elem = findElementWithHash(pH, pKey, &h);
return elem ? elem->data : 0;
}
-/* Insert an element into the hash table pH. The key is pKey,nKey
+/* Insert an element into the hash table pH. The key is pKey
** and the data is "data".
**
** If no element exists with a matching key, then a new
@@ -23839,20 +25035,14 @@ SQLITE_PRIVATE void *sqlite3HashFind(const Hash *pH, const char *pKey, int nKey)
** If the "data" parameter to this function is NULL, then the
** element corresponding to "key" is removed from the hash table.
*/
-SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, int nKey, void *data){
+SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, void *data){
unsigned int h; /* the hash of the key modulo hash table size */
HashElem *elem; /* Used to loop thru the element list */
HashElem *new_elem; /* New element added to the pH */
assert( pH!=0 );
assert( pKey!=0 );
- assert( nKey>=0 );
- if( pH->htsize ){
- h = strHash(pKey, nKey) % pH->htsize;
- }else{
- h = 0;
- }
- elem = findElementGivenHash(pH,pKey,nKey,h);
+ elem = findElementWithHash(pH,pKey,&h);
if( elem ){
void *old_data = elem->data;
if( data==0 ){
@@ -23860,7 +25050,6 @@ SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, int nKey, voi
}else{
elem->data = data;
elem->pKey = pKey;
- assert(nKey==elem->nKey);
}
return old_data;
}
@@ -23868,20 +25057,15 @@ SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, int nKey, voi
new_elem = (HashElem*)sqlite3Malloc( sizeof(HashElem) );
if( new_elem==0 ) return data;
new_elem->pKey = pKey;
- new_elem->nKey = nKey;
new_elem->data = data;
pH->count++;
if( pH->count>=10 && pH->count > 2*pH->htsize ){
if( rehash(pH, pH->count*2) ){
assert( pH->htsize>0 );
- h = strHash(pKey, nKey) % pH->htsize;
+ h = strHash(pKey) % pH->htsize;
}
}
- if( pH->ht ){
- insertElement(pH, &pH->ht[h], new_elem);
- }else{
- insertElement(pH, 0, new_elem);
- }
+ insertElement(pH, pH->ht ? &pH->ht[h] : 0, new_elem);
return 0;
}
@@ -23936,42 +25120,42 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
/* 37 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"),
/* 38 */ "MustBeInt" OpHelp(""),
/* 39 */ "RealAffinity" OpHelp(""),
- /* 40 */ "Permutation" OpHelp(""),
- /* 41 */ "Compare" OpHelp("r[P1 P3] <-> r[P2 P3]"),
- /* 42 */ "Jump" OpHelp(""),
- /* 43 */ "Once" OpHelp(""),
- /* 44 */ "If" OpHelp(""),
- /* 45 */ "IfNot" OpHelp(""),
- /* 46 */ "Column" OpHelp("r[P3]=PX"),
- /* 47 */ "Affinity" OpHelp("affinity(r[P1 P2])"),
- /* 48 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1 P2])"),
- /* 49 */ "Count" OpHelp("r[P2]=count()"),
- /* 50 */ "ReadCookie" OpHelp(""),
- /* 51 */ "SetCookie" OpHelp(""),
- /* 52 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"),
- /* 53 */ "OpenRead" OpHelp("root=P2 iDb=P3"),
- /* 54 */ "OpenWrite" OpHelp("root=P2 iDb=P3"),
- /* 55 */ "OpenAutoindex" OpHelp("nColumn=P2"),
- /* 56 */ "OpenEphemeral" OpHelp("nColumn=P2"),
- /* 57 */ "SorterOpen" OpHelp(""),
- /* 58 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"),
- /* 59 */ "Close" OpHelp(""),
- /* 60 */ "SeekLT" OpHelp("key=r[P3 P4]"),
- /* 61 */ "SeekLE" OpHelp("key=r[P3 P4]"),
- /* 62 */ "SeekGE" OpHelp("key=r[P3 P4]"),
- /* 63 */ "SeekGT" OpHelp("key=r[P3 P4]"),
- /* 64 */ "Seek" OpHelp("intkey=r[P2]"),
- /* 65 */ "NoConflict" OpHelp("key=r[P3 P4]"),
- /* 66 */ "NotFound" OpHelp("key=r[P3 P4]"),
- /* 67 */ "Found" OpHelp("key=r[P3 P4]"),
- /* 68 */ "NotExists" OpHelp("intkey=r[P3]"),
- /* 69 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"),
- /* 70 */ "NewRowid" OpHelp("r[P2]=rowid"),
+ /* 40 */ "Cast" OpHelp("affinity(r[P1])"),
+ /* 41 */ "Permutation" OpHelp(""),
+ /* 42 */ "Compare" OpHelp("r[P1 P3] <-> r[P2 P3]"),
+ /* 43 */ "Jump" OpHelp(""),
+ /* 44 */ "Once" OpHelp(""),
+ /* 45 */ "If" OpHelp(""),
+ /* 46 */ "IfNot" OpHelp(""),
+ /* 47 */ "Column" OpHelp("r[P3]=PX"),
+ /* 48 */ "Affinity" OpHelp("affinity(r[P1 P2])"),
+ /* 49 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1 P2])"),
+ /* 50 */ "Count" OpHelp("r[P2]=count()"),
+ /* 51 */ "ReadCookie" OpHelp(""),
+ /* 52 */ "SetCookie" OpHelp(""),
+ /* 53 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"),
+ /* 54 */ "OpenRead" OpHelp("root=P2 iDb=P3"),
+ /* 55 */ "OpenWrite" OpHelp("root=P2 iDb=P3"),
+ /* 56 */ "OpenAutoindex" OpHelp("nColumn=P2"),
+ /* 57 */ "OpenEphemeral" OpHelp("nColumn=P2"),
+ /* 58 */ "SorterOpen" OpHelp(""),
+ /* 59 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"),
+ /* 60 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"),
+ /* 61 */ "Close" OpHelp(""),
+ /* 62 */ "SeekLT" OpHelp("key=r[P3 P4]"),
+ /* 63 */ "SeekLE" OpHelp("key=r[P3 P4]"),
+ /* 64 */ "SeekGE" OpHelp("key=r[P3 P4]"),
+ /* 65 */ "SeekGT" OpHelp("key=r[P3 P4]"),
+ /* 66 */ "Seek" OpHelp("intkey=r[P2]"),
+ /* 67 */ "NoConflict" OpHelp("key=r[P3 P4]"),
+ /* 68 */ "NotFound" OpHelp("key=r[P3 P4]"),
+ /* 69 */ "Found" OpHelp("key=r[P3 P4]"),
+ /* 70 */ "NotExists" OpHelp("intkey=r[P3]"),
/* 71 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"),
/* 72 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"),
- /* 73 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"),
- /* 74 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"),
- /* 75 */ "Delete" OpHelp(""),
+ /* 73 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"),
+ /* 74 */ "NewRowid" OpHelp("r[P2]=rowid"),
+ /* 75 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"),
/* 76 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"),
/* 77 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"),
/* 78 */ "Ne" OpHelp("if r[P1]!=r[P3] goto P2"),
@@ -23980,7 +25164,7 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
/* 81 */ "Le" OpHelp("if r[P1]<=r[P3] goto P2"),
/* 82 */ "Lt" OpHelp("if r[P1]<r[P3] goto P2"),
/* 83 */ "Ge" OpHelp("if r[P1]>=r[P3] goto P2"),
- /* 84 */ "ResetCount" OpHelp(""),
+ /* 84 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"),
/* 85 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"),
/* 86 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"),
/* 87 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<<r[P1]"),
@@ -23991,70 +25175,69 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
/* 92 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"),
/* 93 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"),
/* 94 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"),
- /* 95 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"),
+ /* 95 */ "Delete" OpHelp(""),
/* 96 */ "BitNot" OpHelp("r[P1]= ~r[P1]"),
/* 97 */ "String8" OpHelp("r[P2]='P4'"),
- /* 98 */ "SorterData" OpHelp("r[P2]=data"),
- /* 99 */ "RowKey" OpHelp("r[P2]=key"),
- /* 100 */ "RowData" OpHelp("r[P2]=data"),
- /* 101 */ "Rowid" OpHelp("r[P2]=rowid"),
- /* 102 */ "NullRow" OpHelp(""),
- /* 103 */ "Last" OpHelp(""),
- /* 104 */ "SorterSort" OpHelp(""),
- /* 105 */ "Sort" OpHelp(""),
- /* 106 */ "Rewind" OpHelp(""),
- /* 107 */ "SorterInsert" OpHelp(""),
- /* 108 */ "IdxInsert" OpHelp("key=r[P2]"),
- /* 109 */ "IdxDelete" OpHelp("key=r[P2 P3]"),
- /* 110 */ "IdxRowid" OpHelp("r[P2]=rowid"),
- /* 111 */ "IdxLE" OpHelp("key=r[P3 P4]"),
- /* 112 */ "IdxGT" OpHelp("key=r[P3 P4]"),
- /* 113 */ "IdxLT" OpHelp("key=r[P3 P4]"),
- /* 114 */ "IdxGE" OpHelp("key=r[P3 P4]"),
- /* 115 */ "Destroy" OpHelp(""),
- /* 116 */ "Clear" OpHelp(""),
- /* 117 */ "ResetSorter" OpHelp(""),
- /* 118 */ "CreateIndex" OpHelp("r[P2]=root iDb=P1"),
- /* 119 */ "CreateTable" OpHelp("r[P2]=root iDb=P1"),
- /* 120 */ "ParseSchema" OpHelp(""),
- /* 121 */ "LoadAnalysis" OpHelp(""),
- /* 122 */ "DropTable" OpHelp(""),
- /* 123 */ "DropIndex" OpHelp(""),
- /* 124 */ "DropTrigger" OpHelp(""),
- /* 125 */ "IntegrityCk" OpHelp(""),
- /* 126 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"),
- /* 127 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"),
- /* 128 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"),
- /* 129 */ "Program" OpHelp(""),
- /* 130 */ "Param" OpHelp(""),
- /* 131 */ "FkCounter" OpHelp("fkctr[P1]+=P2"),
- /* 132 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"),
+ /* 98 */ "ResetCount" OpHelp(""),
+ /* 99 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"),
+ /* 100 */ "SorterData" OpHelp("r[P2]=data"),
+ /* 101 */ "RowKey" OpHelp("r[P2]=key"),
+ /* 102 */ "RowData" OpHelp("r[P2]=data"),
+ /* 103 */ "Rowid" OpHelp("r[P2]=rowid"),
+ /* 104 */ "NullRow" OpHelp(""),
+ /* 105 */ "Last" OpHelp(""),
+ /* 106 */ "SorterSort" OpHelp(""),
+ /* 107 */ "Sort" OpHelp(""),
+ /* 108 */ "Rewind" OpHelp(""),
+ /* 109 */ "SorterInsert" OpHelp(""),
+ /* 110 */ "IdxInsert" OpHelp("key=r[P2]"),
+ /* 111 */ "IdxDelete" OpHelp("key=r[P2 P3]"),
+ /* 112 */ "IdxRowid" OpHelp("r[P2]=rowid"),
+ /* 113 */ "IdxLE" OpHelp("key=r[P3 P4]"),
+ /* 114 */ "IdxGT" OpHelp("key=r[P3 P4]"),
+ /* 115 */ "IdxLT" OpHelp("key=r[P3 P4]"),
+ /* 116 */ "IdxGE" OpHelp("key=r[P3 P4]"),
+ /* 117 */ "Destroy" OpHelp(""),
+ /* 118 */ "Clear" OpHelp(""),
+ /* 119 */ "ResetSorter" OpHelp(""),
+ /* 120 */ "CreateIndex" OpHelp("r[P2]=root iDb=P1"),
+ /* 121 */ "CreateTable" OpHelp("r[P2]=root iDb=P1"),
+ /* 122 */ "ParseSchema" OpHelp(""),
+ /* 123 */ "LoadAnalysis" OpHelp(""),
+ /* 124 */ "DropTable" OpHelp(""),
+ /* 125 */ "DropIndex" OpHelp(""),
+ /* 126 */ "DropTrigger" OpHelp(""),
+ /* 127 */ "IntegrityCk" OpHelp(""),
+ /* 128 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"),
+ /* 129 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"),
+ /* 130 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"),
+ /* 131 */ "Program" OpHelp(""),
+ /* 132 */ "Param" OpHelp(""),
/* 133 */ "Real" OpHelp("r[P2]=P4"),
- /* 134 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"),
- /* 135 */ "IfPos" OpHelp("if r[P1]>0 goto P2"),
- /* 136 */ "IfNeg" OpHelp("r[P1]+=P3, if r[P1]<0 goto P2"),
- /* 137 */ "IfZero" OpHelp("r[P1]+=P3, if r[P1]==0 goto P2"),
- /* 138 */ "AggFinal" OpHelp("accum=r[P1] N=P2"),
- /* 139 */ "IncrVacuum" OpHelp(""),
- /* 140 */ "Expire" OpHelp(""),
- /* 141 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"),
- /* 142 */ "VBegin" OpHelp(""),
- /* 143 */ "ToText" OpHelp(""),
- /* 144 */ "ToBlob" OpHelp(""),
- /* 145 */ "ToNumeric" OpHelp(""),
- /* 146 */ "ToInt" OpHelp(""),
- /* 147 */ "ToReal" OpHelp(""),
- /* 148 */ "VCreate" OpHelp(""),
- /* 149 */ "VDestroy" OpHelp(""),
- /* 150 */ "VOpen" OpHelp(""),
- /* 151 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"),
- /* 152 */ "VNext" OpHelp(""),
- /* 153 */ "VRename" OpHelp(""),
- /* 154 */ "Pagecount" OpHelp(""),
- /* 155 */ "MaxPgcnt" OpHelp(""),
- /* 156 */ "Init" OpHelp("Start at P2"),
- /* 157 */ "Noop" OpHelp(""),
- /* 158 */ "Explain" OpHelp(""),
+ /* 134 */ "FkCounter" OpHelp("fkctr[P1]+=P2"),
+ /* 135 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"),
+ /* 136 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"),
+ /* 137 */ "IfPos" OpHelp("if r[P1]>0 goto P2"),
+ /* 138 */ "IfNeg" OpHelp("r[P1]+=P3, if r[P1]<0 goto P2"),
+ /* 139 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]+=P3, goto P2"),
+ /* 140 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"),
+ /* 141 */ "JumpZeroIncr" OpHelp("if (r[P1]++)==0 ) goto P2"),
+ /* 142 */ "AggFinal" OpHelp("accum=r[P1] N=P2"),
+ /* 143 */ "IncrVacuum" OpHelp(""),
+ /* 144 */ "Expire" OpHelp(""),
+ /* 145 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"),
+ /* 146 */ "VBegin" OpHelp(""),
+ /* 147 */ "VCreate" OpHelp(""),
+ /* 148 */ "VDestroy" OpHelp(""),
+ /* 149 */ "VOpen" OpHelp(""),
+ /* 150 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"),
+ /* 151 */ "VNext" OpHelp(""),
+ /* 152 */ "VRename" OpHelp(""),
+ /* 153 */ "Pagecount" OpHelp(""),
+ /* 154 */ "MaxPgcnt" OpHelp(""),
+ /* 155 */ "Init" OpHelp("Start at P2"),
+ /* 156 */ "Noop" OpHelp(""),
+ /* 157 */ "Explain" OpHelp(""),
};
return azName[i];
}
@@ -24135,18 +25318,6 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
#endif
/*
-** Define the OS_VXWORKS pre-processor macro to 1 if building on
-** vxworks, or 0 otherwise.
-*/
-#ifndef OS_VXWORKS
-# if defined(__RTP__) || defined(_WRS_KERNEL)
-# define OS_VXWORKS 1
-# else
-# define OS_VXWORKS 0
-# endif
-#endif
-
-/*
** standard include files.
*/
#include <sys/types.h>
@@ -24160,18 +25331,30 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
# include <sys/mman.h>
#endif
-#if SQLITE_ENABLE_LOCKING_STYLE || OS_VXWORKS
+#if SQLITE_ENABLE_LOCKING_STYLE
# include <sys/ioctl.h>
-# if OS_VXWORKS
-# include <semaphore.h>
-# include <limits.h>
-# else
-# include <sys/file.h>
-# include <sys/param.h>
-# endif
+# include <sys/file.h>
+# include <sys/param.h>
#endif /* SQLITE_ENABLE_LOCKING_STYLE */
-#if defined(__APPLE__) || (SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS)
+#if defined(__APPLE__) && ((__MAC_OS_X_VERSION_MIN_REQUIRED > 1050) || \
+ (__IPHONE_OS_VERSION_MIN_REQUIRED > 2000))
+# if (!defined(TARGET_OS_EMBEDDED) || (TARGET_OS_EMBEDDED==0)) \
+ && (!defined(TARGET_IPHONE_SIMULATOR) || (TARGET_IPHONE_SIMULATOR==0))
+# define HAVE_GETHOSTUUID 1
+# else
+# warning "gethostuuid() is disabled."
+# endif
+#endif
+
+
+#if OS_VXWORKS
+/* # include <sys/ioctl.h> */
+# include <semaphore.h>
+# include <limits.h>
+#endif /* OS_VXWORKS */
+
+#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
# include <sys/mount.h>
#endif
@@ -24212,6 +25395,10 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
*/
#define MAX_PATHNAME 512
+/* Always cast the getpid() return type for compatibility with
+** kernel modules in VxWorks. */
+#define osGetpid(X) (pid_t)getpid()
+
/*
** Only set the lastErrno if the error code is a real error and not
** a normal expected return code of SQLITE_BUSY or SQLITE_OK
@@ -24300,7 +25487,7 @@ struct unixFile {
** method was called. If xOpen() is called from a different process id,
** indicating that a fork() has occurred, the PRNG will be reset.
*/
-static int randomnessPid = 0;
+static pid_t randomnessPid = 0;
/*
** Allowed values for the unixFile.ctrlFlags bitmask:
@@ -24317,7 +25504,8 @@ static int randomnessPid = 0;
#define UNIXFILE_DELETE 0x20 /* Delete on close */
#define UNIXFILE_URI 0x40 /* Filename might have query parameters */
#define UNIXFILE_NOLOCK 0x80 /* Do no file locking */
-#define UNIXFILE_WARNED 0x0100 /* verifyDbFile() warnings have been issued */
+#define UNIXFILE_WARNED 0x0100 /* verifyDbFile() warnings issued */
+#define UNIXFILE_BLOCK 0x0200 /* Next SHM lock might block */
/*
** Include code that is common to all os_*.c files
@@ -24355,16 +25543,6 @@ static int randomnessPid = 0;
# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead."
#endif
-#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
-# ifndef SQLITE_DEBUG_OS_TRACE
-# define SQLITE_DEBUG_OS_TRACE 0
-# endif
- int sqlite3OSTrace = SQLITE_DEBUG_OS_TRACE;
-# define OSTRACE(X) if( sqlite3OSTrace ) sqlite3DebugPrintf X
-#else
-# define OSTRACE(X)
-#endif
-
/*
** Macros for performance tracing. Normally turned off. Only works
** on i486 hardware.
@@ -24571,6 +25749,14 @@ SQLITE_API int sqlite3_open_file_count = 0;
#endif
/*
+** Explicitly call the 64-bit version of lseek() on Android. Otherwise, lseek()
+** is the 32-bit version, even if _FILE_OFFSET_BITS=64 is defined.
+*/
+#ifdef __ANDROID__
+# define lseek lseek64
+#endif
+
+/*
** Different Unix systems declare open() in different ways. Same use
** open(const char*,int,mode_t). Others use open(const char*,int,...).
** The difference is important when using a pointer to the function.
@@ -24648,7 +25834,7 @@ static struct unix_syscall {
{ "read", (sqlite3_syscall_ptr)read, 0 },
#define osRead ((ssize_t(*)(int,void*,size_t))aSyscall[8].pCurrent)
-#if defined(USE_PREAD) || (SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS)
+#if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE
{ "pread", (sqlite3_syscall_ptr)pread, 0 },
#else
{ "pread", (sqlite3_syscall_ptr)0, 0 },
@@ -24665,7 +25851,7 @@ static struct unix_syscall {
{ "write", (sqlite3_syscall_ptr)write, 0 },
#define osWrite ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent)
-#if defined(USE_PREAD) || (SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS)
+#if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE
{ "pwrite", (sqlite3_syscall_ptr)pwrite, 0 },
#else
{ "pwrite", (sqlite3_syscall_ptr)0, 0 },
@@ -24899,10 +26085,10 @@ static int unixMutexHeld(void) {
#endif
-#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
+#ifdef SQLITE_HAVE_OS_TRACE
/*
** Helper function for printing out trace information from debugging
-** binaries. This returns the string represetation of the supplied
+** binaries. This returns the string representation of the supplied
** integer lock-type.
*/
static const char *azFileLock(int eFileLock){
@@ -24979,9 +26165,22 @@ static int lockTrace(int fd, int op, struct flock *p){
/*
** Retry ftruncate() calls that fail due to EINTR
+**
+** All calls to ftruncate() within this file should be made through
+** this wrapper. On the Android platform, bypassing the logic below
+** could lead to a corrupt database.
*/
static int robust_ftruncate(int h, sqlite3_int64 sz){
int rc;
+#ifdef __ANDROID__
+ /* On Android, ftruncate() always uses 32-bit offsets, even if
+ ** _FILE_OFFSET_BITS=64 is defined. This means it is unsafe to attempt to
+ ** truncate a file to any size larger than 2GiB. Silently ignore any
+ ** such attempts. */
+ if( sz>(sqlite3_int64)0x7FFFFFFF ){
+ rc = SQLITE_OK;
+ }else
+#endif
do{ rc = osFtruncate(h,sz); }while( rc<0 && errno==EINTR );
return rc;
}
@@ -25149,7 +26348,7 @@ static struct vxworksFileId *vxworksFindFileId(const char *zAbsoluteName){
assert( zAbsoluteName[0]=='/' );
n = (int)strlen(zAbsoluteName);
- pNew = sqlite3_malloc( sizeof(*pNew) + (n+1) );
+ pNew = sqlite3_malloc64( sizeof(*pNew) + (n+1) );
if( pNew==0 ) return 0;
pNew->zCanonicalName = (char*)&pNew[1];
memcpy(pNew->zCanonicalName, zAbsoluteName, n+1);
@@ -25429,6 +26628,14 @@ static void robust_close(unixFile *pFile, int h, int lineno){
}
/*
+** Set the pFile->lastErrno. Do this in a subroutine as that provides
+** a convenient place to set a breakpoint.
+*/
+static void storeLastErrno(unixFile *pFile, int error){
+ pFile->lastErrno = error;
+}
+
+/*
** Close all file descriptors accumuated in the unixInodeInfo->pUnused list.
*/
static void closePendingFds(unixFile *pFile){
@@ -25501,7 +26708,7 @@ static int findInodeInfo(
fd = pFile->h;
rc = osFstat(fd, &statbuf);
if( rc!=0 ){
- pFile->lastErrno = errno;
+ storeLastErrno(pFile, errno);
#ifdef EOVERFLOW
if( pFile->lastErrno==EOVERFLOW ) return SQLITE_NOLFS;
#endif
@@ -25522,12 +26729,12 @@ static int findInodeInfo(
if( statbuf.st_size==0 && (pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS)!=0 ){
do{ rc = osWrite(fd, "S", 1); }while( rc<0 && errno==EINTR );
if( rc!=1 ){
- pFile->lastErrno = errno;
+ storeLastErrno(pFile, errno);
return SQLITE_IOERR;
}
rc = osFstat(fd, &statbuf);
if( rc!=0 ){
- pFile->lastErrno = errno;
+ storeLastErrno(pFile, errno);
return SQLITE_IOERR;
}
}
@@ -25545,7 +26752,7 @@ static int findInodeInfo(
pInode = pInode->pNext;
}
if( pInode==0 ){
- pInode = sqlite3_malloc( sizeof(*pInode) );
+ pInode = sqlite3_malloc64( sizeof(*pInode) );
if( pInode==0 ){
return SQLITE_NOMEM;
}
@@ -25650,7 +26857,7 @@ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){
lock.l_type = F_WRLCK;
if( osFcntl(pFile->h, F_GETLK, &lock) ){
rc = SQLITE_IOERR_CHECKRESERVEDLOCK;
- pFile->lastErrno = errno;
+ storeLastErrno(pFile, errno);
} else if( lock.l_type!=F_UNLCK ){
reserved = 1;
}
@@ -25783,7 +26990,8 @@ static int unixLock(sqlite3_file *id, int eFileLock){
assert( pFile );
OSTRACE(("LOCK %d %s was %s(%s,%d) pid=%d (unix)\n", pFile->h,
azFileLock(eFileLock), azFileLock(pFile->eFileLock),
- azFileLock(pFile->pInode->eFileLock), pFile->pInode->nShared , getpid()));
+ azFileLock(pFile->pInode->eFileLock), pFile->pInode->nShared,
+ osGetpid(0)));
/* If there is already a lock of this type or more restrictive on the
** unixFile, do nothing. Don't use the end_lock: exit path, as
@@ -25850,7 +27058,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
tErrno = errno;
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
if( rc!=SQLITE_BUSY ){
- pFile->lastErrno = tErrno;
+ storeLastErrno(pFile, tErrno);
}
goto end_lock;
}
@@ -25885,7 +27093,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
if( rc ){
if( rc!=SQLITE_BUSY ){
- pFile->lastErrno = tErrno;
+ storeLastErrno(pFile, tErrno);
}
goto end_lock;
}else{
@@ -25918,7 +27126,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
tErrno = errno;
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
if( rc!=SQLITE_BUSY ){
- pFile->lastErrno = tErrno;
+ storeLastErrno(pFile, tErrno);
}
}
}
@@ -25991,7 +27199,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
assert( pFile );
OSTRACE(("UNLOCK %d %d was %d(%d,%d) pid=%d (unix)\n", pFile->h, eFileLock,
pFile->eFileLock, pFile->pInode->eFileLock, pFile->pInode->nShared,
- getpid()));
+ osGetpid(0)));
assert( eFileLock<=SHARED_LOCK );
if( pFile->eFileLock<=eFileLock ){
@@ -26025,7 +27233,6 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
** 4: [RRRR.]
*/
if( eFileLock==SHARED_LOCK ){
-
#if !defined(__APPLE__) || !SQLITE_ENABLE_LOCKING_STYLE
(void)handleNFSUnlock;
assert( handleNFSUnlock==0 );
@@ -26043,7 +27250,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
tErrno = errno;
rc = SQLITE_IOERR_UNLOCK;
if( IS_LOCK_ERROR(rc) ){
- pFile->lastErrno = tErrno;
+ storeLastErrno(pFile, tErrno);
}
goto end_unlock;
}
@@ -26055,7 +27262,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
tErrno = errno;
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);
if( IS_LOCK_ERROR(rc) ){
- pFile->lastErrno = tErrno;
+ storeLastErrno(pFile, tErrno);
}
goto end_unlock;
}
@@ -26067,7 +27274,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
tErrno = errno;
rc = SQLITE_IOERR_UNLOCK;
if( IS_LOCK_ERROR(rc) ){
- pFile->lastErrno = tErrno;
+ storeLastErrno(pFile, tErrno);
}
goto end_unlock;
}
@@ -26086,7 +27293,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
** SQLITE_BUSY would confuse the upper layer (in practice it causes
** an assert to fail). */
rc = SQLITE_IOERR_RDLOCK;
- pFile->lastErrno = errno;
+ storeLastErrno(pFile, errno);
goto end_unlock;
}
}
@@ -26099,7 +27306,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
pInode->eFileLock = SHARED_LOCK;
}else{
rc = SQLITE_IOERR_UNLOCK;
- pFile->lastErrno = errno;
+ storeLastErrno(pFile, errno);
goto end_unlock;
}
}
@@ -26117,7 +27324,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
pInode->eFileLock = NO_LOCK;
}else{
rc = SQLITE_IOERR_UNLOCK;
- pFile->lastErrno = errno;
+ storeLastErrno(pFile, errno);
pInode->eFileLock = NO_LOCK;
pFile->eFileLock = NO_LOCK;
}
@@ -26392,7 +27599,7 @@ static int dotlockLock(sqlite3_file *id, int eFileLock) {
} else {
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
if( IS_LOCK_ERROR(rc) ){
- pFile->lastErrno = tErrno;
+ storeLastErrno(pFile, tErrno);
}
}
return rc;
@@ -26419,7 +27626,7 @@ static int dotlockUnlock(sqlite3_file *id, int eFileLock) {
assert( pFile );
OSTRACE(("UNLOCK %d %d was %d pid=%d (dotlock)\n", pFile->h, eFileLock,
- pFile->eFileLock, getpid()));
+ pFile->eFileLock, osGetpid(0)));
assert( eFileLock<=SHARED_LOCK );
/* no-op if possible */
@@ -26446,7 +27653,7 @@ static int dotlockUnlock(sqlite3_file *id, int eFileLock) {
rc = SQLITE_IOERR_UNLOCK;
}
if( IS_LOCK_ERROR(rc) ){
- pFile->lastErrno = tErrno;
+ storeLastErrno(pFile, tErrno);
}
return rc;
}
@@ -26482,10 +27689,9 @@ static int dotlockClose(sqlite3_file *id) {
** still works when you do this, but concurrency is reduced since
** only a single process can be reading the database at a time.
**
-** Omit this section if SQLITE_ENABLE_LOCKING_STYLE is turned off or if
-** compiling for VXWORKS.
+** Omit this section if SQLITE_ENABLE_LOCKING_STYLE is turned off
*/
-#if SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS
+#if SQLITE_ENABLE_LOCKING_STYLE
/*
** Retry flock() calls that fail with EINTR
@@ -26533,7 +27739,7 @@ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){
/* unlock failed with an error */
lrc = SQLITE_IOERR_UNLOCK;
if( IS_LOCK_ERROR(lrc) ){
- pFile->lastErrno = tErrno;
+ storeLastErrno(pFile, tErrno);
rc = lrc;
}
}
@@ -26543,7 +27749,7 @@ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){
/* someone else might have it reserved */
lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
if( IS_LOCK_ERROR(lrc) ){
- pFile->lastErrno = tErrno;
+ storeLastErrno(pFile, tErrno);
rc = lrc;
}
}
@@ -26609,7 +27815,7 @@ static int flockLock(sqlite3_file *id, int eFileLock) {
/* didn't get, must be busy */
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
if( IS_LOCK_ERROR(rc) ){
- pFile->lastErrno = tErrno;
+ storeLastErrno(pFile, tErrno);
}
} else {
/* got it, set the type and return ok */
@@ -26638,7 +27844,7 @@ static int flockUnlock(sqlite3_file *id, int eFileLock) {
assert( pFile );
OSTRACE(("UNLOCK %d %d was %d pid=%d (flock)\n", pFile->h, eFileLock,
- pFile->eFileLock, getpid()));
+ pFile->eFileLock, osGetpid(0)));
assert( eFileLock<=SHARED_LOCK );
/* no-op if possible */
@@ -26699,7 +27905,7 @@ static int flockClose(sqlite3_file *id) {
** to a non-zero value otherwise *pResOut is set to zero. The return value
** is set to SQLITE_OK unless an I/O error occurs during lock checking.
*/
-static int semCheckReservedLock(sqlite3_file *id, int *pResOut) {
+static int semXCheckReservedLock(sqlite3_file *id, int *pResOut) {
int rc = SQLITE_OK;
int reserved = 0;
unixFile *pFile = (unixFile*)id;
@@ -26721,7 +27927,7 @@ static int semCheckReservedLock(sqlite3_file *id, int *pResOut) {
int tErrno = errno;
if( EAGAIN != tErrno ){
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_CHECKRESERVEDLOCK);
- pFile->lastErrno = tErrno;
+ storeLastErrno(pFile, tErrno);
} else {
/* someone else has the lock when we are in NO_LOCK */
reserved = (pFile->eFileLock < SHARED_LOCK);
@@ -26766,7 +27972,7 @@ static int semCheckReservedLock(sqlite3_file *id, int *pResOut) {
** This routine will only increase a lock. Use the sqlite3OsUnlock()
** routine to lower a locking level.
*/
-static int semLock(sqlite3_file *id, int eFileLock) {
+static int semXLock(sqlite3_file *id, int eFileLock) {
unixFile *pFile = (unixFile*)id;
sem_t *pSem = pFile->pInode->pSem;
int rc = SQLITE_OK;
@@ -26799,14 +28005,14 @@ static int semLock(sqlite3_file *id, int eFileLock) {
** If the locking level of the file descriptor is already at or below
** the requested locking level, this routine is a no-op.
*/
-static int semUnlock(sqlite3_file *id, int eFileLock) {
+static int semXUnlock(sqlite3_file *id, int eFileLock) {
unixFile *pFile = (unixFile*)id;
sem_t *pSem = pFile->pInode->pSem;
assert( pFile );
assert( pSem );
OSTRACE(("UNLOCK %d %d was %d pid=%d (sem)\n", pFile->h, eFileLock,
- pFile->eFileLock, getpid()));
+ pFile->eFileLock, osGetpid(0)));
assert( eFileLock<=SHARED_LOCK );
/* no-op if possible */
@@ -26825,7 +28031,7 @@ static int semUnlock(sqlite3_file *id, int eFileLock) {
int rc, tErrno = errno;
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
if( IS_LOCK_ERROR(rc) ){
- pFile->lastErrno = tErrno;
+ storeLastErrno(pFile, tErrno);
}
return rc;
}
@@ -26836,10 +28042,10 @@ static int semUnlock(sqlite3_file *id, int eFileLock) {
/*
** Close a file.
*/
-static int semClose(sqlite3_file *id) {
+static int semXClose(sqlite3_file *id) {
if( id ){
unixFile *pFile = (unixFile*)id;
- semUnlock(id, NO_LOCK);
+ semXUnlock(id, NO_LOCK);
assert( pFile );
unixEnterMutex();
releaseInodeInfo(pFile);
@@ -26927,7 +28133,7 @@ static int afpSetLock(
setLockFlag ? SQLITE_IOERR_LOCK : SQLITE_IOERR_UNLOCK);
#endif /* SQLITE_IGNORE_AFP_LOCK_ERRORS */
if( IS_LOCK_ERROR(rc) ){
- pFile->lastErrno = tErrno;
+ storeLastErrno(pFile, tErrno);
}
return rc;
} else {
@@ -27020,7 +28226,7 @@ static int afpLock(sqlite3_file *id, int eFileLock){
assert( pFile );
OSTRACE(("LOCK %d %s was %s(%s,%d) pid=%d (afp)\n", pFile->h,
azFileLock(eFileLock), azFileLock(pFile->eFileLock),
- azFileLock(pInode->eFileLock), pInode->nShared , getpid()));
+ azFileLock(pInode->eFileLock), pInode->nShared , osGetpid(0)));
/* If there is already a lock of this type or more restrictive on the
** unixFile, do nothing. Don't use the afp_end_lock: exit path, as
@@ -27110,7 +28316,7 @@ static int afpLock(sqlite3_file *id, int eFileLock){
lrc2 = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 0);
if( IS_LOCK_ERROR(lrc1) ) {
- pFile->lastErrno = lrc1Errno;
+ storeLastErrno(pFile, lrc1Errno);
rc = lrc1;
goto afp_end_lock;
} else if( IS_LOCK_ERROR(lrc2) ){
@@ -27206,7 +28412,7 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) {
assert( pFile );
OSTRACE(("UNLOCK %d %d was %d(%d,%d) pid=%d (afp)\n", pFile->h, eFileLock,
pFile->eFileLock, pFile->pInode->eFileLock, pFile->pInode->nShared,
- getpid()));
+ osGetpid(0)));
assert( eFileLock<=SHARED_LOCK );
if( pFile->eFileLock<=eFileLock ){
@@ -27369,7 +28575,7 @@ static int nfsUnlock(sqlite3_file *id, int eFileLock){
** NB: If you define USE_PREAD or USE_PREAD64, then it might also
** be necessary to define _XOPEN_SOURCE to be 500. This varies from
** one system to another. Since SQLite does not define USE_PREAD
-** any any form by default, we will not attempt to define _XOPEN_SOURCE.
+** in any form by default, we will not attempt to define _XOPEN_SOURCE.
** See tickets #2741 and #2681.
**
** To avoid stomping the errno value on a failed read the lastErrno value
@@ -27397,9 +28603,9 @@ static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){
SimulateIOError( newOffset-- );
if( newOffset!=offset ){
if( newOffset == -1 ){
- ((unixFile*)id)->lastErrno = errno;
+ storeLastErrno((unixFile*)id, errno);
}else{
- ((unixFile*)id)->lastErrno = 0;
+ storeLastErrno((unixFile*)id, 0);
}
return -1;
}
@@ -27409,7 +28615,7 @@ static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){
if( got<0 ){
if( errno==EINTR ){ got = 1; continue; }
prior = 0;
- ((unixFile*)id)->lastErrno = errno;
+ storeLastErrno((unixFile*)id, errno);
break;
}else if( got>0 ){
cnt -= got;
@@ -27474,7 +28680,7 @@ static int unixRead(
/* lastErrno set by seekAndRead */
return SQLITE_IOERR_READ;
}else{
- pFile->lastErrno = 0; /* not a system error */
+ storeLastErrno(pFile, 0); /* not a system error */
/* Unread parts of the buffer must be zero-filled */
memset(&((char*)pBuf)[got], 0, amt-got);
return SQLITE_IOERR_SHORT_READ;
@@ -27503,9 +28709,9 @@ static int seekAndWriteFd(
TIMER_START;
#if defined(USE_PREAD)
- do{ rc = osPwrite(fd, pBuf, nBuf, iOff); }while( rc<0 && errno==EINTR );
+ do{ rc = (int)osPwrite(fd, pBuf, nBuf, iOff); }while( rc<0 && errno==EINTR );
#elif defined(USE_PREAD64)
- do{ rc = osPwrite64(fd, pBuf, nBuf, iOff);}while( rc<0 && errno==EINTR);
+ do{ rc = (int)osPwrite64(fd, pBuf, nBuf, iOff);}while( rc<0 && errno==EINTR);
#else
do{
i64 iSeek = lseek(fd, iOff, SEEK_SET);
@@ -27615,7 +28821,7 @@ static int unixWrite(
/* lastErrno set by seekAndWrite */
return SQLITE_IOERR_WRITE;
}else{
- pFile->lastErrno = 0; /* not a system error */
+ storeLastErrno(pFile, 0); /* not a system error */
return SQLITE_FULL;
}
}
@@ -27636,9 +28842,9 @@ SQLITE_API int sqlite3_fullsync_count = 0;
** We do not trust systems to provide a working fdatasync(). Some do.
** Others do no. To be safe, we will stick with the (slightly slower)
** fsync(). If you know that your system does support fdatasync() correctly,
-** then simply compile with -Dfdatasync=fdatasync
+** then simply compile with -Dfdatasync=fdatasync or -DHAVE_FDATASYNC
*/
-#if !defined(fdatasync)
+#if !defined(fdatasync) && !HAVE_FDATASYNC
# define fdatasync fsync
#endif
@@ -27824,7 +29030,7 @@ static int unixSync(sqlite3_file *id, int flags){
rc = full_fsync(pFile->h, isFullsync, isDataOnly);
SimulateIOError( rc=1 );
if( rc ){
- pFile->lastErrno = errno;
+ storeLastErrno(pFile, errno);
return unixLogError(SQLITE_IOERR_FSYNC, "full_fsync", pFile->zPath);
}
@@ -27866,9 +29072,9 @@ static int unixTruncate(sqlite3_file *id, i64 nByte){
nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
}
- rc = robust_ftruncate(pFile->h, (off_t)nByte);
+ rc = robust_ftruncate(pFile->h, nByte);
if( rc ){
- pFile->lastErrno = errno;
+ storeLastErrno(pFile, errno);
return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
}else{
#ifdef SQLITE_DEBUG
@@ -27908,7 +29114,7 @@ static int unixFileSize(sqlite3_file *id, i64 *pSize){
rc = osFstat(((unixFile*)id)->h, &buf);
SimulateIOError( rc=1 );
if( rc!=0 ){
- ((unixFile*)id)->lastErrno = errno;
+ storeLastErrno((unixFile*)id, errno);
return SQLITE_IOERR_FSTAT;
}
*pSize = buf.st_size;
@@ -27944,7 +29150,9 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
i64 nSize; /* Required file size */
struct stat buf; /* Used to hold return values of fstat() */
- if( osFstat(pFile->h, &buf) ) return SQLITE_IOERR_FSTAT;
+ if( osFstat(pFile->h, &buf) ){
+ return SQLITE_IOERR_FSTAT;
+ }
nSize = ((nByte+pFile->szChunk-1) / pFile->szChunk) * pFile->szChunk;
if( nSize>(i64)buf.st_size ){
@@ -27959,24 +29167,28 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
}while( err==EINTR );
if( err ) return SQLITE_IOERR_WRITE;
#else
- /* If the OS does not have posix_fallocate(), fake it. First use
- ** ftruncate() to set the file size, then write a single byte to
- ** the last byte in each block within the extended region. This
- ** is the same technique used by glibc to implement posix_fallocate()
- ** on systems that do not have a real fallocate() system call.
+ /* If the OS does not have posix_fallocate(), fake it. Write a
+ ** single byte to the last byte in each block that falls entirely
+ ** within the extended region. Then, if required, a single byte
+ ** at offset (nSize-1), to set the size of the file correctly.
+ ** This is a similar technique to that used by glibc on systems
+ ** that do not have a real fallocate() call.
*/
int nBlk = buf.st_blksize; /* File-system block size */
+ int nWrite = 0; /* Number of bytes written by seekAndWrite */
i64 iWrite; /* Next offset to write to */
- if( robust_ftruncate(pFile->h, nSize) ){
- pFile->lastErrno = errno;
- return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
- }
iWrite = ((buf.st_size + 2*nBlk - 1)/nBlk)*nBlk-1;
- while( iWrite<nSize ){
- int nWrite = seekAndWrite(pFile, iWrite, "", 1);
+ assert( iWrite>=buf.st_size );
+ assert( (iWrite/nBlk)==((buf.st_size+nBlk-1)/nBlk) );
+ assert( ((iWrite+1)%nBlk)==0 );
+ for(/*no-op*/; iWrite<nSize; iWrite+=nBlk ){
+ nWrite = seekAndWrite(pFile, iWrite, "", 1);
+ if( nWrite!=1 ) return SQLITE_IOERR_WRITE;
+ }
+ if( nWrite==0 || (nSize%nBlk) ){
+ nWrite = seekAndWrite(pFile, nSize-1, "", 1);
if( nWrite!=1 ) return SQLITE_IOERR_WRITE;
- iWrite += nBlk;
}
#endif
}
@@ -27987,7 +29199,7 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
int rc;
if( pFile->szChunk<=0 ){
if( robust_ftruncate(pFile->h, nByte) ){
- pFile->lastErrno = errno;
+ storeLastErrno(pFile, errno);
return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
}
}
@@ -28001,7 +29213,7 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
}
/*
-** If *pArg is inititially negative then this is a query. Set *pArg to
+** If *pArg is initially negative then this is a query. Set *pArg to
** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set.
**
** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags.
@@ -28025,11 +29237,15 @@ static int unixGetTempname(int nBuf, char *zBuf);
static int unixFileControl(sqlite3_file *id, int op, void *pArg){
unixFile *pFile = (unixFile*)id;
switch( op ){
+ case SQLITE_FCNTL_WAL_BLOCK: {
+ /* pFile->ctrlFlags |= UNIXFILE_BLOCK; // Deferred feature */
+ return SQLITE_OK;
+ }
case SQLITE_FCNTL_LOCKSTATE: {
*(int*)pArg = pFile->eFileLock;
return SQLITE_OK;
}
- case SQLITE_LAST_ERRNO: {
+ case SQLITE_FCNTL_LAST_ERRNO: {
*(int*)pArg = pFile->lastErrno;
return SQLITE_OK;
}
@@ -28057,7 +29273,7 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
return SQLITE_OK;
}
case SQLITE_FCNTL_TEMPFILENAME: {
- char *zTFile = sqlite3_malloc( pFile->pVfs->mxPathname );
+ char *zTFile = sqlite3_malloc64( pFile->pVfs->mxPathname );
if( zTFile ){
unixGetTempname(pFile->pVfs->mxPathname, zTFile);
*(char**)pArg = zTFile;
@@ -28098,8 +29314,8 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
}
#endif
#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
- case SQLITE_SET_LOCKPROXYFILE:
- case SQLITE_GET_LOCKPROXYFILE: {
+ case SQLITE_FCNTL_SET_LOCKPROXYFILE:
+ case SQLITE_FCNTL_GET_LOCKPROXYFILE: {
return proxyFileControl(id,op,pArg);
}
#endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */
@@ -28208,7 +29424,7 @@ static int unixSectorSize(sqlite3_file *id){
** Return the device characteristics for the file.
**
** This VFS is set up to return SQLITE_IOCAP_POWERSAFE_OVERWRITE by default.
-** However, that choice is contraversial since technically the underlying
+** However, that choice is controversial since technically the underlying
** file system does not always provide powersafe overwrites. (In other
** words, after a power-loss event, parts of the file that were never
** written might end up being altered.) However, non-PSOW behavior is very,
@@ -28239,7 +29455,9 @@ static int unixDeviceCharacteristics(sqlite3_file *id){
** Instead, it should be called via macro osGetpagesize().
*/
static int unixGetpagesize(void){
-#if defined(_BSD_SOURCE)
+#if OS_VXWORKS
+ return 1024;
+#elif defined(_BSD_SOURCE)
return getpagesize();
#else
return (int)sysconf(_SC_PAGESIZE);
@@ -28332,15 +29550,17 @@ struct unixShm {
** otherwise.
*/
static int unixShmSystemLock(
- unixShmNode *pShmNode, /* Apply locks to this open shared-memory segment */
+ unixFile *pFile, /* Open connection to the WAL file */
int lockType, /* F_UNLCK, F_RDLCK, or F_WRLCK */
int ofst, /* First byte of the locking range */
int n /* Number of bytes to lock */
){
- struct flock f; /* The posix advisory locking structure */
- int rc = SQLITE_OK; /* Result code form fcntl() */
+ unixShmNode *pShmNode; /* Apply locks to this open shared-memory segment */
+ struct flock f; /* The posix advisory locking structure */
+ int rc = SQLITE_OK; /* Result code form fcntl() */
/* Access to the unixShmNode object is serialized by the caller */
+ pShmNode = pFile->pInode->pShmNode;
assert( sqlite3_mutex_held(pShmNode->mutex) || pShmNode->nRef==0 );
/* Shared locks never span more than one byte */
@@ -28350,6 +29570,7 @@ static int unixShmSystemLock(
assert( n>=1 && n<SQLITE_SHM_NLOCK );
if( pShmNode->h>=0 ){
+ int lkType;
/* Initialize the locking parameters */
memset(&f, 0, sizeof(f));
f.l_type = lockType;
@@ -28357,8 +29578,10 @@ static int unixShmSystemLock(
f.l_start = ofst;
f.l_len = n;
- rc = osFcntl(pShmNode->h, F_SETLK, &f);
+ lkType = (pFile->ctrlFlags & UNIXFILE_BLOCK)!=0 ? F_SETLKW : F_SETLK;
+ rc = osFcntl(pShmNode->h, lkType, &f);
rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY;
+ pFile->ctrlFlags &= ~UNIXFILE_BLOCK;
}
/* Update the global lock state and do debug tracing */
@@ -28491,7 +29714,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
int nShmFilename; /* Size of the SHM filename in bytes */
/* Allocate space for the new unixShm object. */
- p = sqlite3_malloc( sizeof(*p) );
+ p = sqlite3_malloc64( sizeof(*p) );
if( p==0 ) return SQLITE_NOMEM;
memset(p, 0, sizeof(*p));
assert( pDbFd->pShm==0 );
@@ -28504,6 +29727,9 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
pShmNode = pInode->pShmNode;
if( pShmNode==0 ){
struct stat sStat; /* fstat() info for database file */
+#ifndef SQLITE_SHM_DIRECTORY
+ const char *zBasePath = pDbFd->zPath;
+#endif
/* Call fstat() to figure out the permissions on the database file. If
** a new *-shm file is created, an attempt will be made to create it
@@ -28517,9 +29743,9 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
#ifdef SQLITE_SHM_DIRECTORY
nShmFilename = sizeof(SQLITE_SHM_DIRECTORY) + 31;
#else
- nShmFilename = 6 + (int)strlen(pDbFd->zPath);
+ nShmFilename = 6 + (int)strlen(zBasePath);
#endif
- pShmNode = sqlite3_malloc( sizeof(*pShmNode) + nShmFilename );
+ pShmNode = sqlite3_malloc64( sizeof(*pShmNode) + nShmFilename );
if( pShmNode==0 ){
rc = SQLITE_NOMEM;
goto shm_open_err;
@@ -28531,7 +29757,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
SQLITE_SHM_DIRECTORY "/sqlite-shm-%x-%x",
(u32)sStat.st_ino, (u32)sStat.st_dev);
#else
- sqlite3_snprintf(nShmFilename, zShmFilename, "%s-shm", pDbFd->zPath);
+ sqlite3_snprintf(nShmFilename, zShmFilename, "%s-shm", zBasePath);
sqlite3FileSuffix3(pDbFd->zPath, zShmFilename);
#endif
pShmNode->h = -1;
@@ -28565,13 +29791,13 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
** If not, truncate the file to zero length.
*/
rc = SQLITE_OK;
- if( unixShmSystemLock(pShmNode, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){
+ if( unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){
if( robust_ftruncate(pShmNode->h, 0) ){
rc = unixLogError(SQLITE_IOERR_SHMOPEN, "ftruncate", zShmFilename);
}
}
if( rc==SQLITE_OK ){
- rc = unixShmSystemLock(pShmNode, F_RDLCK, UNIX_SHM_DMS, 1);
+ rc = unixShmSystemLock(pDbFd, F_RDLCK, UNIX_SHM_DMS, 1);
}
if( rc ) goto shm_open_err;
}
@@ -28729,7 +29955,7 @@ static int unixShmMap(
goto shmpage_out;
}
}else{
- pMem = sqlite3_malloc(szRegion);
+ pMem = sqlite3_malloc64(szRegion);
if( pMem==0 ){
rc = SQLITE_NOMEM;
goto shmpage_out;
@@ -28803,7 +30029,7 @@ static int unixShmLock(
/* Unlock the system-level locks */
if( (mask & allMask)==0 ){
- rc = unixShmSystemLock(pShmNode, F_UNLCK, ofst+UNIX_SHM_BASE, n);
+ rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n);
}else{
rc = SQLITE_OK;
}
@@ -28831,7 +30057,7 @@ static int unixShmLock(
/* Get shared locks at the system level, if necessary */
if( rc==SQLITE_OK ){
if( (allShared & mask)==0 ){
- rc = unixShmSystemLock(pShmNode, F_RDLCK, ofst+UNIX_SHM_BASE, n);
+ rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n);
}else{
rc = SQLITE_OK;
}
@@ -28856,7 +30082,7 @@ static int unixShmLock(
** also mark the local connection as being locked.
*/
if( rc==SQLITE_OK ){
- rc = unixShmSystemLock(pShmNode, F_WRLCK, ofst+UNIX_SHM_BASE, n);
+ rc = unixShmSystemLock(pDbFd, F_WRLCK, ofst+UNIX_SHM_BASE, n);
if( rc==SQLITE_OK ){
assert( (p->sharedMask & mask)==0 );
p->exclMask |= mask;
@@ -28865,7 +30091,7 @@ static int unixShmLock(
}
sqlite3_mutex_leave(pShmNode->mutex);
OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n",
- p->id, getpid(), p->sharedMask, p->exclMask));
+ p->id, osGetpid(0), p->sharedMask, p->exclMask));
return rc;
}
@@ -28924,7 +30150,9 @@ static int unixShmUnmap(
assert( pShmNode->nRef>0 );
pShmNode->nRef--;
if( pShmNode->nRef==0 ){
- if( deleteFlag && pShmNode->h>=0 ) osUnlink(pShmNode->zFilename);
+ if( deleteFlag && pShmNode->h>=0 ){
+ osUnlink(pShmNode->zFilename);
+ }
unixShmPurge(pDbFd);
}
unixLeaveMutex();
@@ -29180,7 +30408,7 @@ static int unixUnfetch(sqlite3_file *fd, i64 iOff, void *p){
** looks at the filesystem type and tries to guess the best locking
** strategy from that.
**
-** For finder-funtion F, two objects are created:
+** For finder-function F, two objects are created:
**
** (1) The real finder-function named "FImpt()".
**
@@ -29201,7 +30429,7 @@ static int unixUnfetch(sqlite3_file *fd, i64 iOff, void *p){
** * An I/O method finder function called FINDER that returns a pointer
** to the METHOD object in the previous bullet.
*/
-#define IOMETHODS(FINDER, METHOD, VERSION, CLOSE, LOCK, UNLOCK, CKLOCK) \
+#define IOMETHODS(FINDER,METHOD,VERSION,CLOSE,LOCK,UNLOCK,CKLOCK,SHMMAP) \
static const sqlite3_io_methods METHOD = { \
VERSION, /* iVersion */ \
CLOSE, /* xClose */ \
@@ -29216,7 +30444,7 @@ static const sqlite3_io_methods METHOD = { \
unixFileControl, /* xFileControl */ \
unixSectorSize, /* xSectorSize */ \
unixDeviceCharacteristics, /* xDeviceCapabilities */ \
- unixShmMap, /* xShmMap */ \
+ SHMMAP, /* xShmMap */ \
unixShmLock, /* xShmLock */ \
unixShmBarrier, /* xShmBarrier */ \
unixShmUnmap, /* xShmUnmap */ \
@@ -29242,16 +30470,18 @@ IOMETHODS(
unixClose, /* xClose method */
unixLock, /* xLock method */
unixUnlock, /* xUnlock method */
- unixCheckReservedLock /* xCheckReservedLock method */
+ unixCheckReservedLock, /* xCheckReservedLock method */
+ unixShmMap /* xShmMap method */
)
IOMETHODS(
nolockIoFinder, /* Finder function name */
nolockIoMethods, /* sqlite3_io_methods object name */
- 1, /* shared memory is disabled */
+ 3, /* shared memory is disabled */
nolockClose, /* xClose method */
nolockLock, /* xLock method */
nolockUnlock, /* xUnlock method */
- nolockCheckReservedLock /* xCheckReservedLock method */
+ nolockCheckReservedLock, /* xCheckReservedLock method */
+ 0 /* xShmMap method */
)
IOMETHODS(
dotlockIoFinder, /* Finder function name */
@@ -29260,10 +30490,11 @@ IOMETHODS(
dotlockClose, /* xClose method */
dotlockLock, /* xLock method */
dotlockUnlock, /* xUnlock method */
- dotlockCheckReservedLock /* xCheckReservedLock method */
+ dotlockCheckReservedLock, /* xCheckReservedLock method */
+ 0 /* xShmMap method */
)
-#if SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS
+#if SQLITE_ENABLE_LOCKING_STYLE
IOMETHODS(
flockIoFinder, /* Finder function name */
flockIoMethods, /* sqlite3_io_methods object name */
@@ -29271,7 +30502,8 @@ IOMETHODS(
flockClose, /* xClose method */
flockLock, /* xLock method */
flockUnlock, /* xUnlock method */
- flockCheckReservedLock /* xCheckReservedLock method */
+ flockCheckReservedLock, /* xCheckReservedLock method */
+ 0 /* xShmMap method */
)
#endif
@@ -29280,10 +30512,11 @@ IOMETHODS(
semIoFinder, /* Finder function name */
semIoMethods, /* sqlite3_io_methods object name */
1, /* shared memory is disabled */
- semClose, /* xClose method */
- semLock, /* xLock method */
- semUnlock, /* xUnlock method */
- semCheckReservedLock /* xCheckReservedLock method */
+ semXClose, /* xClose method */
+ semXLock, /* xLock method */
+ semXUnlock, /* xUnlock method */
+ semXCheckReservedLock, /* xCheckReservedLock method */
+ 0 /* xShmMap method */
)
#endif
@@ -29295,7 +30528,8 @@ IOMETHODS(
afpClose, /* xClose method */
afpLock, /* xLock method */
afpUnlock, /* xUnlock method */
- afpCheckReservedLock /* xCheckReservedLock method */
+ afpCheckReservedLock, /* xCheckReservedLock method */
+ 0 /* xShmMap method */
)
#endif
@@ -29320,7 +30554,8 @@ IOMETHODS(
proxyClose, /* xClose method */
proxyLock, /* xLock method */
proxyUnlock, /* xUnlock method */
- proxyCheckReservedLock /* xCheckReservedLock method */
+ proxyCheckReservedLock, /* xCheckReservedLock method */
+ 0 /* xShmMap method */
)
#endif
@@ -29333,7 +30568,8 @@ IOMETHODS(
unixClose, /* xClose method */
unixLock, /* xLock method */
nfsUnlock, /* xUnlock method */
- unixCheckReservedLock /* xCheckReservedLock method */
+ unixCheckReservedLock, /* xCheckReservedLock method */
+ 0 /* xShmMap method */
)
#endif
@@ -29403,15 +30639,13 @@ static const sqlite3_io_methods
#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
-#if OS_VXWORKS && SQLITE_ENABLE_LOCKING_STYLE
-/*
-** This "finder" function attempts to determine the best locking strategy
-** for the database file "filePath". It then returns the sqlite3_io_methods
-** object that implements that strategy.
-**
-** This is for VXWorks only.
+#if OS_VXWORKS
+/*
+** This "finder" function for VxWorks checks to see if posix advisory
+** locking works. If it does, then that is what is used. If it does not
+** work, then fallback to named semaphore locking.
*/
-static const sqlite3_io_methods *autolockIoFinderImpl(
+static const sqlite3_io_methods *vxworksIoFinderImpl(
const char *filePath, /* name of the database file */
unixFile *pNew /* the open file object */
){
@@ -29437,12 +30671,12 @@ static const sqlite3_io_methods *autolockIoFinderImpl(
}
}
static const sqlite3_io_methods
- *(*const autolockIoFinder)(const char*,unixFile*) = autolockIoFinderImpl;
+ *(*const vxworksIoFinder)(const char*,unixFile*) = vxworksIoFinderImpl;
-#endif /* OS_VXWORKS && SQLITE_ENABLE_LOCKING_STYLE */
+#endif /* OS_VXWORKS */
/*
-** An abstract type for a pointer to a IO method finder function:
+** An abstract type for a pointer to an IO method finder function:
*/
typedef const sqlite3_io_methods *(*finder_type)(const char*,unixFile*);
@@ -29558,7 +30792,7 @@ static int fillInUnixFile(
** the afpLockingContext.
*/
afpLockingContext *pCtx;
- pNew->lockingContext = pCtx = sqlite3_malloc( sizeof(*pCtx) );
+ pNew->lockingContext = pCtx = sqlite3_malloc64( sizeof(*pCtx) );
if( pCtx==0 ){
rc = SQLITE_NOMEM;
}else{
@@ -29588,7 +30822,7 @@ static int fillInUnixFile(
int nFilename;
assert( zFilename!=0 );
nFilename = (int)strlen(zFilename) + 6;
- zLockFile = (char *)sqlite3_malloc(nFilename);
+ zLockFile = (char *)sqlite3_malloc64(nFilename);
if( zLockFile==0 ){
rc = SQLITE_NOMEM;
}else{
@@ -29621,7 +30855,7 @@ static int fillInUnixFile(
}
#endif
- pNew->lastErrno = 0;
+ storeLastErrno(pNew, 0);
#if OS_VXWORKS
if( rc!=SQLITE_OK ){
if( h>=0 ) robust_close(pNew, h, __LINE__);
@@ -29756,7 +30990,7 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
** descriptor on the same path, fail, and return an error to SQLite.
**
** Even if a subsequent open() call does succeed, the consequences of
- ** not searching for a resusable file descriptor are not dire. */
+ ** not searching for a reusable file descriptor are not dire. */
if( 0==osStat(zPath, &sStat) ){
unixInodeInfo *pInode;
@@ -29787,7 +31021,7 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
** written to *pMode. If an IO error occurs, an SQLite error code is
** returned and the value of *pMode is not modified.
**
-** In most cases cases, this routine sets *pMode to 0, which will become
+** In most cases, this routine sets *pMode to 0, which will become
** an indication to robust_open() to create the file using
** SQLITE_DEFAULT_FILE_PERMISSIONS adjusted by the umask.
** But if the file being opened is a WAL or regular journal file, then
@@ -29952,8 +31186,8 @@ static int unixOpen(
** the same instant might all reset the PRNG. But multiple resets
** are harmless.
*/
- if( randomnessPid!=getpid() ){
- randomnessPid = getpid();
+ if( randomnessPid!=osGetpid(0) ){
+ randomnessPid = osGetpid(0);
sqlite3_randomness(0,0);
}
@@ -29965,7 +31199,7 @@ static int unixOpen(
if( pUnused ){
fd = pUnused->fd;
}else{
- pUnused = sqlite3_malloc(sizeof(*pUnused));
+ pUnused = sqlite3_malloc64(sizeof(*pUnused));
if( !pUnused ){
return SQLITE_NOMEM;
}
@@ -30069,13 +31303,16 @@ static int unixOpen(
#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
if( fstatfs(fd, &fsInfo) == -1 ){
- ((unixFile*)pFile)->lastErrno = errno;
+ storeLastErrno(p, errno);
robust_close(p, fd, __LINE__);
return SQLITE_IOERR_ACCESS;
}
if (0 == strncmp("msdos", fsInfo.f_fstypename, 5)) {
((unixFile*)pFile)->fsFlags |= SQLITE_FSFLAGS_IS_MSDOS;
}
+ if (0 == strncmp("exfat", fsInfo.f_fstypename, 5)) {
+ ((unixFile*)pFile)->fsFlags |= SQLITE_FSFLAGS_IS_MSDOS;
+ }
#endif
/* Set up appropriate ctrlFlags */
@@ -30098,19 +31335,6 @@ static int unixOpen(
if( envforce!=NULL ){
useProxy = atoi(envforce)>0;
}else{
- if( statfs(zPath, &fsInfo) == -1 ){
- /* In theory, the close(fd) call is sub-optimal. If the file opened
- ** with fd is a database file, and there are other connections open
- ** on that file that are currently holding advisory locks on it,
- ** then the call to close() will cancel those locks. In practice,
- ** we're assuming that statfs() doesn't fail very often. At least
- ** not while other file descriptors opened by the same process on
- ** the same file are working. */
- p->lastErrno = errno;
- robust_close(p, fd, __LINE__);
- rc = SQLITE_IOERR_ACCESS;
- goto open_finished;
- }
useProxy = !(fsInfo.f_flags&MNT_LOCAL);
}
if( useProxy ){
@@ -30156,7 +31380,7 @@ static int unixDelete(
if( osUnlink(zPath)==(-1) ){
if( errno==ENOENT
#if OS_VXWORKS
- || errno==0x380003
+ || osAccess(zPath,0)!=0
#endif
){
rc = SQLITE_IOERR_DELETE_NOENT;
@@ -30354,8 +31578,8 @@ static int unixRandomness(sqlite3_vfs *NotUsed, int nBuf, char *zBuf){
** tests repeatable.
*/
memset(zBuf, 0, nBuf);
- randomnessPid = getpid();
-#if !defined(SQLITE_TEST)
+ randomnessPid = osGetpid(0);
+#if !defined(SQLITE_TEST) && !defined(SQLITE_OMIT_RANDOMNESS)
{
int fd, got;
fd = robust_open("/dev/urandom", O_RDONLY, 0);
@@ -30536,9 +31760,10 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
**
** C APIs
**
-** sqlite3_file_control(db, dbname, SQLITE_SET_LOCKPROXYFILE,
+** sqlite3_file_control(db, dbname, SQLITE_FCNTL_SET_LOCKPROXYFILE,
** <proxy_path> | ":auto:");
-** sqlite3_file_control(db, dbname, SQLITE_GET_LOCKPROXYFILE, &<proxy_path>);
+** sqlite3_file_control(db, dbname, SQLITE_FCNTL_GET_LOCKPROXYFILE,
+** &<proxy_path>);
**
**
** SQL pragmas
@@ -30579,7 +31804,7 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
** proxy path against the values stored in the conch. The conch file is
** stored in the same directory as the database file and the file name
** is patterned after the database file name as ".<databasename>-conch".
-** If the conch file does not exist, or it's contents do not match the
+** If the conch file does not exist, or its contents do not match the
** host ID and/or proxy path, then the lock is escalated to an exclusive
** lock and the conch file contents is updated with the host ID and proxy
** path and the lock is downgraded to a shared lock again. If the conch
@@ -30631,7 +31856,7 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
** setting the environment variable SQLITE_FORCE_PROXY_LOCKING to 1 will
** force proxy locking to be used for every database file opened, and 0
** will force automatic proxy locking to be disabled for all database
-** files (explicity calling the SQLITE_SET_LOCKPROXYFILE pragma or
+** files (explicitly calling the SQLITE_FCNTL_SET_LOCKPROXYFILE pragma or
** sqlite_file_control API is not affected by SQLITE_FORCE_PROXY_LOCKING).
*/
@@ -30652,6 +31877,7 @@ struct proxyLockingContext {
char *lockProxyPath; /* Name of the proxy lock file */
char *dbPath; /* Name of the open file */
int conchHeld; /* 1 if the conch is held, -1 if lockless */
+ int nFails; /* Number of conch taking failures */
void *oldLockingContext; /* Original lockingcontext to restore on close */
sqlite3_io_methods const *pOldMethod; /* Original I/O methods for close */
};
@@ -30673,7 +31899,7 @@ static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){
{
if( !confstr(_CS_DARWIN_USER_TEMP_DIR, lPath, maxLen) ){
OSTRACE(("GETLOCKPATH failed %s errno=%d pid=%d\n",
- lPath, errno, getpid()));
+ lPath, errno, osGetpid(0)));
return SQLITE_IOERR_LOCK;
}
len = strlcat(lPath, "sqliteplocks", maxLen);
@@ -30695,7 +31921,7 @@ static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){
}
lPath[i+len]='\0';
strlcat(lPath, ":auto:", maxLen);
- OSTRACE(("GETLOCKPATH proxy lock path=%s pid=%d\n", lPath, getpid()));
+ OSTRACE(("GETLOCKPATH proxy lock path=%s pid=%d\n", lPath, osGetpid(0)));
return SQLITE_OK;
}
@@ -30722,7 +31948,7 @@ static int proxyCreateLockPath(const char *lockPath){
if( err!=EEXIST ) {
OSTRACE(("CREATELOCKPATH FAILED creating %s, "
"'%s' proxy lock path=%s pid=%d\n",
- buf, strerror(err), lockPath, getpid()));
+ buf, strerror(err), lockPath, osGetpid(0)));
return err;
}
}
@@ -30731,7 +31957,7 @@ static int proxyCreateLockPath(const char *lockPath){
}
buf[i] = lockPath[i];
}
- OSTRACE(("CREATELOCKPATH proxy lock path=%s pid=%d\n", lockPath, getpid()));
+ OSTRACE(("CREATELOCKPATH proxy lock path=%s pid=%d\n", lockPath, osGetpid(0)));
return 0;
}
@@ -30765,7 +31991,7 @@ static int proxyCreateUnixFile(
if( pUnused ){
fd = pUnused->fd;
}else{
- pUnused = sqlite3_malloc(sizeof(*pUnused));
+ pUnused = sqlite3_malloc64(sizeof(*pUnused));
if( !pUnused ){
return SQLITE_NOMEM;
}
@@ -30798,7 +32024,7 @@ static int proxyCreateUnixFile(
}
}
- pNew = (unixFile *)sqlite3_malloc(sizeof(*pNew));
+ pNew = (unixFile *)sqlite3_malloc64(sizeof(*pNew));
if( pNew==NULL ){
rc = SQLITE_NOMEM;
goto end_create_proxy;
@@ -30831,8 +32057,10 @@ SQLITE_API int sqlite3_hostid_num = 0;
#define PROXY_HOSTIDLEN 16 /* conch file host id length */
+#ifdef HAVE_GETHOSTUUID
/* Not always defined in the headers as it ought to be */
extern int gethostuuid(uuid_t id, const struct timespec *wait);
+#endif
/* get the host ID via gethostuuid(), pHostID must point to PROXY_HOSTIDLEN
** bytes of writable memory.
@@ -30840,10 +32068,9 @@ extern int gethostuuid(uuid_t id, const struct timespec *wait);
static int proxyGetHostID(unsigned char *pHostID, int *pError){
assert(PROXY_HOSTIDLEN == sizeof(uuid_t));
memset(pHostID, 0, PROXY_HOSTIDLEN);
-#if defined(__MAX_OS_X_VERSION_MIN_REQUIRED)\
- && __MAC_OS_X_VERSION_MIN_REQUIRED<1050
+#ifdef HAVE_GETHOSTUUID
{
- static const struct timespec timeout = {1, 0}; /* 1 sec timeout */
+ struct timespec timeout = {1, 0}; /* 1 sec timeout */
if( gethostuuid(pHostID, &timeout) ){
int err = errno;
if( pError ){
@@ -30958,7 +32185,7 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){
*/
struct stat buf;
if( osFstat(conchFile->h, &buf) ){
- pFile->lastErrno = errno;
+ storeLastErrno(pFile, errno);
return SQLITE_IOERR_LOCK;
}
@@ -30978,7 +32205,7 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){
char tBuf[PROXY_MAXCONCHLEN];
int len = osPread(conchFile->h, tBuf, PROXY_MAXCONCHLEN, 0);
if( len<0 ){
- pFile->lastErrno = errno;
+ storeLastErrno(pFile, errno);
return SQLITE_IOERR_LOCK;
}
if( len>PROXY_PATHINDEX && tBuf[0]==(char)PROXY_CONCHVERSION){
@@ -30998,7 +32225,7 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){
if( 0==proxyBreakConchLock(pFile, myHostID) ){
rc = SQLITE_OK;
if( lockType==EXCLUSIVE_LOCK ){
- rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, SHARED_LOCK);
+ rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, SHARED_LOCK);
}
if( !rc ){
rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType);
@@ -31036,11 +32263,12 @@ static int proxyTakeConch(unixFile *pFile){
int forceNewLockPath = 0;
OSTRACE(("TAKECONCH %d for %s pid=%d\n", conchFile->h,
- (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), getpid()));
+ (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"),
+ osGetpid(0)));
rc = proxyGetHostID(myHostID, &pError);
if( (rc&0xff)==SQLITE_IOERR ){
- pFile->lastErrno = pError;
+ storeLastErrno(pFile, pError);
goto end_takeconch;
}
rc = proxyConchLock(pFile, myHostID, SHARED_LOCK);
@@ -31051,7 +32279,7 @@ static int proxyTakeConch(unixFile *pFile){
readLen = seekAndRead((unixFile*)conchFile, 0, readBuf, PROXY_MAXCONCHLEN);
if( readLen<0 ){
/* I/O error: lastErrno set by seekAndRead */
- pFile->lastErrno = conchFile->lastErrno;
+ storeLastErrno(pFile, conchFile->lastErrno);
rc = SQLITE_IOERR_READ;
goto end_takeconch;
}else if( readLen<=(PROXY_HEADERLEN+PROXY_HOSTIDLEN) ||
@@ -31124,7 +32352,7 @@ static int proxyTakeConch(unixFile *pFile){
rc = proxyConchLock(pFile, myHostID, EXCLUSIVE_LOCK);
}
}else{
- rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, EXCLUSIVE_LOCK);
+ rc = proxyConchLock(pFile, myHostID, EXCLUSIVE_LOCK);
}
if( rc==SQLITE_OK ){
char writeBuffer[PROXY_MAXCONCHLEN];
@@ -31133,7 +32361,8 @@ static int proxyTakeConch(unixFile *pFile){
writeBuffer[0] = (char)PROXY_CONCHVERSION;
memcpy(&writeBuffer[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN);
if( pCtx->lockProxyPath!=NULL ){
- strlcpy(&writeBuffer[PROXY_PATHINDEX], pCtx->lockProxyPath, MAXPATHLEN);
+ strlcpy(&writeBuffer[PROXY_PATHINDEX], pCtx->lockProxyPath,
+ MAXPATHLEN);
}else{
strlcpy(&writeBuffer[PROXY_PATHINDEX], tempLockPath, MAXPATHLEN);
}
@@ -31245,7 +32474,7 @@ static int proxyReleaseConch(unixFile *pFile){
conchFile = pCtx->conchFile;
OSTRACE(("RELEASECONCH %d for %s pid=%d\n", conchFile->h,
(pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"),
- getpid()));
+ osGetpid(0)));
if( pCtx->conchHeld>0 ){
rc = conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, NO_LOCK);
}
@@ -31257,7 +32486,7 @@ static int proxyReleaseConch(unixFile *pFile){
/*
** Given the name of a database file, compute the name of its conch file.
-** Store the conch filename in memory obtained from sqlite3_malloc().
+** Store the conch filename in memory obtained from sqlite3_malloc64().
** Make *pConchPath point to the new name. Return SQLITE_OK on success
** or SQLITE_NOMEM if unable to obtain memory.
**
@@ -31273,7 +32502,7 @@ static int proxyCreateConchPathname(char *dbPath, char **pConchPath){
/* Allocate space for the conch filename and initialize the name to
** the name of the original database file. */
- *pConchPath = conchPath = (char *)sqlite3_malloc(len + 8);
+ *pConchPath = conchPath = (char *)sqlite3_malloc64(len + 8);
if( conchPath==0 ){
return SQLITE_NOMEM;
}
@@ -31345,7 +32574,8 @@ static int proxyGetDbPathForUnixFile(unixFile *pFile, char *dbPath){
/* afp style keeps a reference to the db path in the filePath field
** of the struct */
assert( (int)strlen((char*)pFile->lockingContext)<=MAXPATHLEN );
- strlcpy(dbPath, ((afpLockingContext *)pFile->lockingContext)->dbPath, MAXPATHLEN);
+ strlcpy(dbPath, ((afpLockingContext *)pFile->lockingContext)->dbPath,
+ MAXPATHLEN);
} else
#endif
if( pFile->pMethod == &dotlockIoMethods ){
@@ -31386,9 +32616,9 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
}
OSTRACE(("TRANSPROXY %d for %s pid=%d\n", pFile->h,
- (lockPath ? lockPath : ":auto:"), getpid()));
+ (lockPath ? lockPath : ":auto:"), osGetpid(0)));
- pCtx = sqlite3_malloc( sizeof(*pCtx) );
+ pCtx = sqlite3_malloc64( sizeof(*pCtx) );
if( pCtx==0 ){
return SQLITE_NOMEM;
}
@@ -31458,7 +32688,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
*/
static int proxyFileControl(sqlite3_file *id, int op, void *pArg){
switch( op ){
- case SQLITE_GET_LOCKPROXYFILE: {
+ case SQLITE_FCNTL_GET_LOCKPROXYFILE: {
unixFile *pFile = (unixFile*)id;
if( pFile->pMethod == &proxyIoMethods ){
proxyLockingContext *pCtx = (proxyLockingContext*)pFile->lockingContext;
@@ -31473,13 +32703,16 @@ static int proxyFileControl(sqlite3_file *id, int op, void *pArg){
}
return SQLITE_OK;
}
- case SQLITE_SET_LOCKPROXYFILE: {
+ case SQLITE_FCNTL_SET_LOCKPROXYFILE: {
unixFile *pFile = (unixFile*)id;
int rc = SQLITE_OK;
int isProxyStyle = (pFile->pMethod == &proxyIoMethods);
if( pArg==NULL || (const char *)pArg==0 ){
if( isProxyStyle ){
- /* turn off proxy locking - not supported */
+ /* turn off proxy locking - not supported. If support is added for
+ ** switching proxy locking mode off then it will need to fail if
+ ** the journal mode is WAL mode.
+ */
rc = SQLITE_ERROR /*SQLITE_PROTOCOL? SQLITE_MISUSE?*/;
}else{
/* turn off proxy locking - already off - NOOP */
@@ -31670,7 +32903,7 @@ static int proxyClose(sqlite3_file *id) {
** necessarily been initialized when this routine is called, and so they
** should not be used.
*/
-SQLITE_API int sqlite3_os_init(void){
+SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void){
/*
** The following macro defines an initializer for an sqlite3_vfs object.
** The name of the VFS is NAME. The pAppData is a pointer to a pointer
@@ -31724,8 +32957,10 @@ SQLITE_API int sqlite3_os_init(void){
** array cannot be const.
*/
static sqlite3_vfs aVfs[] = {
-#if SQLITE_ENABLE_LOCKING_STYLE && (OS_VXWORKS || defined(__APPLE__))
+#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
UNIXVFS("unix", autolockIoFinder ),
+#elif OS_VXWORKS
+ UNIXVFS("unix", vxworksIoFinder ),
#else
UNIXVFS("unix", posixIoFinder ),
#endif
@@ -31735,11 +32970,11 @@ SQLITE_API int sqlite3_os_init(void){
#if OS_VXWORKS
UNIXVFS("unix-namedsem", semIoFinder ),
#endif
-#if SQLITE_ENABLE_LOCKING_STYLE
+#if SQLITE_ENABLE_LOCKING_STYLE || OS_VXWORKS
UNIXVFS("unix-posix", posixIoFinder ),
-#if !OS_VXWORKS
- UNIXVFS("unix-flock", flockIoFinder ),
#endif
+#if SQLITE_ENABLE_LOCKING_STYLE
+ UNIXVFS("unix-flock", flockIoFinder ),
#endif
#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
UNIXVFS("unix-afp", afpIoFinder ),
@@ -31767,7 +33002,7 @@ SQLITE_API int sqlite3_os_init(void){
** to release dynamically allocated objects. But not on unix.
** This routine is a no-op for unix.
*/
-SQLITE_API int sqlite3_os_end(void){
+SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void){
return SQLITE_OK;
}
@@ -31827,16 +33062,6 @@ SQLITE_API int sqlite3_os_end(void){
# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead."
#endif
-#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
-# ifndef SQLITE_DEBUG_OS_TRACE
-# define SQLITE_DEBUG_OS_TRACE 0
-# endif
- int sqlite3OSTrace = SQLITE_DEBUG_OS_TRACE;
-# define OSTRACE(X) if( sqlite3OSTrace ) sqlite3DebugPrintf X
-#else
-# define OSTRACE(X)
-#endif
-
/*
** Macros for performance tracing. Normally turned off. Only works
** on i486 hardware.
@@ -32017,6 +33242,11 @@ SQLITE_API int sqlite3_open_file_count = 0;
with SQLITE_OMIT_WAL."
#endif
+#if !SQLITE_OS_WINNT && SQLITE_MAX_MMAP_SIZE>0
+# error "Memory mapped files require support from the Windows NT kernel,\
+ compile with SQLITE_MAX_MMAP_SIZE=0."
+#endif
+
/*
** Are most of the Win32 ANSI APIs available (i.e. with certain exceptions
** based on the sub-platform)?
@@ -32146,10 +33376,11 @@ SQLITE_API int sqlite3_open_file_count = 0;
/*
** Do we need to manually define the Win32 file mapping APIs for use with WAL
-** mode (e.g. these APIs are available in the Windows CE SDK; however, they
-** are not present in the header file)?
+** mode or memory mapped files (e.g. these APIs are available in the Windows
+** CE SDK; however, they are not present in the header file)?
*/
-#if SQLITE_WIN32_FILEMAPPING_API && !defined(SQLITE_OMIT_WAL)
+#if SQLITE_WIN32_FILEMAPPING_API && \
+ (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)
/*
** Two of the file mapping APIs are different under WinRT. Figure out which
** set we need.
@@ -32174,10 +33405,12 @@ WINBASEAPI LPVOID WINAPI MapViewOfFile(HANDLE, DWORD, DWORD, DWORD, SIZE_T);
#endif /* SQLITE_OS_WINRT */
/*
-** This file mapping API is common to both Win32 and WinRT.
+** These file mapping APIs are common to both Win32 and WinRT.
*/
+
+WINBASEAPI BOOL WINAPI FlushViewOfFile(LPCVOID, SIZE_T);
WINBASEAPI BOOL WINAPI UnmapViewOfFile(LPCVOID);
-#endif /* SQLITE_WIN32_FILEMAPPING_API && !defined(SQLITE_OMIT_WAL) */
+#endif /* SQLITE_WIN32_FILEMAPPING_API */
/*
** Some Microsoft compilers lack this definition.
@@ -32393,9 +33626,9 @@ SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetWin32(void);
** can manually set this value to 1 to emulate Win98 behavior.
*/
#ifdef SQLITE_TEST
-SQLITE_API LONG volatile sqlite3_os_type = 0;
+SQLITE_API LONG SQLITE_WIN32_VOLATILE sqlite3_os_type = 0;
#else
-static LONG volatile sqlite3_os_type = 0;
+static LONG SQLITE_WIN32_VOLATILE sqlite3_os_type = 0;
#endif
#ifndef SYSCALL
@@ -32470,7 +33703,7 @@ static struct win_syscall {
LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[5].pCurrent)
#if (!SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_ANSI) && \
- !defined(SQLITE_OMIT_WAL))
+ (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0))
{ "CreateFileMappingA", (SYSCALL)CreateFileMappingA, 0 },
#else
{ "CreateFileMappingA", (SYSCALL)0, 0 },
@@ -32480,7 +33713,7 @@ static struct win_syscall {
DWORD,DWORD,DWORD,LPCSTR))aSyscall[6].pCurrent)
#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \
- !defined(SQLITE_OMIT_WAL))
+ (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0))
{ "CreateFileMappingW", (SYSCALL)CreateFileMappingW, 0 },
#else
{ "CreateFileMappingW", (SYSCALL)0, 0 },
@@ -32820,7 +34053,8 @@ static struct win_syscall {
LPOVERLAPPED))aSyscall[48].pCurrent)
#endif
-#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && !defined(SQLITE_OMIT_WAL))
+#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && \
+ (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0))
{ "MapViewOfFile", (SYSCALL)MapViewOfFile, 0 },
#else
{ "MapViewOfFile", (SYSCALL)0, 0 },
@@ -32890,7 +34124,7 @@ static struct win_syscall {
#define osUnlockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
LPOVERLAPPED))aSyscall[58].pCurrent)
-#if SQLITE_OS_WINCE || !defined(SQLITE_OMIT_WAL)
+#if SQLITE_OS_WINCE || !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
{ "UnmapViewOfFile", (SYSCALL)UnmapViewOfFile, 0 },
#else
{ "UnmapViewOfFile", (SYSCALL)0, 0 },
@@ -32926,7 +34160,7 @@ static struct win_syscall {
#define osWaitForSingleObject ((DWORD(WINAPI*)(HANDLE, \
DWORD))aSyscall[63].pCurrent)
-#if SQLITE_OS_WINRT
+#if !SQLITE_OS_WINCE
{ "WaitForSingleObjectEx", (SYSCALL)WaitForSingleObjectEx, 0 },
#else
{ "WaitForSingleObjectEx", (SYSCALL)0, 0 },
@@ -32953,7 +34187,7 @@ static struct win_syscall {
#define osGetFileInformationByHandleEx ((BOOL(WINAPI*)(HANDLE, \
FILE_INFO_BY_HANDLE_CLASS,LPVOID,DWORD))aSyscall[66].pCurrent)
-#if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_WAL)
+#if SQLITE_OS_WINRT && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)
{ "MapViewOfFileFromApp", (SYSCALL)MapViewOfFileFromApp, 0 },
#else
{ "MapViewOfFileFromApp", (SYSCALL)0, 0 },
@@ -33017,7 +34251,7 @@ static struct win_syscall {
#define osGetProcessHeap ((HANDLE(WINAPI*)(VOID))aSyscall[74].pCurrent)
-#if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_WAL)
+#if SQLITE_OS_WINRT && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)
{ "CreateFileMappingFromApp", (SYSCALL)CreateFileMappingFromApp, 0 },
#else
{ "CreateFileMappingFromApp", (SYSCALL)0, 0 },
@@ -33038,10 +34272,36 @@ static struct win_syscall {
#else
{ "InterlockedCompareExchange", (SYSCALL)InterlockedCompareExchange, 0 },
-#define osInterlockedCompareExchange ((LONG(WINAPI*)(LONG volatile*, \
- LONG,LONG))aSyscall[76].pCurrent)
+#define osInterlockedCompareExchange ((LONG(WINAPI*)(LONG \
+ SQLITE_WIN32_VOLATILE*, LONG,LONG))aSyscall[76].pCurrent)
#endif /* defined(InterlockedCompareExchange) */
+#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID
+ { "UuidCreate", (SYSCALL)UuidCreate, 0 },
+#else
+ { "UuidCreate", (SYSCALL)0, 0 },
+#endif
+
+#define osUuidCreate ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[77].pCurrent)
+
+#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID
+ { "UuidCreateSequential", (SYSCALL)UuidCreateSequential, 0 },
+#else
+ { "UuidCreateSequential", (SYSCALL)0, 0 },
+#endif
+
+#define osUuidCreateSequential \
+ ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[78].pCurrent)
+
+#if !defined(SQLITE_NO_SYNC) && SQLITE_MAX_MMAP_SIZE>0
+ { "FlushViewOfFile", (SYSCALL)FlushViewOfFile, 0 },
+#else
+ { "FlushViewOfFile", (SYSCALL)0, 0 },
+#endif
+
+#define osFlushViewOfFile \
+ ((BOOL(WINAPI*)(LPCVOID,SIZE_T))aSyscall[79].pCurrent)
+
}; /* End of the overrideable system calls */
/*
@@ -33135,7 +34395,7 @@ static const char *winNextSystemCall(sqlite3_vfs *p, const char *zName){
** "pnLargest" argument, if non-zero, will be used to return the size of the
** largest committed free block in the heap, in bytes.
*/
-SQLITE_API int sqlite3_win32_compact_heap(LPUINT pnLargest){
+SQLITE_API int SQLITE_STDCALL sqlite3_win32_compact_heap(LPUINT pnLargest){
int rc = SQLITE_OK;
UINT nLargest = 0;
HANDLE hHeap;
@@ -33175,12 +34435,12 @@ SQLITE_API int sqlite3_win32_compact_heap(LPUINT pnLargest){
** the sqlite3_memory_used() function does not return zero, SQLITE_BUSY will
** be returned and no changes will be made to the Win32 native heap.
*/
-SQLITE_API int sqlite3_win32_reset_heap(){
+SQLITE_API int SQLITE_STDCALL sqlite3_win32_reset_heap(){
int rc;
MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */
MUTEX_LOGIC( sqlite3_mutex *pMem; ) /* The memsys static mutex */
- MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
- MUTEX_LOGIC( pMem = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); )
+ MUTEX_LOGIC( pMaster = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); )
+ MUTEX_LOGIC( pMem = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM); )
sqlite3_mutex_enter(pMaster);
sqlite3_mutex_enter(pMem);
winMemAssertMagic();
@@ -33220,7 +34480,7 @@ SQLITE_API int sqlite3_win32_reset_heap(){
** (if available).
*/
-SQLITE_API void sqlite3_win32_write_debug(const char *zBuf, int nBuf){
+SQLITE_API void SQLITE_STDCALL sqlite3_win32_write_debug(const char *zBuf, int nBuf){
char zDbgBuf[SQLITE_WIN32_DBG_BUF_SIZE];
int nMin = MIN(nBuf, (SQLITE_WIN32_DBG_BUF_SIZE - 1)); /* may be negative. */
if( nMin<-1 ) nMin = -1; /* all negative values become -1. */
@@ -33260,7 +34520,7 @@ SQLITE_API void sqlite3_win32_write_debug(const char *zBuf, int nBuf){
static HANDLE sleepObj = NULL;
#endif
-SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds){
+SQLITE_API void SQLITE_STDCALL sqlite3_win32_sleep(DWORD milliseconds){
#if SQLITE_OS_WINRT
if ( sleepObj==NULL ){
sleepObj = osCreateEventExW(NULL, NULL, CREATE_EVENT_MANUAL_RESET,
@@ -33273,6 +34533,16 @@ SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds){
#endif
}
+#if SQLITE_MAX_WORKER_THREADS>0 && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \
+ SQLITE_THREADSAFE>0
+SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject){
+ DWORD rc;
+ while( (rc = osWaitForSingleObjectEx(hObject, INFINITE,
+ TRUE))==WAIT_IO_COMPLETION ){}
+ return rc;
+}
+#endif
+
/*
** Return true (non-zero) if we are running under WinNT, Win2K, WinXP,
** or WinCE. Return false (zero) for Win95, Win98, or WinME.
@@ -33299,20 +34569,25 @@ SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds){
** This function determines if the machine is running a version of Windows
** based on the NT kernel.
*/
-SQLITE_API int sqlite3_win32_is_nt(void){
-#if defined(SQLITE_WIN32_GETVERSIONEX) && SQLITE_WIN32_GETVERSIONEX
+SQLITE_API int SQLITE_STDCALL sqlite3_win32_is_nt(void){
+#if SQLITE_OS_WINRT
+ /*
+ ** NOTE: The WinRT sub-platform is always assumed to be based on the NT
+ ** kernel.
+ */
+ return 1;
+#elif defined(SQLITE_WIN32_GETVERSIONEX) && SQLITE_WIN32_GETVERSIONEX
if( osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0 ){
-#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \
- defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WIN8
- OSVERSIONINFOW sInfo;
+#if defined(SQLITE_WIN32_HAS_ANSI)
+ OSVERSIONINFOA sInfo;
sInfo.dwOSVersionInfoSize = sizeof(sInfo);
- osGetVersionExW(&sInfo);
+ osGetVersionExA(&sInfo);
osInterlockedCompareExchange(&sqlite3_os_type,
(sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0);
-#elif defined(SQLITE_WIN32_HAS_ANSI)
- OSVERSIONINFOA sInfo;
+#elif defined(SQLITE_WIN32_HAS_WIDE)
+ OSVERSIONINFOW sInfo;
sInfo.dwOSVersionInfoSize = sizeof(sInfo);
- osGetVersionExA(&sInfo);
+ osGetVersionExW(&sInfo);
osInterlockedCompareExchange(&sqlite3_os_type,
(sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0);
#endif
@@ -33321,6 +34596,10 @@ SQLITE_API int sqlite3_win32_is_nt(void){
#elif SQLITE_TEST
return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2;
#else
+ /*
+ ** NOTE: All sub-platforms where the GetVersionEx[AW] functions are
+ ** deprecated are always assumed to be based on the NT kernel.
+ */
return 1;
#endif
}
@@ -33644,7 +34923,7 @@ static char *winUnicodeToMbcs(LPCWSTR zWideFilename){
** Convert multibyte character string to UTF-8. Space to hold the
** returned string is obtained from sqlite3_malloc().
*/
-SQLITE_API char *sqlite3_win32_mbcs_to_utf8(const char *zFilename){
+SQLITE_API char *SQLITE_STDCALL sqlite3_win32_mbcs_to_utf8(const char *zFilename){
char *zFilenameUtf8;
LPWSTR zTmpWide;
@@ -33661,7 +34940,7 @@ SQLITE_API char *sqlite3_win32_mbcs_to_utf8(const char *zFilename){
** Convert UTF-8 to multibyte character string. Space to hold the
** returned string is obtained from sqlite3_malloc().
*/
-SQLITE_API char *sqlite3_win32_utf8_to_mbcs(const char *zFilename){
+SQLITE_API char *SQLITE_STDCALL sqlite3_win32_utf8_to_mbcs(const char *zFilename){
char *zFilenameMbcs;
LPWSTR zTmpWide;
@@ -33681,7 +34960,7 @@ SQLITE_API char *sqlite3_win32_utf8_to_mbcs(const char *zFilename){
** argument is the name of the directory to use. The return value will be
** SQLITE_OK if successful.
*/
-SQLITE_API int sqlite3_win32_set_directory(DWORD type, LPCWSTR zValue){
+SQLITE_API int SQLITE_STDCALL sqlite3_win32_set_directory(DWORD type, LPCWSTR zValue){
char **ppDirectory = 0;
#ifndef SQLITE_OMIT_AUTOINIT
int rc = sqlite3_initialize();
@@ -33906,11 +35185,11 @@ static int winRetryIoerr(int *pnRetry, DWORD *pError){
/*
** Log a I/O error retry episode.
*/
-static void winLogIoerr(int nRetry){
+static void winLogIoerr(int nRetry, int lineno){
if( nRetry ){
- sqlite3_log(SQLITE_IOERR,
- "delayed %dms for lock/sharing conflict",
- winIoerrRetryDelay*nRetry*(nRetry+1)/2
+ sqlite3_log(SQLITE_NOTICE,
+ "delayed %dms for lock/sharing conflict at line %d",
+ winIoerrRetryDelay*nRetry*(nRetry+1)/2, lineno
);
}
}
@@ -34390,7 +35669,8 @@ static int winClose(sqlite3_file *id){
assert( pFile->pShm==0 );
#endif
assert( pFile->h!=NULL && pFile->h!=INVALID_HANDLE_VALUE );
- OSTRACE(("CLOSE file=%p\n", pFile->h));
+ OSTRACE(("CLOSE pid=%lu, pFile=%p, file=%p\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
#if SQLITE_MAX_MMAP_SIZE>0
winUnmapfile(pFile);
@@ -34419,7 +35699,8 @@ static int winClose(sqlite3_file *id){
pFile->h = NULL;
}
OpenCounter(-1);
- OSTRACE(("CLOSE file=%p, rc=%s\n", pFile->h, rc ? "ok" : "failed"));
+ OSTRACE(("CLOSE pid=%lu, pFile=%p, file=%p, rc=%s\n",
+ osGetCurrentProcessId(), pFile, pFile->h, rc ? "ok" : "failed"));
return rc ? SQLITE_OK
: winLogError(SQLITE_IOERR_CLOSE, osGetLastError(),
"winClose", pFile->zPath);
@@ -34436,7 +35717,7 @@ static int winRead(
int amt, /* Number of bytes to read */
sqlite3_int64 offset /* Begin reading at this offset */
){
-#if !SQLITE_OS_WINCE
+#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
OVERLAPPED overlapped; /* The offset for ReadFile. */
#endif
winFile *pFile = (winFile*)id; /* file handle */
@@ -34447,7 +35728,8 @@ static int winRead(
assert( amt>0 );
assert( offset>=0 );
SimulateIOError(return SQLITE_IOERR_READ);
- OSTRACE(("READ file=%p, buffer=%p, amount=%d, offset=%lld, lock=%d\n",
+ OSTRACE(("READ pid=%lu, pFile=%p, file=%p, buffer=%p, amount=%d, "
+ "offset=%lld, lock=%d\n", osGetCurrentProcessId(), pFile,
pFile->h, pBuf, amt, offset, pFile->locktype));
#if SQLITE_MAX_MMAP_SIZE>0
@@ -34456,7 +35738,8 @@ static int winRead(
if( offset<pFile->mmapSize ){
if( offset+amt <= pFile->mmapSize ){
memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], amt);
- OSTRACE(("READ-MMAP file=%p, rc=SQLITE_OK\n", pFile->h));
+ OSTRACE(("READ-MMAP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_OK;
}else{
int nCopy = (int)(pFile->mmapSize - offset);
@@ -34468,9 +35751,10 @@ static int winRead(
}
#endif
-#if SQLITE_OS_WINCE
+#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED)
if( winSeekFile(pFile, offset) ){
- OSTRACE(("READ file=%p, rc=SQLITE_FULL\n", pFile->h));
+ OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_FULL\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_FULL;
}
while( !osReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
@@ -34484,19 +35768,22 @@ static int winRead(
DWORD lastErrno;
if( winRetryIoerr(&nRetry, &lastErrno) ) continue;
pFile->lastErrno = lastErrno;
- OSTRACE(("READ file=%p, rc=SQLITE_IOERR_READ\n", pFile->h));
+ OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_READ\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return winLogError(SQLITE_IOERR_READ, pFile->lastErrno,
"winRead", pFile->zPath);
}
- winLogIoerr(nRetry);
+ winLogIoerr(nRetry, __LINE__);
if( nRead<(DWORD)amt ){
/* Unread parts of the buffer must be zero-filled */
memset(&((char*)pBuf)[nRead], 0, amt-nRead);
- OSTRACE(("READ file=%p, rc=SQLITE_IOERR_SHORT_READ\n", pFile->h));
+ OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_SHORT_READ\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_IOERR_SHORT_READ;
}
- OSTRACE(("READ file=%p, rc=SQLITE_OK\n", pFile->h));
+ OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_OK;
}
@@ -34519,7 +35806,8 @@ static int winWrite(
SimulateIOError(return SQLITE_IOERR_WRITE);
SimulateDiskfullError(return SQLITE_FULL);
- OSTRACE(("WRITE file=%p, buffer=%p, amount=%d, offset=%lld, lock=%d\n",
+ OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, buffer=%p, amount=%d, "
+ "offset=%lld, lock=%d\n", osGetCurrentProcessId(), pFile,
pFile->h, pBuf, amt, offset, pFile->locktype));
#if SQLITE_MAX_MMAP_SIZE>0
@@ -34528,7 +35816,8 @@ static int winWrite(
if( offset<pFile->mmapSize ){
if( offset+amt <= pFile->mmapSize ){
memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, amt);
- OSTRACE(("WRITE-MMAP file=%p, rc=SQLITE_OK\n", pFile->h));
+ OSTRACE(("WRITE-MMAP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_OK;
}else{
int nCopy = (int)(pFile->mmapSize - offset);
@@ -34540,13 +35829,13 @@ static int winWrite(
}
#endif
-#if SQLITE_OS_WINCE
+#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED)
rc = winSeekFile(pFile, offset);
if( rc==0 ){
#else
{
#endif
-#if !SQLITE_OS_WINCE
+#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
OVERLAPPED overlapped; /* The offset for WriteFile. */
#endif
u8 *aRem = (u8 *)pBuf; /* Data yet to be written */
@@ -34554,14 +35843,14 @@ static int winWrite(
DWORD nWrite; /* Bytes written by each WriteFile() call */
DWORD lastErrno = NO_ERROR; /* Value returned by GetLastError() */
-#if !SQLITE_OS_WINCE
+#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
memset(&overlapped, 0, sizeof(OVERLAPPED));
overlapped.Offset = (LONG)(offset & 0xffffffff);
overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
#endif
while( nRem>0 ){
-#if SQLITE_OS_WINCE
+#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED)
if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, 0) ){
#else
if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, &overlapped) ){
@@ -34574,7 +35863,7 @@ static int winWrite(
lastErrno = osGetLastError();
break;
}
-#if !SQLITE_OS_WINCE
+#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
offset += nWrite;
overlapped.Offset = (LONG)(offset & 0xffffffff);
overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
@@ -34591,17 +35880,20 @@ static int winWrite(
if( rc ){
if( ( pFile->lastErrno==ERROR_HANDLE_DISK_FULL )
|| ( pFile->lastErrno==ERROR_DISK_FULL )){
- OSTRACE(("WRITE file=%p, rc=SQLITE_FULL\n", pFile->h));
+ OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_FULL\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return winLogError(SQLITE_FULL, pFile->lastErrno,
"winWrite1", pFile->zPath);
}
- OSTRACE(("WRITE file=%p, rc=SQLITE_IOERR_WRITE\n", pFile->h));
+ OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_WRITE\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return winLogError(SQLITE_IOERR_WRITE, pFile->lastErrno,
"winWrite2", pFile->zPath);
}else{
- winLogIoerr(nRetry);
+ winLogIoerr(nRetry, __LINE__);
}
- OSTRACE(("WRITE file=%p, rc=SQLITE_OK\n", pFile->h));
+ OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_OK;
}
@@ -34615,8 +35907,8 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
assert( pFile );
SimulateIOError(return SQLITE_IOERR_TRUNCATE);
- OSTRACE(("TRUNCATE file=%p, size=%lld, lock=%d\n",
- pFile->h, nByte, pFile->locktype));
+ OSTRACE(("TRUNCATE pid=%lu, pFile=%p, file=%p, size=%lld, lock=%d\n",
+ osGetCurrentProcessId(), pFile, pFile->h, nByte, pFile->locktype));
/* If the user has configured a chunk-size for this file, truncate the
** file so that it consists of an integer number of chunks (i.e. the
@@ -34648,7 +35940,8 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
}
#endif
- OSTRACE(("TRUNCATE file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc)));
+ OSTRACE(("TRUNCATE pid=%lu, pFile=%p, file=%p, rc=%s\n",
+ osGetCurrentProcessId(), pFile, pFile->h, sqlite3ErrName(rc)));
return rc;
}
@@ -34672,7 +35965,7 @@ static int winSync(sqlite3_file *id, int flags){
BOOL rc;
#endif
#if !defined(NDEBUG) || !defined(SQLITE_NO_SYNC) || \
- (defined(SQLITE_TEST) && defined(SQLITE_DEBUG))
+ defined(SQLITE_HAVE_OS_TRACE)
/*
** Used when SQLITE_NO_SYNC is not defined and by the assert() and/or
** OSTRACE() macros.
@@ -34693,8 +35986,9 @@ static int winSync(sqlite3_file *id, int flags){
*/
SimulateDiskfullError( return SQLITE_FULL );
- OSTRACE(("SYNC file=%p, flags=%x, lock=%d\n",
- pFile->h, flags, pFile->locktype));
+ OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, flags=%x, lock=%d\n",
+ osGetCurrentProcessId(), pFile, pFile->h, flags,
+ pFile->locktype));
#ifndef SQLITE_TEST
UNUSED_PARAMETER(flags);
@@ -34709,19 +36003,38 @@ static int winSync(sqlite3_file *id, int flags){
** no-op
*/
#ifdef SQLITE_NO_SYNC
- OSTRACE(("SYNC-NOP file=%p, rc=SQLITE_OK\n", pFile->h));
+ OSTRACE(("SYNC-NOP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_OK;
#else
+#if SQLITE_MAX_MMAP_SIZE>0
+ if( pFile->pMapRegion ){
+ if( osFlushViewOfFile(pFile->pMapRegion, 0) ){
+ OSTRACE(("SYNC-MMAP pid=%lu, pFile=%p, pMapRegion=%p, "
+ "rc=SQLITE_OK\n", osGetCurrentProcessId(),
+ pFile, pFile->pMapRegion));
+ }else{
+ pFile->lastErrno = osGetLastError();
+ OSTRACE(("SYNC-MMAP pid=%lu, pFile=%p, pMapRegion=%p, "
+ "rc=SQLITE_IOERR_MMAP\n", osGetCurrentProcessId(),
+ pFile, pFile->pMapRegion));
+ return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno,
+ "winSync1", pFile->zPath);
+ }
+ }
+#endif
rc = osFlushFileBuffers(pFile->h);
SimulateIOError( rc=FALSE );
if( rc ){
- OSTRACE(("SYNC file=%p, rc=SQLITE_OK\n", pFile->h));
+ OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_OK;
}else{
pFile->lastErrno = osGetLastError();
- OSTRACE(("SYNC file=%p, rc=SQLITE_IOERR_FSYNC\n", pFile->h));
+ OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_FSYNC\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return winLogError(SQLITE_IOERR_FSYNC, pFile->lastErrno,
- "winSync", pFile->zPath);
+ "winSync2", pFile->zPath);
}
#endif
}
@@ -35097,7 +36410,7 @@ static int winUnlock(sqlite3_file *id, int locktype){
}
/*
-** If *pArg is inititially negative then this is a query. Set *pArg to
+** If *pArg is initially negative then this is a query. Set *pArg to
** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set.
**
** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags.
@@ -35329,7 +36642,7 @@ struct winShmNode {
int nRef; /* Number of winShm objects pointing to this */
winShm *pFirst; /* All winShm objects pointing to this */
winShmNode *pNext; /* Next in list of all winShmNode objects */
-#ifdef SQLITE_DEBUG
+#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
u8 nextShmId; /* Next available winShm.id value */
#endif
};
@@ -35360,7 +36673,7 @@ struct winShm {
u8 hasMutex; /* True if holding the winShmNode mutex */
u16 sharedMask; /* Mask of shared locks held */
u16 exclMask; /* Mask of exclusive locks held */
-#ifdef SQLITE_DEBUG
+#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
u8 id; /* Id of this connection with its winShmNode */
#endif
};
@@ -35551,7 +36864,7 @@ static int winOpenSharedMemory(winFile *pDbFd){
/* Make the new connection a child of the winShmNode */
p->pShmNode = pShmNode;
-#ifdef SQLITE_DEBUG
+#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
p->id = pShmNode->nextShmId++;
#endif
pShmNode->nRef++;
@@ -35771,16 +37084,16 @@ static int winShmMap(
void volatile **pp /* OUT: Mapped memory */
){
winFile *pDbFd = (winFile*)fd;
- winShm *p = pDbFd->pShm;
+ winShm *pShm = pDbFd->pShm;
winShmNode *pShmNode;
int rc = SQLITE_OK;
- if( !p ){
+ if( !pShm ){
rc = winOpenSharedMemory(pDbFd);
if( rc!=SQLITE_OK ) return rc;
- p = pDbFd->pShm;
+ pShm = pDbFd->pShm;
}
- pShmNode = p->pShmNode;
+ pShmNode = pShm->pShmNode;
sqlite3_mutex_enter(pShmNode->mutex);
assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
@@ -35820,7 +37133,7 @@ static int winShmMap(
}
/* Map the requested memory region into this processes address space. */
- apNew = (struct ShmRegion *)sqlite3_realloc(
+ apNew = (struct ShmRegion *)sqlite3_realloc64(
pShmNode->aRegion, (iRegion+1)*sizeof(apNew[0])
);
if( !apNew ){
@@ -36111,7 +37424,7 @@ static int winUnfetch(sqlite3_file *fd, i64 iOff, void *p){
}else{
/* FIXME: If Windows truly always prevents truncating or deleting a
** file while a mapping is held, then the following winUnmapfile() call
- ** is unnecessary can can be omitted - potentially improving
+ ** is unnecessary can be omitted - potentially improving
** performance. */
winUnmapfile(pFd);
}
@@ -36692,7 +38005,7 @@ static int winOpen(
}
}
#endif
- winLogIoerr(cnt);
+ winLogIoerr(cnt, __LINE__);
OSTRACE(("OPEN file=%p, name=%s, access=%lx, rc=%s\n", h, zUtf8Name,
dwDesiredAccess, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok"));
@@ -36876,7 +38189,7 @@ static int winDelete(
if( rc && rc!=SQLITE_IOERR_DELETE_NOENT ){
rc = winLogError(SQLITE_IOERR_DELETE, lastErrno, "winDelete", zFilename);
}else{
- winLogIoerr(cnt);
+ winLogIoerr(cnt, __LINE__);
}
sqlite3_free(zConverted);
OSTRACE(("DELETE name=%s, rc=%s\n", zFilename, sqlite3ErrName(rc)));
@@ -36926,7 +38239,7 @@ static int winAccess(
attr = sAttrData.dwFileAttributes;
}
}else{
- winLogIoerr(cnt);
+ winLogIoerr(cnt, __LINE__);
if( lastErrno!=ERROR_FILE_NOT_FOUND && lastErrno!=ERROR_PATH_NOT_FOUND ){
sqlite3_free(zConverted);
return winLogError(SQLITE_IOERR_ACCESS, lastErrno, "winAccess",
@@ -37267,7 +38580,7 @@ static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){
static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
int n = 0;
UNUSED_PARAMETER(pVfs);
-#if defined(SQLITE_TEST)
+#if defined(SQLITE_TEST) || defined(SQLITE_OMIT_RANDOMNESS)
n = nBuf;
memset(zBuf, 0, nBuf);
#else
@@ -37301,7 +38614,23 @@ static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
memcpy(&zBuf[n], &i, sizeof(i));
n += sizeof(i);
}
+#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID
+ if( sizeof(UUID)<=nBuf-n ){
+ UUID id;
+ memset(&id, 0, sizeof(UUID));
+ osUuidCreate(&id);
+ memcpy(zBuf, &id, sizeof(UUID));
+ n += sizeof(UUID);
+ }
+ if( sizeof(UUID)<=nBuf-n ){
+ UUID id;
+ memset(&id, 0, sizeof(UUID));
+ osUuidCreateSequential(&id);
+ memcpy(zBuf, &id, sizeof(UUID));
+ n += sizeof(UUID);
+ }
#endif
+#endif /* defined(SQLITE_TEST) || defined(SQLITE_ZERO_PRNG_SEED) */
return n;
}
@@ -37425,7 +38754,7 @@ static int winGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
/*
** Initialize and deinitialize the operating system interface.
*/
-SQLITE_API int sqlite3_os_init(void){
+SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void){
static sqlite3_vfs winVfs = {
3, /* iVersion */
sizeof(winFile), /* szOsFile */
@@ -37479,7 +38808,7 @@ SQLITE_API int sqlite3_os_init(void){
/* Double-check that the aSyscall[] array has been constructed
** correctly. See ticket [bb3a86e890c8e96ab] */
- assert( ArraySize(aSyscall)==77 );
+ assert( ArraySize(aSyscall)==80 );
/* get memory map allocation granularity */
memset(&winSysInfo, 0, sizeof(SYSTEM_INFO));
@@ -37500,7 +38829,7 @@ SQLITE_API int sqlite3_os_init(void){
return SQLITE_OK;
}
-SQLITE_API int sqlite3_os_end(void){
+SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void){
#if SQLITE_OS_WINRT
if( sleepObj!=NULL ){
osCloseHandle(sleepObj);
@@ -37856,7 +39185,7 @@ SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int sz, int *aOp){
** bits to act as the reference */
pBitvec = sqlite3BitvecCreate( sz );
pV = sqlite3MallocZero( (sz+7)/8 + 1 );
- pTmpSpace = sqlite3_malloc(BITVEC_SZ);
+ pTmpSpace = sqlite3_malloc64(BITVEC_SZ);
if( pBitvec==0 || pV==0 || pTmpSpace==0 ) goto bitvec_end;
/* NULL pBitvec tests */
@@ -37955,102 +39284,73 @@ struct PCache {
PgHdr *pPage1; /* Reference to page 1 */
};
-/*
-** Some of the assert() macros in this code are too expensive to run
-** even during normal debugging. Use them only rarely on long-running
-** tests. Enable the expensive asserts using the
-** -DSQLITE_ENABLE_EXPENSIVE_ASSERT=1 compile-time option.
-*/
-#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
-# define expensive_assert(X) assert(X)
-#else
-# define expensive_assert(X)
-#endif
-
/********************************** Linked List Management ********************/
-#if !defined(NDEBUG) && defined(SQLITE_ENABLE_EXPENSIVE_ASSERT)
-/*
-** Check that the pCache->pSynced variable is set correctly. If it
-** is not, either fail an assert or return zero. Otherwise, return
-** non-zero. This is only used in debugging builds, as follows:
-**
-** expensive_assert( pcacheCheckSynced(pCache) );
-*/
-static int pcacheCheckSynced(PCache *pCache){
- PgHdr *p;
- for(p=pCache->pDirtyTail; p!=pCache->pSynced; p=p->pDirtyPrev){
- assert( p->nRef || (p->flags&PGHDR_NEED_SYNC) );
- }
- return (p==0 || p->nRef || (p->flags&PGHDR_NEED_SYNC)==0);
-}
-#endif /* !NDEBUG && SQLITE_ENABLE_EXPENSIVE_ASSERT */
+/* Allowed values for second argument to pcacheManageDirtyList() */
+#define PCACHE_DIRTYLIST_REMOVE 1 /* Remove pPage from dirty list */
+#define PCACHE_DIRTYLIST_ADD 2 /* Add pPage to the dirty list */
+#define PCACHE_DIRTYLIST_FRONT 3 /* Move pPage to the front of the list */
/*
-** Remove page pPage from the list of dirty pages.
+** Manage pPage's participation on the dirty list. Bits of the addRemove
+** argument determines what operation to do. The 0x01 bit means first
+** remove pPage from the dirty list. The 0x02 means add pPage back to
+** the dirty list. Doing both moves pPage to the front of the dirty list.
*/
-static void pcacheRemoveFromDirtyList(PgHdr *pPage){
+static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
PCache *p = pPage->pCache;
- assert( pPage->pDirtyNext || pPage==p->pDirtyTail );
- assert( pPage->pDirtyPrev || pPage==p->pDirty );
-
- /* Update the PCache1.pSynced variable if necessary. */
- if( p->pSynced==pPage ){
- PgHdr *pSynced = pPage->pDirtyPrev;
- while( pSynced && (pSynced->flags&PGHDR_NEED_SYNC) ){
- pSynced = pSynced->pDirtyPrev;
+ if( addRemove & PCACHE_DIRTYLIST_REMOVE ){
+ assert( pPage->pDirtyNext || pPage==p->pDirtyTail );
+ assert( pPage->pDirtyPrev || pPage==p->pDirty );
+
+ /* Update the PCache1.pSynced variable if necessary. */
+ if( p->pSynced==pPage ){
+ PgHdr *pSynced = pPage->pDirtyPrev;
+ while( pSynced && (pSynced->flags&PGHDR_NEED_SYNC) ){
+ pSynced = pSynced->pDirtyPrev;
+ }
+ p->pSynced = pSynced;
}
- p->pSynced = pSynced;
- }
-
- if( pPage->pDirtyNext ){
- pPage->pDirtyNext->pDirtyPrev = pPage->pDirtyPrev;
- }else{
- assert( pPage==p->pDirtyTail );
- p->pDirtyTail = pPage->pDirtyPrev;
- }
- if( pPage->pDirtyPrev ){
- pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext;
- }else{
- assert( pPage==p->pDirty );
- p->pDirty = pPage->pDirtyNext;
- if( p->pDirty==0 && p->bPurgeable ){
- assert( p->eCreate==1 );
- p->eCreate = 2;
+
+ if( pPage->pDirtyNext ){
+ pPage->pDirtyNext->pDirtyPrev = pPage->pDirtyPrev;
+ }else{
+ assert( pPage==p->pDirtyTail );
+ p->pDirtyTail = pPage->pDirtyPrev;
}
+ if( pPage->pDirtyPrev ){
+ pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext;
+ }else{
+ assert( pPage==p->pDirty );
+ p->pDirty = pPage->pDirtyNext;
+ if( p->pDirty==0 && p->bPurgeable ){
+ assert( p->eCreate==1 );
+ p->eCreate = 2;
+ }
+ }
+ pPage->pDirtyNext = 0;
+ pPage->pDirtyPrev = 0;
}
- pPage->pDirtyNext = 0;
- pPage->pDirtyPrev = 0;
-
- expensive_assert( pcacheCheckSynced(p) );
-}
-
-/*
-** Add page pPage to the head of the dirty list (PCache1.pDirty is set to
-** pPage).
-*/
-static void pcacheAddToDirtyList(PgHdr *pPage){
- PCache *p = pPage->pCache;
-
- assert( pPage->pDirtyNext==0 && pPage->pDirtyPrev==0 && p->pDirty!=pPage );
-
- pPage->pDirtyNext = p->pDirty;
- if( pPage->pDirtyNext ){
- assert( pPage->pDirtyNext->pDirtyPrev==0 );
- pPage->pDirtyNext->pDirtyPrev = pPage;
- }else if( p->bPurgeable ){
- assert( p->eCreate==2 );
- p->eCreate = 1;
- }
- p->pDirty = pPage;
- if( !p->pDirtyTail ){
- p->pDirtyTail = pPage;
- }
- if( !p->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) ){
- p->pSynced = pPage;
+ if( addRemove & PCACHE_DIRTYLIST_ADD ){
+ assert( pPage->pDirtyNext==0 && pPage->pDirtyPrev==0 && p->pDirty!=pPage );
+
+ pPage->pDirtyNext = p->pDirty;
+ if( pPage->pDirtyNext ){
+ assert( pPage->pDirtyNext->pDirtyPrev==0 );
+ pPage->pDirtyNext->pDirtyPrev = pPage;
+ }else{
+ p->pDirtyTail = pPage;
+ if( p->bPurgeable ){
+ assert( p->eCreate==2 );
+ p->eCreate = 1;
+ }
+ }
+ p->pDirty = pPage;
+ if( !p->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) ){
+ p->pSynced = pPage;
+ }
}
- expensive_assert( pcacheCheckSynced(p) );
}
/*
@@ -38058,12 +39358,30 @@ static void pcacheAddToDirtyList(PgHdr *pPage){
** being used for an in-memory database, this function is a no-op.
*/
static void pcacheUnpin(PgHdr *p){
- PCache *pCache = p->pCache;
- if( pCache->bPurgeable ){
+ if( p->pCache->bPurgeable ){
if( p->pgno==1 ){
- pCache->pPage1 = 0;
+ p->pCache->pPage1 = 0;
}
- sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, p->pPage, 0);
+ sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 0);
+ }
+}
+
+/*
+** Compute the number of pages of cache requested. p->szCache is the
+** cache size requested by the "PRAGMA cache_size" statement.
+**
+**
+*/
+static int numberOfCachePages(PCache *p){
+ if( p->szCache>=0 ){
+ /* IMPLEMENTATION-OF: R-42059-47211 If the argument N is positive then the
+ ** suggested cache size is set to N. */
+ return p->szCache;
+ }else{
+ /* IMPLEMENTATION-OF: R-61436-13639 If the argument N is negative, then
+ ** the number of cache pages is adjusted to use approximately abs(N*1024)
+ ** bytes of memory. */
+ return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra));
}
}
@@ -38099,7 +39417,7 @@ SQLITE_PRIVATE int sqlite3PcacheSize(void){ return sizeof(PCache); }
** The caller discovers how much space needs to be allocated by
** calling sqlite3PcacheSize().
*/
-SQLITE_PRIVATE void sqlite3PcacheOpen(
+SQLITE_PRIVATE int sqlite3PcacheOpen(
int szPage, /* Size of every page */
int szExtra, /* Extra space associated with each page */
int bPurgeable, /* True if pages are on backing store */
@@ -38108,76 +39426,76 @@ SQLITE_PRIVATE void sqlite3PcacheOpen(
PCache *p /* Preallocated space for the PCache */
){
memset(p, 0, sizeof(PCache));
- p->szPage = szPage;
+ p->szPage = 1;
p->szExtra = szExtra;
p->bPurgeable = bPurgeable;
p->eCreate = 2;
p->xStress = xStress;
p->pStress = pStress;
p->szCache = 100;
+ return sqlite3PcacheSetPageSize(p, szPage);
}
/*
** Change the page size for PCache object. The caller must ensure that there
** are no outstanding page references when this function is called.
*/
-SQLITE_PRIVATE void sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
+SQLITE_PRIVATE int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
assert( pCache->nRef==0 && pCache->pDirty==0 );
- if( pCache->pCache ){
- sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
- pCache->pCache = 0;
+ if( pCache->szPage ){
+ sqlite3_pcache *pNew;
+ pNew = sqlite3GlobalConfig.pcache2.xCreate(
+ szPage, pCache->szExtra + ROUND8(sizeof(PgHdr)),
+ pCache->bPurgeable
+ );
+ if( pNew==0 ) return SQLITE_NOMEM;
+ sqlite3GlobalConfig.pcache2.xCachesize(pNew, numberOfCachePages(pCache));
+ if( pCache->pCache ){
+ sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
+ }
+ pCache->pCache = pNew;
pCache->pPage1 = 0;
+ pCache->szPage = szPage;
}
- pCache->szPage = szPage;
-}
-
-/*
-** Compute the number of pages of cache requested.
-*/
-static int numberOfCachePages(PCache *p){
- if( p->szCache>=0 ){
- return p->szCache;
- }else{
- return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra));
- }
+ return SQLITE_OK;
}
/*
** Try to obtain a page from the cache.
+**
+** This routine returns a pointer to an sqlite3_pcache_page object if
+** such an object is already in cache, or if a new one is created.
+** This routine returns a NULL pointer if the object was not in cache
+** and could not be created.
+**
+** The createFlags should be 0 to check for existing pages and should
+** be 3 (not 1, but 3) to try to create a new page.
+**
+** If the createFlag is 0, then NULL is always returned if the page
+** is not already in the cache. If createFlag is 1, then a new page
+** is created only if that can be done without spilling dirty pages
+** and without exceeding the cache size limit.
+**
+** The caller needs to invoke sqlite3PcacheFetchFinish() to properly
+** initialize the sqlite3_pcache_page object and convert it into a
+** PgHdr object. The sqlite3PcacheFetch() and sqlite3PcacheFetchFinish()
+** routines are split this way for performance reasons. When separated
+** they can both (usually) operate without having to push values to
+** the stack on entry and pop them back off on exit, which saves a
+** lot of pushing and popping.
*/
-SQLITE_PRIVATE int sqlite3PcacheFetch(
+SQLITE_PRIVATE sqlite3_pcache_page *sqlite3PcacheFetch(
PCache *pCache, /* Obtain the page from this cache */
Pgno pgno, /* Page number to obtain */
- int createFlag, /* If true, create page if it does not exist already */
- PgHdr **ppPage /* Write the page here */
+ int createFlag /* If true, create page if it does not exist already */
){
- sqlite3_pcache_page *pPage;
- PgHdr *pPgHdr = 0;
int eCreate;
assert( pCache!=0 );
- assert( createFlag==1 || createFlag==0 );
+ assert( pCache->pCache!=0 );
+ assert( createFlag==3 || createFlag==0 );
assert( pgno>0 );
- /* If the pluggable cache (sqlite3_pcache*) has not been allocated,
- ** allocate it now.
- */
- if( !pCache->pCache ){
- sqlite3_pcache *p;
- if( !createFlag ){
- *ppPage = 0;
- return SQLITE_OK;
- }
- p = sqlite3GlobalConfig.pcache2.xCreate(
- pCache->szPage, pCache->szExtra + sizeof(PgHdr), pCache->bPurgeable
- );
- if( !p ){
- return SQLITE_NOMEM;
- }
- sqlite3GlobalConfig.pcache2.xCachesize(p, numberOfCachePages(pCache));
- pCache->pCache = p;
- }
-
/* eCreate defines what to do if the page does not exist.
** 0 Do not allocate a new page. (createFlag==0)
** 1 Allocate a new page if doing so is inexpensive.
@@ -38185,89 +39503,135 @@ SQLITE_PRIVATE int sqlite3PcacheFetch(
** 2 Allocate a new page even it doing so is difficult.
** (createFlag==1 AND !(bPurgeable AND pDirty)
*/
- eCreate = createFlag==0 ? 0 : pCache->eCreate;
- assert( (createFlag*(1+(!pCache->bPurgeable||!pCache->pDirty)))==eCreate );
- pPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
- if( !pPage && eCreate==1 ){
- PgHdr *pPg;
+ eCreate = createFlag & pCache->eCreate;
+ assert( eCreate==0 || eCreate==1 || eCreate==2 );
+ assert( createFlag==0 || pCache->eCreate==eCreate );
+ assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) );
+ return sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
+}
- /* Find a dirty page to write-out and recycle. First try to find a
- ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC
- ** cleared), but if that is not possible settle for any other
- ** unreferenced dirty page.
- */
- expensive_assert( pcacheCheckSynced(pCache) );
- for(pPg=pCache->pSynced;
- pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC));
- pPg=pPg->pDirtyPrev
- );
- pCache->pSynced = pPg;
- if( !pPg ){
- for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev);
- }
- if( pPg ){
- int rc;
+/*
+** If the sqlite3PcacheFetch() routine is unable to allocate a new
+** page because new clean pages are available for reuse and the cache
+** size limit has been reached, then this routine can be invoked to
+** try harder to allocate a page. This routine might invoke the stress
+** callback to spill dirty pages to the journal. It will then try to
+** allocate the new page and will only fail to allocate a new page on
+** an OOM error.
+**
+** This routine should be invoked only after sqlite3PcacheFetch() fails.
+*/
+SQLITE_PRIVATE int sqlite3PcacheFetchStress(
+ PCache *pCache, /* Obtain the page from this cache */
+ Pgno pgno, /* Page number to obtain */
+ sqlite3_pcache_page **ppPage /* Write result here */
+){
+ PgHdr *pPg;
+ if( pCache->eCreate==2 ) return 0;
+
+
+ /* Find a dirty page to write-out and recycle. First try to find a
+ ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC
+ ** cleared), but if that is not possible settle for any other
+ ** unreferenced dirty page.
+ */
+ for(pPg=pCache->pSynced;
+ pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC));
+ pPg=pPg->pDirtyPrev
+ );
+ pCache->pSynced = pPg;
+ if( !pPg ){
+ for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev);
+ }
+ if( pPg ){
+ int rc;
#ifdef SQLITE_LOG_CACHE_SPILL
- sqlite3_log(SQLITE_FULL,
- "spill page %d making room for %d - cache used: %d/%d",
- pPg->pgno, pgno,
- sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache),
- numberOfCachePages(pCache));
-#endif
- rc = pCache->xStress(pCache->pStress, pPg);
- if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
- return rc;
- }
+ sqlite3_log(SQLITE_FULL,
+ "spill page %d making room for %d - cache used: %d/%d",
+ pPg->pgno, pgno,
+ sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache),
+ numberOfCachePages(pCache));
+#endif
+ rc = pCache->xStress(pCache->pStress, pPg);
+ if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
+ return rc;
}
-
- pPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2);
}
+ *ppPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2);
+ return *ppPage==0 ? SQLITE_NOMEM : SQLITE_OK;
+}
- if( pPage ){
- pPgHdr = (PgHdr *)pPage->pExtra;
-
- if( !pPgHdr->pPage ){
- memset(pPgHdr, 0, sizeof(PgHdr));
- pPgHdr->pPage = pPage;
- pPgHdr->pData = pPage->pBuf;
- pPgHdr->pExtra = (void *)&pPgHdr[1];
- memset(pPgHdr->pExtra, 0, pCache->szExtra);
- pPgHdr->pCache = pCache;
- pPgHdr->pgno = pgno;
- }
- assert( pPgHdr->pCache==pCache );
- assert( pPgHdr->pgno==pgno );
- assert( pPgHdr->pData==pPage->pBuf );
- assert( pPgHdr->pExtra==(void *)&pPgHdr[1] );
-
- if( 0==pPgHdr->nRef ){
- pCache->nRef++;
- }
- pPgHdr->nRef++;
- if( pgno==1 ){
- pCache->pPage1 = pPgHdr;
- }
+/*
+** This is a helper routine for sqlite3PcacheFetchFinish()
+**
+** In the uncommon case where the page being fetched has not been
+** initialized, this routine is invoked to do the initialization.
+** This routine is broken out into a separate function since it
+** requires extra stack manipulation that can be avoided in the common
+** case.
+*/
+static SQLITE_NOINLINE PgHdr *pcacheFetchFinishWithInit(
+ PCache *pCache, /* Obtain the page from this cache */
+ Pgno pgno, /* Page number obtained */
+ sqlite3_pcache_page *pPage /* Page obtained by prior PcacheFetch() call */
+){
+ PgHdr *pPgHdr;
+ assert( pPage!=0 );
+ pPgHdr = (PgHdr*)pPage->pExtra;
+ assert( pPgHdr->pPage==0 );
+ memset(pPgHdr, 0, sizeof(PgHdr));
+ pPgHdr->pPage = pPage;
+ pPgHdr->pData = pPage->pBuf;
+ pPgHdr->pExtra = (void *)&pPgHdr[1];
+ memset(pPgHdr->pExtra, 0, pCache->szExtra);
+ pPgHdr->pCache = pCache;
+ pPgHdr->pgno = pgno;
+ return sqlite3PcacheFetchFinish(pCache,pgno,pPage);
+}
+
+/*
+** This routine converts the sqlite3_pcache_page object returned by
+** sqlite3PcacheFetch() into an initialized PgHdr object. This routine
+** must be called after sqlite3PcacheFetch() in order to get a usable
+** result.
+*/
+SQLITE_PRIVATE PgHdr *sqlite3PcacheFetchFinish(
+ PCache *pCache, /* Obtain the page from this cache */
+ Pgno pgno, /* Page number obtained */
+ sqlite3_pcache_page *pPage /* Page obtained by prior PcacheFetch() call */
+){
+ PgHdr *pPgHdr;
+
+ if( pPage==0 ) return 0;
+ pPgHdr = (PgHdr *)pPage->pExtra;
+
+ if( !pPgHdr->pPage ){
+ return pcacheFetchFinishWithInit(pCache, pgno, pPage);
+ }
+ if( 0==pPgHdr->nRef ){
+ pCache->nRef++;
}
- *ppPage = pPgHdr;
- return (pPgHdr==0 && eCreate) ? SQLITE_NOMEM : SQLITE_OK;
+ pPgHdr->nRef++;
+ if( pgno==1 ){
+ pCache->pPage1 = pPgHdr;
+ }
+ return pPgHdr;
}
/*
** Decrement the reference count on a page. If the page is clean and the
-** reference count drops to 0, then it is made elible for recycling.
+** reference count drops to 0, then it is made eligible for recycling.
*/
-SQLITE_PRIVATE void sqlite3PcacheRelease(PgHdr *p){
+SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
assert( p->nRef>0 );
p->nRef--;
if( p->nRef==0 ){
- PCache *pCache = p->pCache;
- pCache->nRef--;
+ p->pCache->nRef--;
if( (p->flags&PGHDR_DIRTY)==0 ){
pcacheUnpin(p);
- }else{
+ }else if( p->pDirtyPrev!=0 ){
/* Move the page to the head of the dirty list. */
- pcacheRemoveFromDirtyList(p);
- pcacheAddToDirtyList(p);
+ pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
}
}
}
@@ -38286,17 +39650,15 @@ SQLITE_PRIVATE void sqlite3PcacheRef(PgHdr *p){
** page pointed to by p is invalid.
*/
SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr *p){
- PCache *pCache;
assert( p->nRef==1 );
if( p->flags&PGHDR_DIRTY ){
- pcacheRemoveFromDirtyList(p);
+ pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
}
- pCache = p->pCache;
- pCache->nRef--;
+ p->pCache->nRef--;
if( p->pgno==1 ){
- pCache->pPage1 = 0;
+ p->pCache->pPage1 = 0;
}
- sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, p->pPage, 1);
+ sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 1);
}
/*
@@ -38308,7 +39670,7 @@ SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr *p){
assert( p->nRef>0 );
if( 0==(p->flags & PGHDR_DIRTY) ){
p->flags |= PGHDR_DIRTY;
- pcacheAddToDirtyList( p);
+ pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD);
}
}
@@ -38318,7 +39680,7 @@ SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr *p){
*/
SQLITE_PRIVATE void sqlite3PcacheMakeClean(PgHdr *p){
if( (p->flags & PGHDR_DIRTY) ){
- pcacheRemoveFromDirtyList(p);
+ pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC);
if( p->nRef==0 ){
pcacheUnpin(p);
@@ -38357,8 +39719,7 @@ SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno);
p->pgno = newPgno;
if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){
- pcacheRemoveFromDirtyList(p);
- pcacheAddToDirtyList(p);
+ pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
}
}
@@ -38399,9 +39760,8 @@ SQLITE_PRIVATE void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
** Close a cache.
*/
SQLITE_PRIVATE void sqlite3PcacheClose(PCache *pCache){
- if( pCache->pCache ){
- sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
- }
+ assert( pCache->pCache!=0 );
+ sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
}
/*
@@ -38510,11 +39870,8 @@ SQLITE_PRIVATE int sqlite3PcachePageRefcount(PgHdr *p){
** Return the total number of pages in the cache.
*/
SQLITE_PRIVATE int sqlite3PcachePagecount(PCache *pCache){
- int nPage = 0;
- if( pCache->pCache ){
- nPage = sqlite3GlobalConfig.pcache2.xPagecount(pCache->pCache);
- }
- return nPage;
+ assert( pCache->pCache!=0 );
+ return sqlite3GlobalConfig.pcache2.xPagecount(pCache->pCache);
}
#ifdef SQLITE_TEST
@@ -38530,22 +39887,27 @@ SQLITE_PRIVATE int sqlite3PcacheGetCachesize(PCache *pCache){
** Set the suggested cache-size value.
*/
SQLITE_PRIVATE void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){
+ assert( pCache->pCache!=0 );
pCache->szCache = mxPage;
- if( pCache->pCache ){
- sqlite3GlobalConfig.pcache2.xCachesize(pCache->pCache,
- numberOfCachePages(pCache));
- }
+ sqlite3GlobalConfig.pcache2.xCachesize(pCache->pCache,
+ numberOfCachePages(pCache));
}
/*
** Free up as much memory as possible from the page cache.
*/
SQLITE_PRIVATE void sqlite3PcacheShrink(PCache *pCache){
- if( pCache->pCache ){
- sqlite3GlobalConfig.pcache2.xShrink(pCache->pCache);
- }
+ assert( pCache->pCache!=0 );
+ sqlite3GlobalConfig.pcache2.xShrink(pCache->pCache);
}
+/*
+** Return the size of the header added by this middleware layer
+** in the page-cache hierarchy.
+*/
+SQLITE_PRIVATE int sqlite3HeaderSizePcache(void){ return ROUND8(sizeof(PgHdr)); }
+
+
#if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
/*
** For all dirty pages currently in the cache, invoke the specified
@@ -38577,7 +39939,7 @@ SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHd
** This file implements the default page cache implementation (the
** sqlite3_pcache interface). It also contains part of the implementation
** of the SQLITE_CONFIG_PAGECACHE and sqlite3_release_memory() features.
-** If the default page cache implementation is overriden, then neither of
+** If the default page cache implementation is overridden, then neither of
** these two features are available.
*/
@@ -38588,7 +39950,7 @@ typedef struct PgFreeslot PgFreeslot;
typedef struct PGroup PGroup;
/* Each page cache (or PCache) belongs to a PGroup. A PGroup is a set
-** of one or more PCaches that are able to recycle each others unpinned
+** of one or more PCaches that are able to recycle each other's unpinned
** pages when they are under memory pressure. A PGroup is an instance of
** the following object.
**
@@ -38758,7 +40120,6 @@ SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
static void *pcache1Alloc(int nByte){
void *p = 0;
assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
- sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
if( nByte<=pcache1.szSlot ){
sqlite3_mutex_enter(pcache1.mutex);
p = (PgHdr1 *)pcache1.pFree;
@@ -38767,7 +40128,8 @@ static void *pcache1Alloc(int nByte){
pcache1.nFreeSlot--;
pcache1.bUnderPressure = pcache1.nFreeSlot<pcache1.nReserve;
assert( pcache1.nFreeSlot>=0 );
- sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, 1);
+ sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
+ sqlite3StatusUp(SQLITE_STATUS_PAGECACHE_USED, 1);
}
sqlite3_mutex_leave(pcache1.mutex);
}
@@ -38780,7 +40142,8 @@ static void *pcache1Alloc(int nByte){
if( p ){
int sz = sqlite3MallocSize(p);
sqlite3_mutex_enter(pcache1.mutex);
- sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz);
+ sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
+ sqlite3StatusUp(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz);
sqlite3_mutex_leave(pcache1.mutex);
}
#endif
@@ -38798,7 +40161,7 @@ static int pcache1Free(void *p){
if( p>=pcache1.pStart && p<pcache1.pEnd ){
PgFreeslot *pSlot;
sqlite3_mutex_enter(pcache1.mutex);
- sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, -1);
+ sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_USED, 1);
pSlot = (PgFreeslot*)p;
pSlot->pNext = pcache1.pFree;
pcache1.pFree = pSlot;
@@ -38812,7 +40175,7 @@ static int pcache1Free(void *p){
nFreed = sqlite3MallocSize(p);
#ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
sqlite3_mutex_enter(pcache1.mutex);
- sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -nFreed);
+ sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_OVERFLOW, nFreed);
sqlite3_mutex_leave(pcache1.mutex);
#endif
sqlite3_free(p);
@@ -38859,7 +40222,7 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache){
pPg = 0;
}
#else
- pPg = pcache1Alloc(sizeof(PgHdr1) + pCache->szPage + pCache->szExtra);
+ pPg = pcache1Alloc(ROUND8(sizeof(PgHdr1)) + pCache->szPage + pCache->szExtra);
p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
#endif
pcache1EnterMutex(pCache->pGroup);
@@ -38946,7 +40309,7 @@ static int pcache1UnderMemoryPressure(PCache1 *pCache){
**
** The PCache mutex must be held when this function is called.
*/
-static int pcache1ResizeHash(PCache1 *p){
+static void pcache1ResizeHash(PCache1 *p){
PgHdr1 **apNew;
unsigned int nNew;
unsigned int i;
@@ -38978,8 +40341,6 @@ static int pcache1ResizeHash(PCache1 *p){
p->apHash = apNew;
p->nHash = nNew;
}
-
- return (p->apHash ? SQLITE_OK : SQLITE_NOMEM);
}
/*
@@ -39114,6 +40475,9 @@ static void pcache1Shutdown(void *NotUsed){
memset(&pcache1, 0, sizeof(pcache1));
}
+/* forward declaration */
+static void pcache1Destroy(sqlite3_pcache *p);
+
/*
** Implementation of the sqlite3_pcache.xCreate method.
**
@@ -39158,12 +40522,17 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
pCache->szPage = szPage;
pCache->szExtra = szExtra;
pCache->bPurgeable = (bPurgeable ? 1 : 0);
+ pcache1EnterMutex(pGroup);
+ pcache1ResizeHash(pCache);
if( bPurgeable ){
pCache->nMin = 10;
- pcache1EnterMutex(pGroup);
pGroup->nMinPage += pCache->nMin;
pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
- pcache1LeaveMutex(pGroup);
+ }
+ pcache1LeaveMutex(pGroup);
+ if( pCache->nHash==0 ){
+ pcache1Destroy((sqlite3_pcache*)pCache);
+ pCache = 0;
}
}
return (sqlite3_pcache *)pCache;
@@ -39219,6 +40588,95 @@ static int pcache1Pagecount(sqlite3_pcache *p){
return n;
}
+
+/*
+** Implement steps 3, 4, and 5 of the pcache1Fetch() algorithm described
+** in the header of the pcache1Fetch() procedure.
+**
+** This steps are broken out into a separate procedure because they are
+** usually not needed, and by avoiding the stack initialization required
+** for these steps, the main pcache1Fetch() procedure can run faster.
+*/
+static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
+ PCache1 *pCache,
+ unsigned int iKey,
+ int createFlag
+){
+ unsigned int nPinned;
+ PGroup *pGroup = pCache->pGroup;
+ PgHdr1 *pPage = 0;
+
+ /* Step 3: Abort if createFlag is 1 but the cache is nearly full */
+ assert( pCache->nPage >= pCache->nRecyclable );
+ nPinned = pCache->nPage - pCache->nRecyclable;
+ assert( pGroup->mxPinned == pGroup->nMaxPage + 10 - pGroup->nMinPage );
+ assert( pCache->n90pct == pCache->nMax*9/10 );
+ if( createFlag==1 && (
+ nPinned>=pGroup->mxPinned
+ || nPinned>=pCache->n90pct
+ || (pcache1UnderMemoryPressure(pCache) && pCache->nRecyclable<nPinned)
+ )){
+ return 0;
+ }
+
+ if( pCache->nPage>=pCache->nHash ) pcache1ResizeHash(pCache);
+ assert( pCache->nHash>0 && pCache->apHash );
+
+ /* Step 4. Try to recycle a page. */
+ if( pCache->bPurgeable && pGroup->pLruTail && (
+ (pCache->nPage+1>=pCache->nMax)
+ || pGroup->nCurrentPage>=pGroup->nMaxPage
+ || pcache1UnderMemoryPressure(pCache)
+ )){
+ PCache1 *pOther;
+ pPage = pGroup->pLruTail;
+ assert( pPage->isPinned==0 );
+ pcache1RemoveFromHash(pPage);
+ pcache1PinPage(pPage);
+ pOther = pPage->pCache;
+
+ /* We want to verify that szPage and szExtra are the same for pOther
+ ** and pCache. Assert that we can verify this by comparing sums. */
+ assert( (pCache->szPage & (pCache->szPage-1))==0 && pCache->szPage>=512 );
+ assert( pCache->szExtra<512 );
+ assert( (pOther->szPage & (pOther->szPage-1))==0 && pOther->szPage>=512 );
+ assert( pOther->szExtra<512 );
+
+ if( pOther->szPage+pOther->szExtra != pCache->szPage+pCache->szExtra ){
+ pcache1FreePage(pPage);
+ pPage = 0;
+ }else{
+ pGroup->nCurrentPage -= (pOther->bPurgeable - pCache->bPurgeable);
+ }
+ }
+
+ /* Step 5. If a usable page buffer has still not been found,
+ ** attempt to allocate a new one.
+ */
+ if( !pPage ){
+ if( createFlag==1 ) sqlite3BeginBenignMalloc();
+ pPage = pcache1AllocPage(pCache);
+ if( createFlag==1 ) sqlite3EndBenignMalloc();
+ }
+
+ if( pPage ){
+ unsigned int h = iKey % pCache->nHash;
+ pCache->nPage++;
+ pPage->iKey = iKey;
+ pPage->pNext = pCache->apHash[h];
+ pPage->pCache = pCache;
+ pPage->pLruPrev = 0;
+ pPage->pLruNext = 0;
+ pPage->isPinned = 1;
+ *(void **)pPage->page.pExtra = 0;
+ pCache->apHash[h] = pPage;
+ if( iKey>pCache->iMaxKey ){
+ pCache->iMaxKey = iKey;
+ }
+ }
+ return pPage;
+}
+
/*
** Implementation of the sqlite3_pcache.xFetch method.
**
@@ -39278,9 +40736,7 @@ static sqlite3_pcache_page *pcache1Fetch(
unsigned int iKey,
int createFlag
){
- unsigned int nPinned;
PCache1 *pCache = (PCache1 *)p;
- PGroup *pGroup;
PgHdr1 *pPage = 0;
assert( offsetof(PgHdr1,page)==0 );
@@ -39288,107 +40744,22 @@ static sqlite3_pcache_page *pcache1Fetch(
assert( pCache->bPurgeable || pCache->nMin==0 );
assert( pCache->bPurgeable==0 || pCache->nMin==10 );
assert( pCache->nMin==0 || pCache->bPurgeable );
- pcache1EnterMutex(pGroup = pCache->pGroup);
+ assert( pCache->nHash>0 );
+ pcache1EnterMutex(pCache->pGroup);
/* Step 1: Search the hash table for an existing entry. */
- if( pCache->nHash>0 ){
- unsigned int h = iKey % pCache->nHash;
- for(pPage=pCache->apHash[h]; pPage&&pPage->iKey!=iKey; pPage=pPage->pNext);
- }
+ pPage = pCache->apHash[iKey % pCache->nHash];
+ while( pPage && pPage->iKey!=iKey ){ pPage = pPage->pNext; }
/* Step 2: Abort if no existing page is found and createFlag is 0 */
if( pPage ){
if( !pPage->isPinned ) pcache1PinPage(pPage);
- goto fetch_out;
- }
- if( createFlag==0 ){
- goto fetch_out;
- }
-
- /* The pGroup local variable will normally be initialized by the
- ** pcache1EnterMutex() macro above. But if SQLITE_MUTEX_OMIT is defined,
- ** then pcache1EnterMutex() is a no-op, so we have to initialize the
- ** local variable here. Delaying the initialization of pGroup is an
- ** optimization: The common case is to exit the module before reaching
- ** this point.
- */
-#ifdef SQLITE_MUTEX_OMIT
- pGroup = pCache->pGroup;
-#endif
-
- /* Step 3: Abort if createFlag is 1 but the cache is nearly full */
- assert( pCache->nPage >= pCache->nRecyclable );
- nPinned = pCache->nPage - pCache->nRecyclable;
- assert( pGroup->mxPinned == pGroup->nMaxPage + 10 - pGroup->nMinPage );
- assert( pCache->n90pct == pCache->nMax*9/10 );
- if( createFlag==1 && (
- nPinned>=pGroup->mxPinned
- || nPinned>=pCache->n90pct
- || pcache1UnderMemoryPressure(pCache)
- )){
- goto fetch_out;
- }
-
- if( pCache->nPage>=pCache->nHash && pcache1ResizeHash(pCache) ){
- goto fetch_out;
- }
- assert( pCache->nHash>0 && pCache->apHash );
-
- /* Step 4. Try to recycle a page. */
- if( pCache->bPurgeable && pGroup->pLruTail && (
- (pCache->nPage+1>=pCache->nMax)
- || pGroup->nCurrentPage>=pGroup->nMaxPage
- || pcache1UnderMemoryPressure(pCache)
- )){
- PCache1 *pOther;
- pPage = pGroup->pLruTail;
- assert( pPage->isPinned==0 );
- pcache1RemoveFromHash(pPage);
- pcache1PinPage(pPage);
- pOther = pPage->pCache;
-
- /* We want to verify that szPage and szExtra are the same for pOther
- ** and pCache. Assert that we can verify this by comparing sums. */
- assert( (pCache->szPage & (pCache->szPage-1))==0 && pCache->szPage>=512 );
- assert( pCache->szExtra<512 );
- assert( (pOther->szPage & (pOther->szPage-1))==0 && pOther->szPage>=512 );
- assert( pOther->szExtra<512 );
-
- if( pOther->szPage+pOther->szExtra != pCache->szPage+pCache->szExtra ){
- pcache1FreePage(pPage);
- pPage = 0;
- }else{
- pGroup->nCurrentPage -= (pOther->bPurgeable - pCache->bPurgeable);
- }
- }
-
- /* Step 5. If a usable page buffer has still not been found,
- ** attempt to allocate a new one.
- */
- if( !pPage ){
- if( createFlag==1 ) sqlite3BeginBenignMalloc();
- pPage = pcache1AllocPage(pCache);
- if( createFlag==1 ) sqlite3EndBenignMalloc();
- }
-
- if( pPage ){
- unsigned int h = iKey % pCache->nHash;
- pCache->nPage++;
- pPage->iKey = iKey;
- pPage->pNext = pCache->apHash[h];
- pPage->pCache = pCache;
- pPage->pLruPrev = 0;
- pPage->pLruNext = 0;
- pPage->isPinned = 1;
- *(void **)pPage->page.pExtra = 0;
- pCache->apHash[h] = pPage;
- }
-
-fetch_out:
- if( pPage && iKey>pCache->iMaxKey ){
- pCache->iMaxKey = iKey;
+ }else if( createFlag ){
+ /* Steps 3, 4, and 5 implemented by this subroutine */
+ pPage = pcache1FetchStage2(pCache, iKey, createFlag);
}
- pcache1LeaveMutex(pGroup);
+ assert( pPage==0 || pCache->iMaxKey>=iKey );
+ pcache1LeaveMutex(pCache->pGroup);
return (sqlite3_pcache_page*)pPage;
}
@@ -39536,6 +40907,19 @@ SQLITE_PRIVATE void sqlite3PCacheSetDefault(void){
sqlite3_config(SQLITE_CONFIG_PCACHE2, &defaultMethods);
}
+/*
+** Return the size of the header on each page of this PCACHE implementation.
+*/
+SQLITE_PRIVATE int sqlite3HeaderSizePcache1(void){ return ROUND8(sizeof(PgHdr1)); }
+
+/*
+** Return the global mutex used by this PCACHE implementation. The
+** sqlite3_status() routine needs access to this mutex.
+*/
+SQLITE_PRIVATE sqlite3_mutex *sqlite3Pcache1Mutex(void){
+ return pcache1.mutex;
+}
+
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
/*
** This function is called to free superfluous dynamically allocated memory
@@ -39647,7 +41031,7 @@ SQLITE_PRIVATE void sqlite3PcacheStats(
** No INSERTs may occurs after a SMALLEST. An assertion will fail if
** that is attempted.
**
-** The cost of an INSERT is roughly constant. (Sometime new memory
+** The cost of an INSERT is roughly constant. (Sometimes new memory
** has to be allocated on an INSERT.) The cost of a TEST with a new
** batch number is O(NlogN) where N is the number of elements in the RowSet.
** The cost of a TEST using the same batch number is O(logN). The cost
@@ -40039,8 +41423,8 @@ SQLITE_PRIVATE int sqlite3RowSetNext(RowSet *p, i64 *pRowid){
** Check to see if element iRowid was inserted into the rowset as
** part of any insert batch prior to iBatch. Return 1 or 0.
**
-** If this is the first test of a new batch and if there exist entires
-** on pRowSet->pEntry, then sort those entires into the forest at
+** If this is the first test of a new batch and if there exist entries
+** on pRowSet->pEntry, then sort those entries into the forest at
** pRowSet->pForest so that they can be tested.
*/
SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64 iRowid){
@@ -40322,12 +41706,12 @@ SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal);
** Definition: Two databases (or the same database at two points it time)
** are said to be "logically equivalent" if they give the same answer to
** all queries. Note in particular the content of freelist leaf
-** pages can be changed arbitarily without effecting the logical equivalence
+** pages can be changed arbitrarily without affecting the logical equivalence
** of the database.
**
** (7) At any time, if any subset, including the empty set and the total set,
** of the unsynced changes to a rollback journal are removed and the
-** journal is rolled back, the resulting database file will be logical
+** journal is rolled back, the resulting database file will be logically
** equivalent to the database file at the beginning of the transaction.
**
** (8) When a transaction is rolled back, the xTruncate method of the VFS
@@ -40624,7 +42008,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
**
** The exception is when the database file is unlocked as the pager moves
** from ERROR to OPEN state. At this point there may be a hot-journal file
-** in the file-system that needs to be rolled back (as part of a OPEN->SHARED
+** in the file-system that needs to be rolled back (as part of an OPEN->SHARED
** transition, by the same pager or any other). If the call to xUnlock()
** fails at this point and the pager is left holding an EXCLUSIVE lock, this
** can confuse the call to xCheckReservedLock() call made later as part
@@ -40707,7 +42091,7 @@ struct PagerSavepoint {
#define SPILLFLAG_NOSYNC 0x04 /* Spill is ok, but do not sync */
/*
-** A open page cache is an instance of struct Pager. A description of
+** An open page cache is an instance of struct Pager. A description of
** some of the more important member variables follows:
**
** eState
@@ -40879,7 +42263,7 @@ struct Pager {
/**************************************************************************
** The following block contains those class members that change during
- ** routine opertion. Class members not in this block are either fixed
+ ** routine operation. Class members not in this block are either fixed
** when the pager is first created or else only change when there is a
** significant mode change (such as changing the page_size, locking_mode,
** or the journal_mode). From another view, these class members describe
@@ -40892,6 +42276,8 @@ struct Pager {
u8 setMaster; /* True if a m-j name has been written to jrnl */
u8 doNotSpill; /* Do not spill the cache when non-zero */
u8 subjInMemory; /* True to use in-memory sub-journals */
+ u8 bUseFetch; /* True to use xFetch() */
+ u8 hasBeenUsed; /* True if any content previously read from this pager*/
Pgno dbSize; /* Number of pages in the database */
Pgno dbOrigSize; /* dbSize before the current transaction */
Pgno dbFileSize; /* Number of pages in the database file */
@@ -40909,9 +42295,9 @@ struct Pager {
sqlite3_backup *pBackup; /* Pointer to list of ongoing backup processes */
PagerSavepoint *aSavepoint; /* Array of active savepoints */
int nSavepoint; /* Number of elements in aSavepoint[] */
+ u32 iDataVersion; /* Changes whenever database content changes */
char dbFileVers[16]; /* Changes whenever database file changes */
- u8 bUseFetch; /* True to use xFetch() */
int nMmapOut; /* Number of mmap pages currently outstanding */
sqlite3_int64 szMmap; /* Desired maximum mmap size */
PgHdr *pMmapFreelist; /* List of free mmap page headers (pDirty) */
@@ -41924,29 +43310,23 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
}
/*
-** Find a page in the hash table given its page number. Return
-** a pointer to the page or NULL if the requested page is not
-** already in memory.
-*/
-static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){
- PgHdr *p = 0; /* Return value */
-
- /* It is not possible for a call to PcacheFetch() with createFlag==0 to
- ** fail, since no attempt to allocate dynamic memory will be made.
- */
- (void)sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &p);
- return p;
-}
-
-/*
** Discard the entire contents of the in-memory page-cache.
*/
static void pager_reset(Pager *pPager){
+ pPager->iDataVersion++;
sqlite3BackupRestart(pPager->pBackup);
sqlite3PcacheClear(pPager->pPCache);
}
/*
+** Return the pPager->iDataVersion value
+*/
+SQLITE_PRIVATE u32 sqlite3PagerDataVersion(Pager *pPager){
+ assert( pPager->eState>PAGER_OPEN );
+ return pPager->iDataVersion;
+}
+
+/*
** Free all structures in the Pager.aSavepoint[] array and set both
** Pager.aSavepoint and Pager.nSavepoint to zero. Close the sub-journal
** if it is open and the pager is not in exclusive mode.
@@ -42202,6 +43582,14 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
rc = SQLITE_OK;
}else{
rc = sqlite3OsTruncate(pPager->jfd, 0);
+ if( rc==SQLITE_OK && pPager->fullSync ){
+ /* Make sure the new file size is written into the inode right away.
+ ** Otherwise the journal might resurrect following a power loss and
+ ** cause the last transaction to roll back. See
+ ** https://bugzilla.mozilla.org/show_bug.cgi?id=1072773
+ */
+ rc = sqlite3OsSync(pPager->jfd, pPager->syncFlags);
+ }
}
pPager->journalOff = 0;
}else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST
@@ -42230,7 +43618,7 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
#ifdef SQLITE_CHECK_PAGES
sqlite3PcacheIterateDirty(pPager->pPCache, pager_set_pagehash);
if( pPager->dbSize==0 && sqlite3PcacheRefCount(pPager->pPCache)>0 ){
- PgHdr *p = pager_lookup(pPager, 1);
+ PgHdr *p = sqlite3PagerLookup(pPager, 1);
if( p ){
p->pageHash = 0;
sqlite3PagerUnrefNotNull(p);
@@ -42509,7 +43897,7 @@ static int pager_playback_one_page(
if( pagerUseWal(pPager) ){
pPg = 0;
}else{
- pPg = pager_lookup(pPager, pgno);
+ pPg = sqlite3PagerLookup(pPager, pgno);
}
assert( pPg || !MEMDB );
assert( pPager->eState!=PAGER_OPEN || pPg==0 );
@@ -42689,7 +44077,7 @@ static int pager_delmaster(Pager *pPager, const char *zMaster){
rc = sqlite3OsFileSize(pMaster, &nMasterJournal);
if( rc!=SQLITE_OK ) goto delmaster_out;
nMasterPtr = pVfs->mxPathname+1;
- zMasterJournal = sqlite3Malloc((int)nMasterJournal + nMasterPtr + 1);
+ zMasterJournal = sqlite3Malloc(nMasterJournal + nMasterPtr + 1);
if( !zMasterJournal ){
rc = SQLITE_NOMEM;
goto delmaster_out;
@@ -42758,7 +44146,7 @@ delmaster_out:
** If the file on disk is currently larger than nPage pages, then use the VFS
** xTruncate() method to truncate it.
**
-** Or, it might might be the case that the file on disk is smaller than
+** Or, it might be the case that the file on disk is smaller than
** nPage pages. Some operating system implementations can get confused if
** you try to truncate a file to some size that is larger than it
** currently is, so detect this case and write a single zero byte to
@@ -42817,7 +44205,7 @@ SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *pFile){
/*
** Set the value of the Pager.sectorSize variable for the given
** pager based on the value returned by the xSectorSize method
-** of the open database file. The sector size will be used used
+** of the open database file. The sector size will be used
** to determine the size and alignment of journal header and
** master journal pointers within created journal files.
**
@@ -43152,7 +44540,7 @@ static int readDbPage(PgHdr *pPg, u32 iFrame){
**
** For an encrypted database, the situation is more complex: bytes
** 24..39 of the database are white noise. But the probability of
- ** white noising equaling 16 bytes of 0xff is vanishingly small so
+ ** white noise equaling 16 bytes of 0xff is vanishingly small so
** we should still be ok.
*/
memset(pPager->dbFileVers, 0xff, sizeof(pPager->dbFileVers));
@@ -43286,9 +44674,7 @@ static int pagerWalFrames(
){
int rc; /* Return code */
int nList; /* Number of pages in pList */
-#if defined(SQLITE_DEBUG) || defined(SQLITE_CHECK_PAGES)
PgHdr *p; /* For looping over pages */
-#endif
assert( pPager->pWal );
assert( pList );
@@ -43305,7 +44691,6 @@ static int pagerWalFrames(
** any pages with page numbers greater than nTruncate into the WAL file.
** They will never be read by any client. So remove them from the pDirty
** list here. */
- PgHdr *p;
PgHdr **ppNext = &pList;
nList = 0;
for(p=pList; (*ppNext = p)!=0; p=p->pDirty){
@@ -43325,7 +44710,6 @@ static int pagerWalFrames(
pPager->pageSize, pList, nTruncate, isCommit, pPager->walSyncFlags
);
if( rc==SQLITE_OK && pPager->pBackup ){
- PgHdr *p;
for(p=pList; p; p=p->pDirty){
sqlite3BackupUpdate(pPager->pBackup, p->pgno, (u8 *)p->pData);
}
@@ -43879,11 +45263,15 @@ SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nR
if( rc==SQLITE_OK ){
pager_reset(pPager);
- pPager->dbSize = (Pgno)((nByte+pageSize-1)/pageSize);
- pPager->pageSize = pageSize;
+ rc = sqlite3PcacheSetPageSize(pPager->pPCache, pageSize);
+ }
+ if( rc==SQLITE_OK ){
sqlite3PageFree(pPager->pTmpSpace);
pPager->pTmpSpace = pNew;
- sqlite3PcacheSetPageSize(pPager->pPCache, pageSize);
+ pPager->dbSize = (Pgno)((nByte+pageSize-1)/pageSize);
+ pPager->pageSize = pageSize;
+ }else{
+ sqlite3PageFree(pNew);
}
}
@@ -44017,7 +45405,7 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){
int rc; /* Return code */
/* Check that this is either a no-op (because the requested lock is
- ** already held, or one of the transistions that the busy-handler
+ ** already held), or one of the transitions that the busy-handler
** may be invoked during, according to the comment above
** sqlite3PagerSetBusyhandler().
*/
@@ -44136,7 +45524,7 @@ static int pagerAcquireMapPage(
PgHdr **ppPage /* OUT: Acquired page object */
){
PgHdr *p; /* Memory mapped page to return */
-
+
if( pPager->pMmapFreelist ){
*ppPage = p = pPager->pMmapFreelist;
pPager->pMmapFreelist = p->pDirty;
@@ -44645,8 +46033,8 @@ static int pagerStress(void *p, PgHdr *pPg){
** a rollback or by user request, respectively.
**
** Spilling is also prohibited when in an error state since that could
- ** lead to database corruption. In the current implementaton it
- ** is impossible for sqlite3PcacheFetch() to be called with createFlag==1
+ ** lead to database corruption. In the current implementation it
+ ** is impossible for sqlite3PcacheFetch() to be called with createFlag==3
** while in the error state, hence it is impossible for this routine to
** be called in the error state. Nevertheless, we include a NEVER()
** test for the error state as a safeguard against future changes.
@@ -44982,22 +46370,23 @@ act_like_temp_file:
testcase( rc!=SQLITE_OK );
}
- /* If an error occurred in either of the blocks above, free the
- ** Pager structure and close the file.
+ /* Initialize the PCache object. */
+ if( rc==SQLITE_OK ){
+ assert( nExtra<1000 );
+ nExtra = ROUND8(nExtra);
+ rc = sqlite3PcacheOpen(szPageDflt, nExtra, !memDb,
+ !memDb?pagerStress:0, (void *)pPager, pPager->pPCache);
+ }
+
+ /* If an error occurred above, free the Pager structure and close the file.
*/
if( rc!=SQLITE_OK ){
- assert( !pPager->pTmpSpace );
sqlite3OsClose(pPager->fd);
+ sqlite3PageFree(pPager->pTmpSpace);
sqlite3_free(pPager);
return rc;
}
- /* Initialize the PCache object. */
- assert( nExtra<1000 );
- nExtra = ROUND8(nExtra);
- sqlite3PcacheOpen(szPageDflt, nExtra, !memDb,
- !memDb?pagerStress:0, (void *)pPager, pPager->pPCache);
-
PAGERTRACE(("OPEN %d %s\n", FILEHANDLEID(pPager->fd), pPager->zFilename));
IOTRACE(("OPEN %p %s\n", pPager, pPager->zFilename))
@@ -45184,7 +46573,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){
*pExists = (first!=0);
}else if( rc==SQLITE_CANTOPEN ){
/* If we cannot open the rollback journal file in order to see if
- ** its has a zero header, that might be due to an I/O error, or
+ ** it has a zero header, that might be due to an I/O error, or
** it might be due to the race condition described above and in
** ticket #3883. Either way, assume that the journal is hot.
** This might be a false positive. But if it is, then the
@@ -45366,16 +46755,12 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
);
}
- if( !pPager->tempFile && (
- pPager->pBackup
- || sqlite3PcachePagecount(pPager->pPCache)>0
- || USEFETCH(pPager)
- )){
- /* The shared-lock has just been acquired on the database file
- ** and there are already pages in the cache (from a previous
- ** read or write transaction). Check to see if the database
- ** has been modified. If the database has changed, flush the
- ** cache.
+ if( !pPager->tempFile && pPager->hasBeenUsed ){
+ /* The shared-lock has just been acquired then check to
+ ** see if the database has been modified. If the database has changed,
+ ** flush the cache. The pPager->hasBeenUsed flag prevents this from
+ ** occurring on the very first access to a file, in order to save a
+ ** single unnecessary sqlite3OsRead() call at the start-up.
**
** Database changes is detected by looking at 15 bytes beginning
** at offset 24 into the file. The first 4 of these 16 bytes are
@@ -45540,13 +46925,13 @@ SQLITE_PRIVATE int sqlite3PagerAcquire(
if( pgno==0 ){
return SQLITE_CORRUPT_BKPT;
}
+ pPager->hasBeenUsed = 1;
/* If the pager is in the error state, return an error immediately.
** Otherwise, request the page from the PCache layer. */
if( pPager->errCode!=SQLITE_OK ){
rc = pPager->errCode;
}else{
-
if( bMmapOk && pagerUseWal(pPager) ){
rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
if( rc!=SQLITE_OK ) goto pager_acquire_err;
@@ -45561,7 +46946,7 @@ SQLITE_PRIVATE int sqlite3PagerAcquire(
if( rc==SQLITE_OK && pData ){
if( pPager->eState>PAGER_READER ){
- (void)sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &pPg);
+ pPg = sqlite3PagerLookup(pPager, pgno);
}
if( pPg==0 ){
rc = pagerAcquireMapPage(pPager, pgno, pData, &pPg);
@@ -45579,7 +46964,16 @@ SQLITE_PRIVATE int sqlite3PagerAcquire(
}
}
- rc = sqlite3PcacheFetch(pPager->pPCache, pgno, 1, ppPage);
+ {
+ sqlite3_pcache_page *pBase;
+ pBase = sqlite3PcacheFetch(pPager->pPCache, pgno, 3);
+ if( pBase==0 ){
+ rc = sqlite3PcacheFetchStress(pPager->pPCache, pgno, &pBase);
+ if( rc!=SQLITE_OK ) goto pager_acquire_err;
+ }
+ pPg = *ppPage = sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pBase);
+ if( pPg==0 ) rc = SQLITE_NOMEM;
+ }
}
if( rc!=SQLITE_OK ){
@@ -45676,13 +47070,13 @@ pager_acquire_err:
** has ever happened.
*/
SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
- PgHdr *pPg = 0;
+ sqlite3_pcache_page *pPage;
assert( pPager!=0 );
assert( pgno!=0 );
assert( pPager->pPCache!=0 );
- assert( pPager->eState>=PAGER_READER && pPager->eState!=PAGER_ERROR );
- sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &pPg);
- return pPg;
+ pPage = sqlite3PcacheFetch(pPager->pPCache, pgno, 0);
+ assert( pPage==0 || pPager->hasBeenUsed );
+ return sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pPage);
}
/*
@@ -46019,109 +47413,120 @@ static int pager_write(PgHdr *pPg){
}
/*
-** Mark a data page as writeable. This routine must be called before
-** making changes to a page. The caller must check the return value
-** of this function and be careful not to change any page data unless
-** this routine returns SQLITE_OK.
-**
-** The difference between this function and pager_write() is that this
-** function also deals with the special case where 2 or more pages
-** fit on a single disk sector. In this case all co-resident pages
-** must have been written to the journal file before returning.
+** This is a variant of sqlite3PagerWrite() that runs when the sector size
+** is larger than the page size. SQLite makes the (reasonable) assumption that
+** all bytes of a sector are written together by hardware. Hence, all bytes of
+** a sector need to be journalled in case of a power loss in the middle of
+** a write.
**
-** If an error occurs, SQLITE_NOMEM or an IO error code is returned
-** as appropriate. Otherwise, SQLITE_OK.
+** Usually, the sector size is less than or equal to the page size, in which
+** case pages can be individually written. This routine only runs in the exceptional
+** case where the page size is smaller than the sector size.
*/
-SQLITE_PRIVATE int sqlite3PagerWrite(DbPage *pDbPage){
- int rc = SQLITE_OK;
-
- PgHdr *pPg = pDbPage;
- Pager *pPager = pPg->pPager;
+static SQLITE_NOINLINE int pagerWriteLargeSector(PgHdr *pPg){
+ int rc = SQLITE_OK; /* Return code */
+ Pgno nPageCount; /* Total number of pages in database file */
+ Pgno pg1; /* First page of the sector pPg is located on. */
+ int nPage = 0; /* Number of pages starting at pg1 to journal */
+ int ii; /* Loop counter */
+ int needSync = 0; /* True if any page has PGHDR_NEED_SYNC */
+ Pager *pPager = pPg->pPager; /* The pager that owns pPg */
+ Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize);
- assert( (pPg->flags & PGHDR_MMAP)==0 );
- assert( pPager->eState>=PAGER_WRITER_LOCKED );
- assert( pPager->eState!=PAGER_ERROR );
- assert( assert_pager_state(pPager) );
+ /* Set the doNotSpill NOSYNC bit to 1. This is because we cannot allow
+ ** a journal header to be written between the pages journaled by
+ ** this function.
+ */
+ assert( !MEMDB );
+ assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)==0 );
+ pPager->doNotSpill |= SPILLFLAG_NOSYNC;
- if( pPager->sectorSize > (u32)pPager->pageSize ){
- Pgno nPageCount; /* Total number of pages in database file */
- Pgno pg1; /* First page of the sector pPg is located on. */
- int nPage = 0; /* Number of pages starting at pg1 to journal */
- int ii; /* Loop counter */
- int needSync = 0; /* True if any page has PGHDR_NEED_SYNC */
- Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize);
-
- /* Set the doNotSpill NOSYNC bit to 1. This is because we cannot allow
- ** a journal header to be written between the pages journaled by
- ** this function.
- */
- assert( !MEMDB );
- assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)==0 );
- pPager->doNotSpill |= SPILLFLAG_NOSYNC;
+ /* This trick assumes that both the page-size and sector-size are
+ ** an integer power of 2. It sets variable pg1 to the identifier
+ ** of the first page of the sector pPg is located on.
+ */
+ pg1 = ((pPg->pgno-1) & ~(nPagePerSector-1)) + 1;
- /* This trick assumes that both the page-size and sector-size are
- ** an integer power of 2. It sets variable pg1 to the identifier
- ** of the first page of the sector pPg is located on.
- */
- pg1 = ((pPg->pgno-1) & ~(nPagePerSector-1)) + 1;
+ nPageCount = pPager->dbSize;
+ if( pPg->pgno>nPageCount ){
+ nPage = (pPg->pgno - pg1)+1;
+ }else if( (pg1+nPagePerSector-1)>nPageCount ){
+ nPage = nPageCount+1-pg1;
+ }else{
+ nPage = nPagePerSector;
+ }
+ assert(nPage>0);
+ assert(pg1<=pPg->pgno);
+ assert((pg1+nPage)>pPg->pgno);
- nPageCount = pPager->dbSize;
- if( pPg->pgno>nPageCount ){
- nPage = (pPg->pgno - pg1)+1;
- }else if( (pg1+nPagePerSector-1)>nPageCount ){
- nPage = nPageCount+1-pg1;
- }else{
- nPage = nPagePerSector;
- }
- assert(nPage>0);
- assert(pg1<=pPg->pgno);
- assert((pg1+nPage)>pPg->pgno);
-
- for(ii=0; ii<nPage && rc==SQLITE_OK; ii++){
- Pgno pg = pg1+ii;
- PgHdr *pPage;
- if( pg==pPg->pgno || !sqlite3BitvecTest(pPager->pInJournal, pg) ){
- if( pg!=PAGER_MJ_PGNO(pPager) ){
- rc = sqlite3PagerGet(pPager, pg, &pPage);
- if( rc==SQLITE_OK ){
- rc = pager_write(pPage);
- if( pPage->flags&PGHDR_NEED_SYNC ){
- needSync = 1;
- }
- sqlite3PagerUnrefNotNull(pPage);
+ for(ii=0; ii<nPage && rc==SQLITE_OK; ii++){
+ Pgno pg = pg1+ii;
+ PgHdr *pPage;
+ if( pg==pPg->pgno || !sqlite3BitvecTest(pPager->pInJournal, pg) ){
+ if( pg!=PAGER_MJ_PGNO(pPager) ){
+ rc = sqlite3PagerGet(pPager, pg, &pPage);
+ if( rc==SQLITE_OK ){
+ rc = pager_write(pPage);
+ if( pPage->flags&PGHDR_NEED_SYNC ){
+ needSync = 1;
}
+ sqlite3PagerUnrefNotNull(pPage);
}
- }else if( (pPage = pager_lookup(pPager, pg))!=0 ){
- if( pPage->flags&PGHDR_NEED_SYNC ){
- needSync = 1;
- }
- sqlite3PagerUnrefNotNull(pPage);
}
+ }else if( (pPage = sqlite3PagerLookup(pPager, pg))!=0 ){
+ if( pPage->flags&PGHDR_NEED_SYNC ){
+ needSync = 1;
+ }
+ sqlite3PagerUnrefNotNull(pPage);
}
+ }
- /* If the PGHDR_NEED_SYNC flag is set for any of the nPage pages
- ** starting at pg1, then it needs to be set for all of them. Because
- ** writing to any of these nPage pages may damage the others, the
- ** journal file must contain sync()ed copies of all of them
- ** before any of them can be written out to the database file.
- */
- if( rc==SQLITE_OK && needSync ){
- assert( !MEMDB );
- for(ii=0; ii<nPage; ii++){
- PgHdr *pPage = pager_lookup(pPager, pg1+ii);
- if( pPage ){
- pPage->flags |= PGHDR_NEED_SYNC;
- sqlite3PagerUnrefNotNull(pPage);
- }
+ /* If the PGHDR_NEED_SYNC flag is set for any of the nPage pages
+ ** starting at pg1, then it needs to be set for all of them. Because
+ ** writing to any of these nPage pages may damage the others, the
+ ** journal file must contain sync()ed copies of all of them
+ ** before any of them can be written out to the database file.
+ */
+ if( rc==SQLITE_OK && needSync ){
+ assert( !MEMDB );
+ for(ii=0; ii<nPage; ii++){
+ PgHdr *pPage = sqlite3PagerLookup(pPager, pg1+ii);
+ if( pPage ){
+ pPage->flags |= PGHDR_NEED_SYNC;
+ sqlite3PagerUnrefNotNull(pPage);
}
}
+ }
+
+ assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)!=0 );
+ pPager->doNotSpill &= ~SPILLFLAG_NOSYNC;
+ return rc;
+}
- assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)!=0 );
- pPager->doNotSpill &= ~SPILLFLAG_NOSYNC;
+/*
+** Mark a data page as writeable. This routine must be called before
+** making changes to a page. The caller must check the return value
+** of this function and be careful not to change any page data unless
+** this routine returns SQLITE_OK.
+**
+** The difference between this function and pager_write() is that this
+** function also deals with the special case where 2 or more pages
+** fit on a single disk sector. In this case all co-resident pages
+** must have been written to the journal file before returning.
+**
+** If an error occurs, SQLITE_NOMEM or an IO error code is returned
+** as appropriate. Otherwise, SQLITE_OK.
+*/
+SQLITE_PRIVATE int sqlite3PagerWrite(PgHdr *pPg){
+ assert( (pPg->flags & PGHDR_MMAP)==0 );
+ assert( pPg->pPager->eState>=PAGER_WRITER_LOCKED );
+ assert( pPg->pPager->eState!=PAGER_ERROR );
+ assert( assert_pager_state(pPg->pPager) );
+ if( pPg->pPager->sectorSize > (u32)pPg->pPager->pageSize ){
+ return pagerWriteLargeSector(pPg);
}else{
- rc = pager_write(pDbPage);
+ return pager_write(pPg);
}
- return rc;
}
/*
@@ -46537,6 +47942,7 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager *pPager){
}
PAGERTRACE(("COMMIT %d\n", PAGERID(pPager)));
+ pPager->iDataVersion++;
rc = pager_end_transaction(pPager, pPager->setMaster, 1);
return pager_error(pPager, rc);
}
@@ -47017,7 +48423,7 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
** for the page moved there.
*/
pPg->flags &= ~PGHDR_NEED_SYNC;
- pPgOld = pager_lookup(pPager, pgno);
+ pPgOld = sqlite3PagerLookup(pPager, pgno);
assert( !pPgOld || pPgOld->nRef==1 );
if( pPgOld ){
pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC);
@@ -47078,6 +48484,18 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
#endif
/*
+** The page handle passed as the first argument refers to a dirty page
+** with a page number other than iNew. This function changes the page's
+** page number to iNew and sets the value of the PgHdr.flags field to
+** the value passed as the third parameter.
+*/
+SQLITE_PRIVATE void sqlite3PagerRekey(DbPage *pPg, Pgno iNew, u16 flags){
+ assert( pPg->pgno!=iNew );
+ pPg->flags = flags;
+ sqlite3PcacheMove(pPg, iNew);
+}
+
+/*
** Return a pointer to the data for the specified page.
*/
SQLITE_PRIVATE void *sqlite3PagerGetData(DbPage *pPg){
@@ -47222,6 +48640,8 @@ SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){
}
assert( state==pPager->eState );
}
+ }else if( eMode==PAGER_JOURNALMODE_OFF ){
+ sqlite3OsClose(pPager->jfd);
}
}
@@ -47293,7 +48713,8 @@ SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, int eMode, int *pnLog,
int rc = SQLITE_OK;
if( pPager->pWal ){
rc = sqlite3WalCheckpoint(pPager->pWal, eMode,
- pPager->xBusyHandler, pPager->pBusyHandlerArg,
+ (eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler),
+ pPager->pBusyHandlerArg,
pPager->ckptSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
pnLog, pnCkpt
);
@@ -47470,11 +48891,12 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager){
** is empty, return 0.
*/
SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
- assert( pPager->eState==PAGER_READER );
+ assert( pPager->eState>=PAGER_READER );
return sqlite3WalFramesize(pPager->pWal);
}
#endif
+
#endif /* SQLITE_OMIT_DISKIO */
/************** End of pager.c ***********************************************/
@@ -48002,7 +49424,7 @@ static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){
if( pWal->nWiData<=iPage ){
int nByte = sizeof(u32*)*(iPage+1);
volatile u32 **apNew;
- apNew = (volatile u32 **)sqlite3_realloc((void *)pWal->apWiData, nByte);
+ apNew = (volatile u32 **)sqlite3_realloc64((void *)pWal->apWiData, nByte);
if( !apNew ){
*ppPage = 0;
return SQLITE_NOMEM;
@@ -48054,7 +49476,7 @@ static volatile WalIndexHdr *walIndexHdr(Wal *pWal){
** The argument to this macro must be of type u32. On a little-endian
** architecture, it returns the u32 value that results from interpreting
** the 4 bytes as a big-endian value. On a big-endian architecture, it
-** returns the value that would be produced by intepreting the 4 bytes
+** returns the value that would be produced by interpreting the 4 bytes
** of the input value as a little-endian integer.
*/
#define BYTESWAP32(x) ( \
@@ -48268,9 +49690,10 @@ static void walUnlockShared(Wal *pWal, int lockIdx){
SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED);
WALTRACE(("WAL%p: release SHARED-%s\n", pWal, walLockName(lockIdx)));
}
-static int walLockExclusive(Wal *pWal, int lockIdx, int n){
+static int walLockExclusive(Wal *pWal, int lockIdx, int n, int fBlock){
int rc;
if( pWal->exclusiveMode ) return SQLITE_OK;
+ if( fBlock ) sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_WAL_BLOCK, 0);
rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE);
WALTRACE(("WAL%p: acquire EXCLUSIVE-%s cnt=%d %s\n", pWal,
@@ -48468,7 +49891,7 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
assert( idx <= HASHTABLE_NSLOT/2 + 1 );
/* If this is the first entry to be added to this hash-table, zero the
- ** entire hash table and aPgno[] array before proceding.
+ ** entire hash table and aPgno[] array before proceeding.
*/
if( idx==1 ){
int nByte = (int)((u8 *)&aHash[HASHTABLE_NSLOT] - (u8 *)&aPgno[1]);
@@ -48556,7 +49979,7 @@ static int walIndexRecover(Wal *pWal){
assert( pWal->writeLock );
iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock;
nLock = SQLITE_SHM_NLOCK - iLock;
- rc = walLockExclusive(pWal, iLock, nLock);
+ rc = walLockExclusive(pWal, iLock, nLock, 0);
if( rc ){
return rc;
}
@@ -48626,7 +50049,7 @@ static int walIndexRecover(Wal *pWal){
/* Malloc a buffer to read frames into. */
szFrame = szPage + WAL_FRAME_HDRSIZE;
- aFrame = (u8 *)sqlite3_malloc(szFrame);
+ aFrame = (u8 *)sqlite3_malloc64(szFrame);
if( !aFrame ){
rc = SQLITE_NOMEM;
goto recovery_error;
@@ -48984,7 +50407,7 @@ static void walMergesort(
** Free an iterator allocated by walIteratorInit().
*/
static void walIteratorFree(WalIterator *p){
- sqlite3ScratchFree(p);
+ sqlite3_free(p);
}
/*
@@ -49019,7 +50442,7 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){
nByte = sizeof(WalIterator)
+ (nSegment-1)*sizeof(struct WalSegment)
+ iLast*sizeof(ht_slot);
- p = (WalIterator *)sqlite3ScratchMalloc(nByte);
+ p = (WalIterator *)sqlite3_malloc64(nByte);
if( !p ){
return SQLITE_NOMEM;
}
@@ -49029,7 +50452,7 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){
/* Allocate temporary space used by the merge-sort routine. This block
** of memory will be freed before this function returns.
*/
- aTmp = (ht_slot *)sqlite3ScratchMalloc(
+ aTmp = (ht_slot *)sqlite3_malloc64(
sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast)
);
if( !aTmp ){
@@ -49066,7 +50489,7 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){
p->aSegment[i].aPgno = (u32 *)aPgno;
}
}
- sqlite3ScratchFree(aTmp);
+ sqlite3_free(aTmp);
if( rc!=SQLITE_OK ){
walIteratorFree(p);
@@ -49090,7 +50513,7 @@ static int walBusyLock(
){
int rc;
do {
- rc = walLockExclusive(pWal, lockIdx, n);
+ rc = walLockExclusive(pWal, lockIdx, n, 0);
}while( xBusy && rc==SQLITE_BUSY && xBusy(pBusyArg) );
return rc;
}
@@ -49104,6 +50527,38 @@ static int walPagesize(Wal *pWal){
}
/*
+** The following is guaranteed when this function is called:
+**
+** a) the WRITER lock is held,
+** b) the entire log file has been checkpointed, and
+** c) any existing readers are reading exclusively from the database
+** file - there are no readers that may attempt to read a frame from
+** the log file.
+**
+** This function updates the shared-memory structures so that the next
+** client to write to the database (which may be this one) does so by
+** writing frames into the start of the log file.
+**
+** The value of parameter salt1 is used as the aSalt[1] value in the
+** new wal-index header. It should be passed a pseudo-random value (i.e.
+** one obtained from sqlite3_randomness()).
+*/
+static void walRestartHdr(Wal *pWal, u32 salt1){
+ volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
+ int i; /* Loop counter */
+ u32 *aSalt = pWal->hdr.aSalt; /* Big-endian salt values */
+ pWal->nCkpt++;
+ pWal->hdr.mxFrame = 0;
+ sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0]));
+ memcpy(&pWal->hdr.aSalt[1], &salt1, 4);
+ walIndexWriteHdr(pWal);
+ pInfo->nBackfill = 0;
+ pInfo->aReadMark[1] = 0;
+ for(i=2; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
+ assert( pInfo->aReadMark[0]==0 );
+}
+
+/*
** Copy as much content as we can from the WAL back into the database file
** in response to an sqlite3_wal_checkpoint() request or the equivalent.
**
@@ -49126,7 +50581,7 @@ static int walPagesize(Wal *pWal){
** database file.
**
** This routine uses and updates the nBackfill field of the wal-index header.
-** This is the only routine tha will increase the value of nBackfill.
+** This is the only routine that will increase the value of nBackfill.
** (A WAL reset or recovery will revert nBackfill to zero, but not increase
** its value.)
**
@@ -49137,12 +50592,12 @@ static int walPagesize(Wal *pWal){
static int walCheckpoint(
Wal *pWal, /* Wal connection */
int eMode, /* One of PASSIVE, FULL or RESTART */
- int (*xBusyCall)(void*), /* Function to call when busy */
+ int (*xBusy)(void*), /* Function to call when busy */
void *pBusyArg, /* Context argument for xBusyHandler */
int sync_flags, /* Flags for OsSync() (or 0) */
u8 *zBuf /* Temporary buffer to use */
){
- int rc; /* Return code */
+ int rc = SQLITE_OK; /* Return code */
int szPage; /* Database page-size */
WalIterator *pIter = 0; /* Wal iterator context */
u32 iDbpage = 0; /* Next database page to write */
@@ -49151,123 +50606,154 @@ static int walCheckpoint(
u32 mxPage; /* Max database page to write */
int i; /* Loop counter */
volatile WalCkptInfo *pInfo; /* The checkpoint status information */
- int (*xBusy)(void*) = 0; /* Function to call when waiting for locks */
szPage = walPagesize(pWal);
testcase( szPage<=32768 );
testcase( szPage>=65536 );
pInfo = walCkptInfo(pWal);
- if( pInfo->nBackfill>=pWal->hdr.mxFrame ) return SQLITE_OK;
+ if( pInfo->nBackfill<pWal->hdr.mxFrame ){
- /* Allocate the iterator */
- rc = walIteratorInit(pWal, &pIter);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- assert( pIter );
+ /* Allocate the iterator */
+ rc = walIteratorInit(pWal, &pIter);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ assert( pIter );
- if( eMode!=SQLITE_CHECKPOINT_PASSIVE ) xBusy = xBusyCall;
+ /* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked
+ ** in the SQLITE_CHECKPOINT_PASSIVE mode. */
+ assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 );
- /* Compute in mxSafeFrame the index of the last frame of the WAL that is
- ** safe to write into the database. Frames beyond mxSafeFrame might
- ** overwrite database pages that are in use by active readers and thus
- ** cannot be backfilled from the WAL.
- */
- mxSafeFrame = pWal->hdr.mxFrame;
- mxPage = pWal->hdr.nPage;
- for(i=1; i<WAL_NREADER; i++){
- u32 y = pInfo->aReadMark[i];
- if( mxSafeFrame>y ){
- assert( y<=pWal->hdr.mxFrame );
- rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
- if( rc==SQLITE_OK ){
- pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
- walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
- }else if( rc==SQLITE_BUSY ){
- mxSafeFrame = y;
- xBusy = 0;
- }else{
- goto walcheckpoint_out;
+ /* Compute in mxSafeFrame the index of the last frame of the WAL that is
+ ** safe to write into the database. Frames beyond mxSafeFrame might
+ ** overwrite database pages that are in use by active readers and thus
+ ** cannot be backfilled from the WAL.
+ */
+ mxSafeFrame = pWal->hdr.mxFrame;
+ mxPage = pWal->hdr.nPage;
+ for(i=1; i<WAL_NREADER; i++){
+ /* Thread-sanitizer reports that the following is an unsafe read,
+ ** as some other thread may be in the process of updating the value
+ ** of the aReadMark[] slot. The assumption here is that if that is
+ ** happening, the other client may only be increasing the value,
+ ** not decreasing it. So assuming either that either the "old" or
+ ** "new" version of the value is read, and not some arbitrary value
+ ** that would never be written by a real client, things are still
+ ** safe. */
+ u32 y = pInfo->aReadMark[i];
+ if( mxSafeFrame>y ){
+ assert( y<=pWal->hdr.mxFrame );
+ rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
+ if( rc==SQLITE_OK ){
+ pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
+ walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
+ }else if( rc==SQLITE_BUSY ){
+ mxSafeFrame = y;
+ xBusy = 0;
+ }else{
+ goto walcheckpoint_out;
+ }
}
}
- }
- if( pInfo->nBackfill<mxSafeFrame
- && (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0), 1))==SQLITE_OK
- ){
- i64 nSize; /* Current size of database file */
- u32 nBackfill = pInfo->nBackfill;
-
- /* Sync the WAL to disk */
- if( sync_flags ){
- rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
- }
+ if( pInfo->nBackfill<mxSafeFrame
+ && (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0),1))==SQLITE_OK
+ ){
+ i64 nSize; /* Current size of database file */
+ u32 nBackfill = pInfo->nBackfill;
- /* If the database may grow as a result of this checkpoint, hint
- ** about the eventual size of the db file to the VFS layer.
- */
- if( rc==SQLITE_OK ){
- i64 nReq = ((i64)mxPage * szPage);
- rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
- if( rc==SQLITE_OK && nSize<nReq ){
- sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
+ /* Sync the WAL to disk */
+ if( sync_flags ){
+ rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
}
- }
+ /* If the database may grow as a result of this checkpoint, hint
+ ** about the eventual size of the db file to the VFS layer.
+ */
+ if( rc==SQLITE_OK ){
+ i64 nReq = ((i64)mxPage * szPage);
+ rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
+ if( rc==SQLITE_OK && nSize<nReq ){
+ sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
+ }
+ }
- /* Iterate through the contents of the WAL, copying data to the db file. */
- while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
- i64 iOffset;
- assert( walFramePgno(pWal, iFrame)==iDbpage );
- if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ) continue;
- iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE;
- /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
- rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset);
- if( rc!=SQLITE_OK ) break;
- iOffset = (iDbpage-1)*(i64)szPage;
- testcase( IS_BIG_INT(iOffset) );
- rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset);
- if( rc!=SQLITE_OK ) break;
- }
- /* If work was actually accomplished... */
- if( rc==SQLITE_OK ){
- if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
- i64 szDb = pWal->hdr.nPage*(i64)szPage;
- testcase( IS_BIG_INT(szDb) );
- rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
- if( rc==SQLITE_OK && sync_flags ){
- rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
+ /* Iterate through the contents of the WAL, copying data to the db file */
+ while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
+ i64 iOffset;
+ assert( walFramePgno(pWal, iFrame)==iDbpage );
+ if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ){
+ continue;
}
+ iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE;
+ /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
+ rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset);
+ if( rc!=SQLITE_OK ) break;
+ iOffset = (iDbpage-1)*(i64)szPage;
+ testcase( IS_BIG_INT(iOffset) );
+ rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset);
+ if( rc!=SQLITE_OK ) break;
}
+
+ /* If work was actually accomplished... */
if( rc==SQLITE_OK ){
- pInfo->nBackfill = mxSafeFrame;
+ if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
+ i64 szDb = pWal->hdr.nPage*(i64)szPage;
+ testcase( IS_BIG_INT(szDb) );
+ rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
+ if( rc==SQLITE_OK && sync_flags ){
+ rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
+ }
+ }
+ if( rc==SQLITE_OK ){
+ pInfo->nBackfill = mxSafeFrame;
+ }
}
- }
- /* Release the reader lock held while backfilling */
- walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
- }
+ /* Release the reader lock held while backfilling */
+ walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
+ }
- if( rc==SQLITE_BUSY ){
- /* Reset the return code so as not to report a checkpoint failure
- ** just because there are active readers. */
- rc = SQLITE_OK;
+ if( rc==SQLITE_BUSY ){
+ /* Reset the return code so as not to report a checkpoint failure
+ ** just because there are active readers. */
+ rc = SQLITE_OK;
+ }
}
- /* If this is an SQLITE_CHECKPOINT_RESTART operation, and the entire wal
- ** file has been copied into the database file, then block until all
- ** readers have finished using the wal file. This ensures that the next
- ** process to write to the database restarts the wal file.
+ /* If this is an SQLITE_CHECKPOINT_RESTART or TRUNCATE operation, and the
+ ** entire wal file has been copied into the database file, then block
+ ** until all readers have finished using the wal file. This ensures that
+ ** the next process to write to the database restarts the wal file.
*/
if( rc==SQLITE_OK && eMode!=SQLITE_CHECKPOINT_PASSIVE ){
assert( pWal->writeLock );
if( pInfo->nBackfill<pWal->hdr.mxFrame ){
rc = SQLITE_BUSY;
- }else if( eMode==SQLITE_CHECKPOINT_RESTART ){
- assert( mxSafeFrame==pWal->hdr.mxFrame );
+ }else if( eMode>=SQLITE_CHECKPOINT_RESTART ){
+ u32 salt1;
+ sqlite3_randomness(4, &salt1);
+ assert( pInfo->nBackfill==pWal->hdr.mxFrame );
rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(1), WAL_NREADER-1);
if( rc==SQLITE_OK ){
+ if( eMode==SQLITE_CHECKPOINT_TRUNCATE ){
+ /* IMPLEMENTATION-OF: R-44699-57140 This mode works the same way as
+ ** SQLITE_CHECKPOINT_RESTART with the addition that it also
+ ** truncates the log file to zero bytes just prior to a
+ ** successful return.
+ **
+ ** In theory, it might be safe to do this without updating the
+ ** wal-index header in shared memory, as all subsequent reader or
+ ** writer clients should see that the entire log file has been
+ ** checkpointed and behave accordingly. This seems unsafe though,
+ ** as it would leave the system in a state where the contents of
+ ** the wal-index header do not match the contents of the
+ ** file-system. To avoid this, update the wal-index header to
+ ** indicate that the log file contains zero valid frames. */
+ walRestartHdr(pWal, salt1);
+ rc = sqlite3OsTruncate(pWal->pWalFd, 0);
+ }
walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
}
}
@@ -49430,7 +50916,7 @@ static int walIndexTryHdr(Wal *pWal, int *pChanged){
** wal-index from the WAL before returning.
**
** Set *pChanged to 1 if the wal-index header value in pWal->hdr is
-** changed by this opertion. If pWal->hdr is unchanged, set *pChanged
+** changed by this operation. If pWal->hdr is unchanged, set *pChanged
** to 0.
**
** If the wal-index header is successfully read, return SQLITE_OK.
@@ -49468,7 +50954,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
walUnlockShared(pWal, WAL_WRITE_LOCK);
rc = SQLITE_READONLY_RECOVERY;
}
- }else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){
+ }else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1, 1)) ){
pWal->writeLock = 1;
if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
badHdr = walIndexTryHdr(pWal, pChanged);
@@ -49634,7 +51120,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
** may have been appended to the log before READ_LOCK(0) was obtained.
** When holding READ_LOCK(0), the reader ignores the entire log file,
** which implies that the database file contains a trustworthy
- ** snapshoT. Since holding READ_LOCK(0) prevents a checkpoint from
+ ** snapshot. Since holding READ_LOCK(0) prevents a checkpoint from
** happening, this is usually correct.
**
** However, if frames have been appended to the log (or if the log
@@ -49674,7 +51160,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
&& (mxReadMark<pWal->hdr.mxFrame || mxI==0)
){
for(i=1; i<WAL_NREADER; i++){
- rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
+ rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1, 0);
if( rc==SQLITE_OK ){
mxReadMark = pInfo->aReadMark[i] = pWal->hdr.mxFrame;
mxI = i;
@@ -49840,7 +51326,7 @@ SQLITE_PRIVATE int sqlite3WalFindFrame(
for(iKey=walHash(pgno); aHash[iKey]; iKey=walNextHash(iKey)){
u32 iFrame = aHash[iKey] + iZero;
if( iFrame<=iLast && aPgno[aHash[iKey]]==pgno ){
- /* assert( iFrame>iRead ); -- not true if there is corruption */
+ assert( iFrame>iRead || CORRUPT_DB );
iRead = iFrame;
}
if( (nCollide--)==0 ){
@@ -49930,7 +51416,7 @@ SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){
/* Only one writer allowed at a time. Get the write lock. Return
** SQLITE_BUSY if unable.
*/
- rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
+ rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1, 0);
if( rc ){
return rc;
}
@@ -50005,7 +51491,6 @@ SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *p
}
if( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal);
}
- assert( rc==SQLITE_OK );
return rc;
}
@@ -50054,7 +51539,6 @@ SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData){
return rc;
}
-
/*
** This function is called just before writing a set of frames to the log
** file (see sqlite3WalFrames()). It checks to see if, instead of appending
@@ -50077,7 +51561,7 @@ static int walRestartLog(Wal *pWal){
if( pInfo->nBackfill>0 ){
u32 salt1;
sqlite3_randomness(4, &salt1);
- rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
+ rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1, 0);
if( rc==SQLITE_OK ){
/* If all readers are using WAL_READ_LOCK(0) (in other words if no
** readers are currently using the WAL), then the transactions
@@ -50087,20 +51571,8 @@ static int walRestartLog(Wal *pWal){
** In theory it would be Ok to update the cache of the header only
** at this point. But updating the actual wal-index header is also
** safe and means there is no special case for sqlite3WalUndo()
- ** to handle if this transaction is rolled back.
- */
- int i; /* Loop counter */
- u32 *aSalt = pWal->hdr.aSalt; /* Big-endian salt values */
-
- pWal->nCkpt++;
- pWal->hdr.mxFrame = 0;
- sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0]));
- aSalt[1] = salt1;
- walIndexWriteHdr(pWal);
- pInfo->nBackfill = 0;
- pInfo->aReadMark[1] = 0;
- for(i=2; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
- assert( pInfo->aReadMark[0]==0 );
+ ** to handle if this transaction is rolled back. */
+ walRestartHdr(pWal, salt1);
walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
}else if( rc!=SQLITE_BUSY ){
return rc;
@@ -50302,7 +51774,7 @@ SQLITE_PRIVATE int sqlite3WalFrames(
**
** Padding and syncing only occur if this set of frames complete a
** transaction and if PRAGMA synchronous=FULL. If synchronous==NORMAL
- ** or synchonous==OFF, then no padding or syncing are needed.
+ ** or synchronous==OFF, then no padding or syncing are needed.
**
** If SQLITE_IOCAP_POWERSAFE_OVERWRITE is defined, then padding is not
** needed and only the sync is done. If padding is needed, then the
@@ -50388,7 +51860,7 @@ SQLITE_PRIVATE int sqlite3WalFrames(
*/
SQLITE_PRIVATE int sqlite3WalCheckpoint(
Wal *pWal, /* Wal connection */
- int eMode, /* PASSIVE, FULL or RESTART */
+ int eMode, /* PASSIVE, FULL, RESTART, or TRUNCATE */
int (*xBusy)(void*), /* Function to call when busy */
void *pBusyArg, /* Context argument for xBusyHandler */
int sync_flags, /* Flags to sync db file with (or 0) */
@@ -50400,29 +51872,42 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint(
int rc; /* Return code */
int isChanged = 0; /* True if a new wal-index header is loaded */
int eMode2 = eMode; /* Mode to pass to walCheckpoint() */
+ int (*xBusy2)(void*) = xBusy; /* Busy handler for eMode2 */
assert( pWal->ckptLock==0 );
assert( pWal->writeLock==0 );
+ /* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked
+ ** in the SQLITE_CHECKPOINT_PASSIVE mode. */
+ assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 );
+
if( pWal->readOnly ) return SQLITE_READONLY;
WALTRACE(("WAL%p: checkpoint begins\n", pWal));
- rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
+
+ /* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive
+ ** "checkpoint" lock on the database file. */
+ rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1, 0);
if( rc ){
- /* Usually this is SQLITE_BUSY meaning that another thread or process
- ** is already running a checkpoint, or maybe a recovery. But it might
- ** also be SQLITE_IOERR. */
+ /* EVIDENCE-OF: R-10421-19736 If any other process is running a
+ ** checkpoint operation at the same time, the lock cannot be obtained and
+ ** SQLITE_BUSY is returned.
+ ** EVIDENCE-OF: R-53820-33897 Even if there is a busy-handler configured,
+ ** it will not be invoked in this case.
+ */
+ testcase( rc==SQLITE_BUSY );
+ testcase( xBusy!=0 );
return rc;
}
pWal->ckptLock = 1;
- /* If this is a blocking-checkpoint, then obtain the write-lock as well
- ** to prevent any writers from running while the checkpoint is underway.
- ** This has to be done before the call to walIndexReadHdr() below.
+ /* IMPLEMENTATION-OF: R-59782-36818 The SQLITE_CHECKPOINT_FULL, RESTART and
+ ** TRUNCATE modes also obtain the exclusive "writer" lock on the database
+ ** file.
**
- ** If the writer lock cannot be obtained, then a passive checkpoint is
- ** run instead. Since the checkpointer is not holding the writer lock,
- ** there is no point in blocking waiting for any readers. Assuming no
- ** other error occurs, this function will return SQLITE_BUSY to the caller.
+ ** EVIDENCE-OF: R-60642-04082 If the writer lock cannot be obtained
+ ** immediately, and a busy-handler is configured, it is invoked and the
+ ** writer lock retried until either the busy-handler returns 0 or the
+ ** lock is successfully obtained.
*/
if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){
rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_WRITE_LOCK, 1);
@@ -50430,6 +51915,7 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint(
pWal->writeLock = 1;
}else if( rc==SQLITE_BUSY ){
eMode2 = SQLITE_CHECKPOINT_PASSIVE;
+ xBusy2 = 0;
rc = SQLITE_OK;
}
}
@@ -50447,7 +51933,7 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint(
if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
rc = SQLITE_CORRUPT_BKPT;
}else{
- rc = walCheckpoint(pWal, eMode2, xBusy, pBusyArg, sync_flags, zBuf);
+ rc = walCheckpoint(pWal, eMode2, xBusy2, pBusyArg, sync_flags, zBuf);
}
/* If no error occurred, set the output variables. */
@@ -50605,7 +52091,7 @@ SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal){
** May you share freely, never taking more than you give.
**
*************************************************************************
-** This file implements a external (disk-based) database using BTrees.
+** This file implements an external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
**
** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
@@ -50731,7 +52217,7 @@ SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal){
**
** The flags define the format of this btree page. The leaf flag means that
** this page has no children. The zerodata flag means that this page carries
-** only keys and no data. The intkey flag means that the key is a integer
+** only keys and no data. The intkey flag means that the key is an integer
** which is stored in the key size entry of the cell header rather than in
** the payload area.
**
@@ -50868,12 +52354,14 @@ typedef struct BtLock BtLock;
struct MemPage {
u8 isInit; /* True if previously initialized. MUST BE FIRST! */
u8 nOverflow; /* Number of overflow cell bodies in aCell[] */
- u8 intKey; /* True if intkey flag is set */
- u8 leaf; /* True if leaf flag is set */
- u8 hasData; /* True if this page stores data */
+ u8 intKey; /* True if table b-trees. False for index b-trees */
+ u8 intKeyLeaf; /* True if the leaf of an intKey table */
+ u8 noPayload; /* True if internal intKey page (thus w/o data) */
+ u8 leaf; /* True if a leaf page */
u8 hdrOffset; /* 100 for page 1. 0 otherwise */
u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */
u8 max1bytePayload; /* min(maxLocal,127) */
+ u8 bBusy; /* Prevent endless loops on corrupt database files */
u16 maxLocal; /* Copy of BtShared.maxLocal or BtShared.maxLeaf */
u16 minLocal; /* Copy of BtShared.minLocal or BtShared.minLeaf */
u16 cellOffset; /* Index in aData of first cell pointer */
@@ -50945,6 +52433,7 @@ struct Btree {
u8 locked; /* True if db currently has pBt locked */
int wantToLock; /* Number of nested calls to sqlite3BtreeEnter() */
int nBackup; /* Number of backup operations reading this btree */
+ u32 iDataVersion; /* Combines with pBt->pPager->iDataVersion */
Btree *pNext; /* List of other sharable Btrees from the same db */
Btree *pPrev; /* Back pointer of the same list */
#ifndef SQLITE_OMIT_SHARED_CACHE
@@ -51011,6 +52500,9 @@ struct BtShared {
#endif
u8 inTransaction; /* Transaction state */
u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */
+#ifdef SQLITE_HAS_CODEC
+ u8 optimalReserve; /* Desired amount of reserved space per page */
+#endif
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 */
@@ -51030,7 +52522,7 @@ struct BtShared {
BtLock *pLock; /* List of locks held on this shared-btree struct */
Btree *pWriter; /* Btree with currently open write transaction */
#endif
- u8 *pTmpSpace; /* BtShared.pageSize bytes of space for tmp use */
+ u8 *pTmpSpace; /* Temp space sufficient to hold a single cell */
};
/*
@@ -51051,12 +52543,10 @@ struct BtShared {
*/
typedef struct CellInfo CellInfo;
struct CellInfo {
- i64 nKey; /* The key for INTKEY tables, or number of bytes in key */
- u8 *pCell; /* Pointer to the start of cell content */
- u32 nData; /* Number of bytes of data */
- u32 nPayload; /* Total amount of payload */
- u16 nHeader; /* Size of the cell content header in bytes */
- u16 nLocal; /* Amount of payload held locally */
+ i64 nKey; /* The key for INTKEY tables, or nPayload otherwise */
+ u8 *pPayload; /* Pointer to the start of payload */
+ u32 nPayload; /* Bytes of payload */
+ u16 nLocal; /* Amount of payload held locally, not on overflow */
u16 iOverflow; /* Offset to overflow page number. Zero if no overflow */
u16 nSize; /* Size of the cell content on the main b-tree page */
};
@@ -51085,6 +52575,11 @@ struct CellInfo {
**
** Fields in this structure are accessed under the BtShared.mutex
** found at self->pBt->mutex.
+**
+** skipNext meaning:
+** eState==SKIPNEXT && skipNext>0: Next sqlite3BtreeNext() is no-op.
+** eState==SKIPNEXT && skipNext<0: Next sqlite3BtreePrevious() is no-op.
+** eState==FAULT: Cursor fault with skipNext as error code.
*/
struct BtCursor {
Btree *pBtree; /* The Btree to which this cursor belongs */
@@ -51097,7 +52592,8 @@ struct BtCursor {
void *pKey; /* Saved key that was cursor last known position */
Pgno pgnoRoot; /* The root page of this tree */
int nOvflAlloc; /* Allocated size of aOverflow[] array */
- int skipNext; /* Prev() is noop if negative. Next() is noop if positive */
+ int skipNext; /* Prev() is noop if negative. Next() is noop if positive.
+ ** Error code if eState==CURSOR_FAULT */
u8 curFlags; /* zero or more BTCF_* flags defined below */
u8 eState; /* One of the CURSOR_XXX constants (see below) */
u8 hints; /* As configured by CursorSetHints() */
@@ -51139,11 +52635,11 @@ struct BtCursor {
** seek the cursor to the saved position.
**
** CURSOR_FAULT:
-** A unrecoverable error (an I/O error or a malloc failure) has occurred
+** An unrecoverable error (an I/O error or a malloc failure) has occurred
** on a different connection that shares the BtShared cache with this
** cursor. The error has left the cache in an inconsistent state.
** Do nothing else with this cursor. Any attempt to use the cursor
-** should return the error code stored in BtCursor.skip
+** should return the error code stored in BtCursor.skipNext
*/
#define CURSOR_INVALID 0
#define CURSOR_VALID 1
@@ -51253,6 +52749,8 @@ struct IntegrityCk {
int mxErr; /* Stop accumulating errors when this reaches zero */
int nErr; /* Number of messages written to zErrMsg so far */
int mallocFailed; /* A memory allocation error has occurred */
+ const char *zPfx; /* Error message prefix */
+ int v1, v2; /* Values for up to two %d fields in zPfx */
StrAccum errMsg; /* Accumulate the error message text here */
};
@@ -51288,7 +52786,7 @@ static void lockBtreeMutex(Btree *p){
** Release the BtShared mutex associated with B-Tree handle p and
** clear the p->locked boolean.
*/
-static void unlockBtreeMutex(Btree *p){
+static void SQLITE_NOINLINE unlockBtreeMutex(Btree *p){
BtShared *pBt = p->pBt;
assert( p->locked==1 );
assert( sqlite3_mutex_held(pBt->mutex) );
@@ -51299,6 +52797,9 @@ static void unlockBtreeMutex(Btree *p){
p->locked = 0;
}
+/* Forward reference */
+static void SQLITE_NOINLINE btreeLockCarefully(Btree *p);
+
/*
** Enter a mutex on the given BTree object.
**
@@ -51316,8 +52817,6 @@ static void unlockBtreeMutex(Btree *p){
** subsequent Btrees that desire a lock.
*/
SQLITE_PRIVATE void sqlite3BtreeEnter(Btree *p){
- Btree *pLater;
-
/* Some basic sanity checking on the Btree. The list of Btrees
** connected by pNext and pPrev should be in sorted order by
** Btree.pBt value. All elements of the list should belong to
@@ -51342,9 +52841,20 @@ SQLITE_PRIVATE void sqlite3BtreeEnter(Btree *p){
if( !p->sharable ) return;
p->wantToLock++;
if( p->locked ) return;
+ btreeLockCarefully(p);
+}
+
+/* This is a helper function for sqlite3BtreeLock(). By moving
+** complex, but seldom used logic, out of sqlite3BtreeLock() and
+** into this routine, we avoid unnecessary stack pointer changes
+** and thus help the sqlite3BtreeLock() routine to run much faster
+** in the common case.
+*/
+static void SQLITE_NOINLINE btreeLockCarefully(Btree *p){
+ Btree *pLater;
/* In most cases, we should be able to acquire the lock we
- ** want without having to go throught the ascending lock
+ ** want without having to go through the ascending lock
** procedure that follows. Just be sure not to block.
*/
if( sqlite3_mutex_try(p->pBt->mutex)==SQLITE_OK ){
@@ -51374,10 +52884,12 @@ SQLITE_PRIVATE void sqlite3BtreeEnter(Btree *p){
}
}
+
/*
** Exit the recursive mutex on a Btree.
*/
SQLITE_PRIVATE void sqlite3BtreeLeave(Btree *p){
+ assert( sqlite3_mutex_held(p->db->mutex) );
if( p->sharable ){
assert( p->wantToLock>0 );
p->wantToLock--;
@@ -51549,7 +53061,7 @@ SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3 *db){
** May you share freely, never taking more than you give.
**
*************************************************************************
-** This file implements a external (disk-based) database using BTrees.
+** This file implements an external (disk-based) database using BTrees.
** See the header comment on "btreeInt.h" for additional information.
** Including a description of file format and an overview of operation.
*/
@@ -51625,7 +53137,7 @@ static BtShared *SQLITE_WSD sqlite3SharedCacheList = 0;
** The shared cache setting effects only future calls to
** sqlite3_open(), sqlite3_open16(), or sqlite3_open_v2().
*/
-SQLITE_API int sqlite3_enable_shared_cache(int enable){
+SQLITE_API int SQLITE_STDCALL sqlite3_enable_shared_cache(int enable){
sqlite3GlobalConfig.sharedCacheEnabled = enable;
return SQLITE_OK;
}
@@ -51714,6 +53226,12 @@ static int hasSharedCacheTableLock(
for(p=sqliteHashFirst(&pSchema->idxHash); p; p=sqliteHashNext(p)){
Index *pIdx = (Index *)sqliteHashData(p);
if( pIdx->tnum==(int)iRoot ){
+ if( iTab ){
+ /* Two or more indexes share the same root page. There must
+ ** be imposter tables. So just return true. The assert is not
+ ** useful in that case. */
+ return 1;
+ }
iTab = pIdx->pTable->tnum;
}
}
@@ -52026,7 +53544,9 @@ static void invalidateIncrblobCursors(
BtShared *pBt = pBtree->pBt;
assert( sqlite3BtreeHoldsMutex(pBtree) );
for(p=pBt->pCursor; p; p=p->pNext){
- if( (p->curFlags & BTCF_Incrblob)!=0 && (isClearTable || p->info.nKey==iRow) ){
+ if( (p->curFlags & BTCF_Incrblob)!=0
+ && (isClearTable || p->info.nKey==iRow)
+ ){
p->eState = CURSOR_INVALID;
}
}
@@ -52131,10 +53651,15 @@ static void btreeReleaseAllCursorPages(BtCursor *pCur){
static int saveCursorPosition(BtCursor *pCur){
int rc;
- assert( CURSOR_VALID==pCur->eState );
+ assert( CURSOR_VALID==pCur->eState || CURSOR_SKIPNEXT==pCur->eState );
assert( 0==pCur->pKey );
assert( cursorHoldsMutex(pCur) );
+ if( pCur->eState==CURSOR_SKIPNEXT ){
+ pCur->eState = CURSOR_VALID;
+ }else{
+ pCur->skipNext = 0;
+ }
rc = sqlite3BtreeKeySize(pCur, &pCur->nKey);
assert( rc==SQLITE_OK ); /* KeySize() cannot fail */
@@ -52145,7 +53670,7 @@ static int saveCursorPosition(BtCursor *pCur){
** data.
*/
if( 0==pCur->apPage[0]->intKey ){
- void *pKey = sqlite3Malloc( (int)pCur->nKey );
+ void *pKey = sqlite3Malloc( pCur->nKey );
if( pKey ){
rc = sqlite3BtreeKey(pCur, 0, (int)pCur->nKey, pKey);
if( rc==SQLITE_OK ){
@@ -52168,18 +53693,44 @@ static int saveCursorPosition(BtCursor *pCur){
return rc;
}
+/* Forward reference */
+static int SQLITE_NOINLINE saveCursorsOnList(BtCursor*,Pgno,BtCursor*);
+
/*
** Save the positions of all cursors (except pExcept) that are open on
-** the table with root-page iRoot. Usually, this is called just before cursor
-** pExcept is used to modify the table (BtreeDelete() or BtreeInsert()).
+** the table with root-page iRoot. "Saving the cursor position" means that
+** the location in the btree is remembered in such a way that it can be
+** moved back to the same spot after the btree has been modified. This
+** routine is called just before cursor pExcept is used to modify the
+** table, for example in BtreeDelete() or BtreeInsert().
+**
+** Implementation note: This routine merely checks to see if any cursors
+** need to be saved. It calls out to saveCursorsOnList() in the (unusual)
+** event that cursors are in need to being saved.
*/
static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){
BtCursor *p;
assert( sqlite3_mutex_held(pBt->mutex) );
assert( pExcept==0 || pExcept->pBt==pBt );
for(p=pBt->pCursor; p; p=p->pNext){
+ if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) ) break;
+ }
+ return p ? saveCursorsOnList(p, iRoot, pExcept) : SQLITE_OK;
+}
+
+/* This helper routine to saveAllCursors does the actual work of saving
+** the cursors if and when a cursor is found that actually requires saving.
+** The common case is that no cursors need to be saved, so this routine is
+** broken out from its caller to avoid unnecessary stack pointer movement.
+*/
+static int SQLITE_NOINLINE saveCursorsOnList(
+ BtCursor *p, /* The first cursor that needs saving */
+ Pgno iRoot, /* Only save cursor with this iRoot. Save all if zero */
+ BtCursor *pExcept /* Do not save this cursor */
+){
+ do{
if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) ){
- if( p->eState==CURSOR_VALID ){
+ if( p->eState==CURSOR_VALID || p->eState==CURSOR_SKIPNEXT ){
int rc = saveCursorPosition(p);
if( SQLITE_OK!=rc ){
return rc;
@@ -52189,7 +53740,8 @@ static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){
btreeReleaseAllCursorPages(p);
}
}
- }
+ p = p->pNext;
+ }while( p );
return SQLITE_OK;
}
@@ -52250,17 +53802,19 @@ static int btreeMoveto(
*/
static int btreeRestoreCursorPosition(BtCursor *pCur){
int rc;
+ int skipNext;
assert( cursorHoldsMutex(pCur) );
assert( pCur->eState>=CURSOR_REQUIRESEEK );
if( pCur->eState==CURSOR_FAULT ){
return pCur->skipNext;
}
pCur->eState = CURSOR_INVALID;
- rc = btreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &pCur->skipNext);
+ rc = btreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &skipNext);
if( rc==SQLITE_OK ){
sqlite3_free(pCur->pKey);
pCur->pKey = 0;
assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_INVALID );
+ pCur->skipNext |= skipNext;
if( pCur->skipNext && pCur->eState==CURSOR_VALID ){
pCur->eState = CURSOR_SKIPNEXT;
}
@@ -52274,37 +53828,49 @@ static int btreeRestoreCursorPosition(BtCursor *pCur){
SQLITE_OK)
/*
-** Determine whether or not a cursor has moved from the position it
-** was last placed at. Cursors can move when the row they are pointing
-** at is deleted out from under them.
+** Determine whether or not a cursor has moved from the position where
+** it was last placed, or has been invalidated for any other reason.
+** Cursors can move when the row they are pointing at is deleted out
+** from under them, for example. Cursor might also move if a btree
+** is rebalanced.
+**
+** Calling this routine with a NULL cursor pointer returns false.
+**
+** Use the separate sqlite3BtreeCursorRestore() routine to restore a cursor
+** back to where it ought to be if this routine returns true.
+*/
+SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor *pCur){
+ return pCur->eState!=CURSOR_VALID;
+}
+
+/*
+** This routine restores a cursor back to its original position after it
+** has been moved by some outside activity (such as a btree rebalance or
+** a row having been deleted out from under the cursor).
**
-** This routine returns an error code if something goes wrong. The
-** integer *pHasMoved is set as follows:
+** On success, the *pDifferentRow parameter is false if the cursor is left
+** pointing at exactly the same row. *pDifferntRow is the row the cursor
+** was pointing to has been deleted, forcing the cursor to point to some
+** nearby row.
**
-** 0: The cursor is unchanged
-** 1: The cursor is still pointing at the same row, but the pointers
-** returned by sqlite3BtreeKeyFetch() or sqlite3BtreeDataFetch()
-** might now be invalid because of a balance() or other change to the
-** b-tree.
-** 2: The cursor is no longer pointing to the row. The row might have
-** been deleted out from under the cursor.
+** This routine should only be called for a cursor that just returned
+** TRUE from sqlite3BtreeCursorHasMoved().
*/
-SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor *pCur, int *pHasMoved){
+SQLITE_PRIVATE int sqlite3BtreeCursorRestore(BtCursor *pCur, int *pDifferentRow){
int rc;
- if( pCur->eState==CURSOR_VALID ){
- *pHasMoved = 0;
- return SQLITE_OK;
- }
+ assert( pCur!=0 );
+ assert( pCur->eState!=CURSOR_VALID );
rc = restoreCursorPosition(pCur);
if( rc ){
- *pHasMoved = 2;
+ *pDifferentRow = 1;
return rc;
}
- if( pCur->eState!=CURSOR_VALID || NEVER(pCur->skipNext!=0) ){
- *pHasMoved = 2;
+ if( pCur->eState!=CURSOR_VALID ){
+ *pDifferentRow = 1;
}else{
- *pHasMoved = 1;
+ assert( pCur->skipNext==0 );
+ *pDifferentRow = 0;
}
return SQLITE_OK;
}
@@ -52469,47 +54035,44 @@ static u8 *findOverflowCell(MemPage *pPage, int iCell){
** are two versions of this function. btreeParseCell() takes a
** cell index as the second argument and btreeParseCellPtr()
** takes a pointer to the body of the cell as its second argument.
-**
-** Within this file, the parseCell() macro can be called instead of
-** btreeParseCellPtr(). Using some compilers, this will be faster.
*/
static void btreeParseCellPtr(
MemPage *pPage, /* Page containing the cell */
u8 *pCell, /* Pointer to the cell text. */
CellInfo *pInfo /* Fill in this structure */
){
- u16 n; /* Number bytes in cell content header */
+ u8 *pIter; /* For scanning through pCell */
u32 nPayload; /* Number of bytes of cell payload */
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
-
- pInfo->pCell = pCell;
assert( pPage->leaf==0 || pPage->leaf==1 );
- n = pPage->childPtrSize;
- assert( n==4-4*pPage->leaf );
- if( pPage->intKey ){
- if( pPage->hasData ){
- assert( n==0 );
- n = getVarint32(pCell, nPayload);
- }else{
- nPayload = 0;
- }
- n += getVarint(&pCell[n], (u64*)&pInfo->nKey);
- pInfo->nData = nPayload;
+ if( pPage->intKeyLeaf ){
+ assert( pPage->childPtrSize==0 );
+ pIter = pCell + getVarint32(pCell, nPayload);
+ pIter += getVarint(pIter, (u64*)&pInfo->nKey);
+ }else if( pPage->noPayload ){
+ assert( pPage->childPtrSize==4 );
+ pInfo->nSize = 4 + getVarint(&pCell[4], (u64*)&pInfo->nKey);
+ pInfo->nPayload = 0;
+ pInfo->nLocal = 0;
+ pInfo->iOverflow = 0;
+ pInfo->pPayload = 0;
+ return;
}else{
- pInfo->nData = 0;
- n += getVarint32(&pCell[n], nPayload);
+ pIter = pCell + pPage->childPtrSize;
+ pIter += getVarint32(pIter, nPayload);
pInfo->nKey = nPayload;
}
pInfo->nPayload = nPayload;
- pInfo->nHeader = n;
+ pInfo->pPayload = pIter;
testcase( nPayload==pPage->maxLocal );
testcase( nPayload==pPage->maxLocal+1 );
- if( likely(nPayload<=pPage->maxLocal) ){
+ if( nPayload<=pPage->maxLocal ){
/* This is the (easy) common case where the entire payload fits
** on the local page. No overflow is required.
*/
- if( (pInfo->nSize = (u16)(n+nPayload))<4 ) pInfo->nSize = 4;
+ pInfo->nSize = nPayload + (u16)(pIter - pCell);
+ if( pInfo->nSize<4 ) pInfo->nSize = 4;
pInfo->nLocal = (u16)nPayload;
pInfo->iOverflow = 0;
}else{
@@ -52536,18 +54099,16 @@ static void btreeParseCellPtr(
}else{
pInfo->nLocal = (u16)minLocal;
}
- pInfo->iOverflow = (u16)(pInfo->nLocal + n);
+ pInfo->iOverflow = (u16)(&pInfo->pPayload[pInfo->nLocal] - pCell);
pInfo->nSize = pInfo->iOverflow + 4;
}
}
-#define parseCell(pPage, iCell, pInfo) \
- btreeParseCellPtr((pPage), findCell((pPage), (iCell)), (pInfo))
static void btreeParseCell(
MemPage *pPage, /* Page containing the cell */
int iCell, /* The cell index. First cell is 0 */
CellInfo *pInfo /* Fill in this structure */
){
- parseCell(pPage, iCell, pInfo);
+ btreeParseCellPtr(pPage, findCell(pPage, iCell), pInfo);
}
/*
@@ -52557,8 +54118,9 @@ static void btreeParseCell(
** the space used by the cell pointer.
*/
static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
- u8 *pIter = &pCell[pPage->childPtrSize];
- u32 nSize;
+ u8 *pIter = pCell + pPage->childPtrSize; /* For looping over bytes of pCell */
+ u8 *pEnd; /* End mark for a varint */
+ u32 nSize; /* Size value to return */
#ifdef SQLITE_DEBUG
/* The value returned by this function should always be the same as
@@ -52569,26 +54131,34 @@ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
btreeParseCellPtr(pPage, pCell, &debuginfo);
#endif
+ if( pPage->noPayload ){
+ pEnd = &pIter[9];
+ while( (*pIter++)&0x80 && pIter<pEnd );
+ assert( pPage->childPtrSize==4 );
+ return (u16)(pIter - pCell);
+ }
+ nSize = *pIter;
+ if( nSize>=0x80 ){
+ pEnd = &pIter[9];
+ nSize &= 0x7f;
+ do{
+ nSize = (nSize<<7) | (*++pIter & 0x7f);
+ }while( *(pIter)>=0x80 && pIter<pEnd );
+ }
+ pIter++;
if( pPage->intKey ){
- u8 *pEnd;
- if( pPage->hasData ){
- pIter += getVarint32(pIter, nSize);
- }else{
- nSize = 0;
- }
-
/* pIter now points at the 64-bit integer key value, a variable length
** integer. The following block moves pIter to point at the first byte
** past the end of the key value. */
pEnd = &pIter[9];
while( (*pIter++)&0x80 && pIter<pEnd );
- }else{
- pIter += getVarint32(pIter, nSize);
}
-
testcase( nSize==pPage->maxLocal );
testcase( nSize==pPage->maxLocal+1 );
- if( nSize>pPage->maxLocal ){
+ if( nSize<=pPage->maxLocal ){
+ nSize += (u32)(pIter - pCell);
+ if( nSize<4 ) nSize = 4;
+ }else{
int minLocal = pPage->minLocal;
nSize = minLocal + (nSize - minLocal) % (pPage->pBt->usableSize - 4);
testcase( nSize==pPage->maxLocal );
@@ -52596,16 +54166,9 @@ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
if( nSize>pPage->maxLocal ){
nSize = minLocal;
}
- nSize += 4;
- }
- nSize += (u32)(pIter - pCell);
-
- /* The minimum size of any cell is 4 bytes. */
- if( nSize<4 ){
- nSize = 4;
+ nSize += 4 + (u16)(pIter - pCell);
}
-
- assert( nSize==debuginfo.nSize );
+ assert( nSize==debuginfo.nSize || CORRUPT_DB );
return (u16)nSize;
}
@@ -52628,7 +54191,6 @@ static void ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell, int *pRC){
if( *pRC ) return;
assert( pCell!=0 );
btreeParseCellPtr(pPage, pCell, &info);
- assert( (info.nData+(pPage->intKey?0:info.nKey))==info.nPayload );
if( info.iOverflow ){
Pgno ovfl = get4byte(&pCell[info.iOverflow]);
ptrmapPut(pPage->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, pRC);
@@ -52642,10 +54204,15 @@ static void ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell, int *pRC){
** end of the page and all free space is collected into one
** big FreeBlk that occurs in between the header and cell
** pointer array and the cell content area.
+**
+** EVIDENCE-OF: R-44582-60138 SQLite may from time to time reorganize a
+** b-tree page so that there are no freeblocks or fragment bytes, all
+** unused bytes are contained in the unallocated space region, and all
+** cells are packed tightly at the end of the page.
*/
static int defragmentPage(MemPage *pPage){
int i; /* Loop counter */
- int pc; /* Address of a i-th cell */
+ int pc; /* Address of the i-th cell */
int hdr; /* Offset to the page header */
int size; /* Size of a cell */
int usableSize; /* Number of usable bytes on a page */
@@ -52654,6 +54221,7 @@ static int defragmentPage(MemPage *pPage){
int nCell; /* Number of cells on the page */
unsigned char *data; /* The page data */
unsigned char *temp; /* Temp area for cell content */
+ unsigned char *src; /* Source of content */
int iCellFirst; /* First allowable cell index */
int iCellLast; /* Last possible cell index */
@@ -52663,15 +54231,13 @@ static int defragmentPage(MemPage *pPage){
assert( pPage->pBt->usableSize <= SQLITE_MAX_PAGE_SIZE );
assert( pPage->nOverflow==0 );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
- temp = sqlite3PagerTempSpace(pPage->pBt->pPager);
- data = pPage->aData;
+ temp = 0;
+ src = data = pPage->aData;
hdr = pPage->hdrOffset;
cellOffset = pPage->cellOffset;
nCell = pPage->nCell;
assert( nCell==get2byte(&data[hdr+3]) );
usableSize = pPage->pBt->usableSize;
- cbrk = get2byte(&data[hdr+5]);
- memcpy(&temp[cbrk], &data[cbrk], usableSize - cbrk);
cbrk = usableSize;
iCellFirst = cellOffset + 2*nCell;
iCellLast = usableSize - 4;
@@ -52690,7 +54256,7 @@ static int defragmentPage(MemPage *pPage){
}
#endif
assert( pc>=iCellFirst && pc<=iCellLast );
- size = cellSizePtr(pPage, &temp[pc]);
+ size = cellSizePtr(pPage, &src[pc]);
cbrk -= size;
#if defined(SQLITE_ENABLE_OVERSIZE_CELL_CHECK)
if( cbrk<iCellFirst ){
@@ -52704,8 +54270,16 @@ static int defragmentPage(MemPage *pPage){
assert( cbrk+size<=usableSize && cbrk>=iCellFirst );
testcase( cbrk+size==usableSize );
testcase( pc+size==usableSize );
- memcpy(&data[cbrk], &temp[pc], size);
put2byte(pAddr, cbrk);
+ if( temp==0 ){
+ int x;
+ if( cbrk==pc ) continue;
+ temp = sqlite3PagerTempSpace(pPage->pBt->pPager);
+ x = get2byte(&data[hdr+5]);
+ memcpy(&temp[x], &data[x], (cbrk+size) - x);
+ src = temp;
+ }
+ memcpy(&data[cbrk], &src[pc], size);
}
assert( cbrk>=iCellFirst );
put2byte(&data[hdr+5], cbrk);
@@ -52721,6 +54295,69 @@ static int defragmentPage(MemPage *pPage){
}
/*
+** Search the free-list on page pPg for space to store a cell nByte bytes in
+** size. If one can be found, return a pointer to the space and remove it
+** from the free-list.
+**
+** If no suitable space can be found on the free-list, return NULL.
+**
+** This function may detect corruption within pPg. If corruption is
+** detected then *pRc is set to SQLITE_CORRUPT and NULL is returned.
+**
+** If a slot of at least nByte bytes is found but cannot be used because
+** there are already at least 60 fragmented bytes on the page, return NULL.
+** In this case, if pbDefrag parameter is not NULL, set *pbDefrag to true.
+*/
+static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc, int *pbDefrag){
+ const int hdr = pPg->hdrOffset;
+ u8 * const aData = pPg->aData;
+ int iAddr;
+ int pc;
+ int usableSize = pPg->pBt->usableSize;
+
+ for(iAddr=hdr+1; (pc = get2byte(&aData[iAddr]))>0; iAddr=pc){
+ int size; /* Size of the free slot */
+ /* EVIDENCE-OF: R-06866-39125 Freeblocks are always connected in order of
+ ** increasing offset. */
+ if( pc>usableSize-4 || pc<iAddr+4 ){
+ *pRc = SQLITE_CORRUPT_BKPT;
+ return 0;
+ }
+ /* EVIDENCE-OF: R-22710-53328 The third and fourth bytes of each
+ ** freeblock form a big-endian integer which is the size of the freeblock
+ ** in bytes, including the 4-byte header. */
+ size = get2byte(&aData[pc+2]);
+ if( size>=nByte ){
+ int x = size - nByte;
+ testcase( x==4 );
+ testcase( x==3 );
+ if( x<4 ){
+ /* EVIDENCE-OF: R-11498-58022 In a well-formed b-tree page, the total
+ ** number of bytes in fragments may not exceed 60. */
+ if( aData[hdr+7]>=60 ){
+ if( pbDefrag ) *pbDefrag = 1;
+ return 0;
+ }
+ /* Remove the slot from the free-list. Update the number of
+ ** fragmented bytes within the page. */
+ memcpy(&aData[iAddr], &aData[pc], 2);
+ aData[hdr+7] += (u8)x;
+ }else if( size+pc > usableSize ){
+ *pRc = SQLITE_CORRUPT_BKPT;
+ return 0;
+ }else{
+ /* The slot remains on the free-list. Reduce its size to account
+ ** for the portion used by the new allocation. */
+ put2byte(&aData[pc+2], x);
+ }
+ return &aData[pc + x];
+ }
+ }
+
+ return 0;
+}
+
+/*
** Allocate nByte bytes of space from within the B-Tree page passed
** as the first argument. Write into *pIdx the index into pPage->aData[]
** of the first byte of allocated space. Return either SQLITE_OK or
@@ -52736,11 +54373,9 @@ static int defragmentPage(MemPage *pPage){
static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
const int hdr = pPage->hdrOffset; /* Local cache of pPage->hdrOffset */
u8 * const data = pPage->aData; /* Local cache of pPage->aData */
- int nFrag; /* Number of fragmented bytes on pPage */
int top; /* First byte of cell content area */
+ int rc = SQLITE_OK; /* Integer return code */
int gap; /* First byte of gap between cell pointers and cell content */
- int rc; /* Integer return code */
- int usableSize; /* Usable size of the page */
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
assert( pPage->pBt );
@@ -52748,62 +54383,45 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
assert( nByte>=0 ); /* Minimum cell size is 4 */
assert( pPage->nFree>=nByte );
assert( pPage->nOverflow==0 );
- usableSize = pPage->pBt->usableSize;
- assert( nByte < usableSize-8 );
+ assert( nByte < (int)(pPage->pBt->usableSize-8) );
- nFrag = data[hdr+7];
assert( pPage->cellOffset == hdr + 12 - 4*pPage->leaf );
gap = pPage->cellOffset + 2*pPage->nCell;
+ assert( gap<=65536 );
+ /* EVIDENCE-OF: R-29356-02391 If the database uses a 65536-byte page size
+ ** and the reserved space is zero (the usual value for reserved space)
+ ** then the cell content offset of an empty page wants to be 65536.
+ ** However, that integer is too large to be stored in a 2-byte unsigned
+ ** integer, so a value of 0 is used in its place. */
top = get2byteNotZero(&data[hdr+5]);
if( gap>top ) return SQLITE_CORRUPT_BKPT;
+
+ /* If there is enough space between gap and top for one more cell pointer
+ ** array entry offset, and if the freelist is not empty, then search the
+ ** freelist looking for a free slot big enough to satisfy the request.
+ */
testcase( gap+2==top );
testcase( gap+1==top );
testcase( gap==top );
-
- if( nFrag>=60 ){
- /* Always defragment highly fragmented pages */
- rc = defragmentPage(pPage);
+ if( gap+2<=top && (data[hdr+1] || data[hdr+2]) ){
+ int bDefrag = 0;
+ u8 *pSpace = pageFindSlot(pPage, nByte, &rc, &bDefrag);
if( rc ) return rc;
- top = get2byteNotZero(&data[hdr+5]);
- }else if( gap+2<=top ){
- /* Search the freelist looking for a free slot big enough to satisfy
- ** the request. The allocation is made from the first free slot in
- ** the list that is large enough to accommodate it.
- */
- int pc, addr;
- for(addr=hdr+1; (pc = get2byte(&data[addr]))>0; addr=pc){
- int size; /* Size of the free slot */
- if( pc>usableSize-4 || pc<addr+4 ){
- return SQLITE_CORRUPT_BKPT;
- }
- size = get2byte(&data[pc+2]);
- if( size>=nByte ){
- int x = size - nByte;
- testcase( x==4 );
- testcase( x==3 );
- if( x<4 ){
- /* Remove the slot from the free-list. Update the number of
- ** fragmented bytes within the page. */
- memcpy(&data[addr], &data[pc], 2);
- data[hdr+7] = (u8)(nFrag + x);
- }else if( size+pc > usableSize ){
- return SQLITE_CORRUPT_BKPT;
- }else{
- /* The slot remains on the free-list. Reduce its size to account
- ** for the portion used by the new allocation. */
- put2byte(&data[pc+2], x);
- }
- *pIdx = pc + x;
- return SQLITE_OK;
- }
+ if( bDefrag ) goto defragment_page;
+ if( pSpace ){
+ assert( pSpace>=data && (pSpace - data)<65536 );
+ *pIdx = (int)(pSpace - data);
+ return SQLITE_OK;
}
}
- /* Check to make sure there is enough space in the gap to satisfy
- ** the allocation. If not, defragment.
+ /* The request could not be fulfilled using a freelist slot. Check
+ ** to see if defragmentation is necessary.
*/
testcase( gap+2+nByte==top );
if( gap+2+nByte>top ){
+ defragment_page:
+ assert( pPage->nCell>0 || CORRUPT_DB );
rc = defragmentPage(pPage);
if( rc ) return rc;
top = get2byteNotZero(&data[hdr+5]);
@@ -52826,90 +54444,100 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
/*
** Return a section of the pPage->aData to the freelist.
-** The first byte of the new free block is pPage->aDisk[start]
-** and the size of the block is "size" bytes.
-**
-** Most of the effort here is involved in coalesing adjacent
-** free blocks into a single big free block.
-*/
-static int freeSpace(MemPage *pPage, int start, int size){
- int addr, pbegin, hdr;
- int iLast; /* Largest possible freeblock offset */
- unsigned char *data = pPage->aData;
+** The first byte of the new free block is pPage->aData[iStart]
+** and the size of the block is iSize bytes.
+**
+** Adjacent freeblocks are coalesced.
+**
+** Note that even though the freeblock list was checked by btreeInitPage(),
+** that routine will not detect overlap between cells or freeblocks. Nor
+** does it detect cells or freeblocks that encrouch into the reserved bytes
+** at the end of the page. So do additional corruption checks inside this
+** routine and return SQLITE_CORRUPT if any problems are found.
+*/
+static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
+ u16 iPtr; /* Address of ptr to next freeblock */
+ u16 iFreeBlk; /* Address of the next freeblock */
+ u8 hdr; /* Page header size. 0 or 100 */
+ u8 nFrag = 0; /* Reduction in fragmentation */
+ u16 iOrigSize = iSize; /* Original value of iSize */
+ u32 iLast = pPage->pBt->usableSize-4; /* Largest possible freeblock offset */
+ u32 iEnd = iStart + iSize; /* First byte past the iStart buffer */
+ unsigned char *data = pPage->aData; /* Page content */
assert( pPage->pBt!=0 );
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
- assert( start>=pPage->hdrOffset+6+pPage->childPtrSize );
- assert( (start + size) <= (int)pPage->pBt->usableSize );
+ assert( iStart>=pPage->hdrOffset+6+pPage->childPtrSize );
+ assert( CORRUPT_DB || iEnd <= pPage->pBt->usableSize );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
- assert( size>=0 ); /* Minimum cell size is 4 */
+ assert( iSize>=4 ); /* Minimum cell size is 4 */
+ assert( iStart<=iLast );
+ /* Overwrite deleted information with zeros when the secure_delete
+ ** option is enabled */
if( pPage->pBt->btsFlags & BTS_SECURE_DELETE ){
- /* Overwrite deleted information with zeros when the secure_delete
- ** option is enabled */
- memset(&data[start], 0, size);
+ memset(&data[iStart], 0, iSize);
}
- /* Add the space back into the linked list of freeblocks. Note that
- ** even though the freeblock list was checked by btreeInitPage(),
- ** btreeInitPage() did not detect overlapping cells or
- ** freeblocks that overlapped cells. Nor does it detect when the
- ** cell content area exceeds the value in the page header. If these
- ** situations arise, then subsequent insert operations might corrupt
- ** the freelist. So we do need to check for corruption while scanning
- ** the freelist.
+ /* The list of freeblocks must be in ascending order. Find the
+ ** spot on the list where iStart should be inserted.
*/
hdr = pPage->hdrOffset;
- addr = hdr + 1;
- iLast = pPage->pBt->usableSize - 4;
- assert( start<=iLast );
- while( (pbegin = get2byte(&data[addr]))<start && pbegin>0 ){
- if( pbegin<addr+4 ){
- return SQLITE_CORRUPT_BKPT;
+ iPtr = hdr + 1;
+ if( data[iPtr+1]==0 && data[iPtr]==0 ){
+ iFreeBlk = 0; /* Shortcut for the case when the freelist is empty */
+ }else{
+ while( (iFreeBlk = get2byte(&data[iPtr]))>0 && iFreeBlk<iStart ){
+ if( iFreeBlk<iPtr+4 ) return SQLITE_CORRUPT_BKPT;
+ iPtr = iFreeBlk;
}
- addr = pbegin;
- }
- if( pbegin>iLast ){
- return SQLITE_CORRUPT_BKPT;
- }
- assert( pbegin>addr || pbegin==0 );
- put2byte(&data[addr], start);
- put2byte(&data[start], pbegin);
- put2byte(&data[start+2], size);
- pPage->nFree = pPage->nFree + (u16)size;
-
- /* Coalesce adjacent free blocks */
- addr = hdr + 1;
- while( (pbegin = get2byte(&data[addr]))>0 ){
- int pnext, psize, x;
- assert( pbegin>addr );
- assert( pbegin <= (int)pPage->pBt->usableSize-4 );
- pnext = get2byte(&data[pbegin]);
- psize = get2byte(&data[pbegin+2]);
- if( pbegin + psize + 3 >= pnext && pnext>0 ){
- int frag = pnext - (pbegin+psize);
- if( (frag<0) || (frag>(int)data[hdr+7]) ){
- return SQLITE_CORRUPT_BKPT;
- }
- data[hdr+7] -= (u8)frag;
- x = get2byte(&data[pnext]);
- put2byte(&data[pbegin], x);
- x = pnext + get2byte(&data[pnext+2]) - pbegin;
- put2byte(&data[pbegin+2], x);
- }else{
- addr = pbegin;
+ if( iFreeBlk>iLast ) return SQLITE_CORRUPT_BKPT;
+ assert( iFreeBlk>iPtr || iFreeBlk==0 );
+
+ /* At this point:
+ ** iFreeBlk: First freeblock after iStart, or zero if none
+ ** iPtr: The address of a pointer iFreeBlk
+ **
+ ** Check to see if iFreeBlk should be coalesced onto the end of iStart.
+ */
+ if( iFreeBlk && iEnd+3>=iFreeBlk ){
+ nFrag = iFreeBlk - iEnd;
+ if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_BKPT;
+ iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]);
+ iSize = iEnd - iStart;
+ iFreeBlk = get2byte(&data[iFreeBlk]);
}
- }
-
- /* If the cell content area begins with a freeblock, remove it. */
- if( data[hdr+1]==data[hdr+5] && data[hdr+2]==data[hdr+6] ){
- int top;
- pbegin = get2byte(&data[hdr+1]);
- memcpy(&data[hdr+1], &data[pbegin], 2);
- top = get2byte(&data[hdr+5]) + get2byte(&data[pbegin+2]);
- put2byte(&data[hdr+5], top);
- }
- assert( sqlite3PagerIswriteable(pPage->pDbPage) );
+
+ /* If iPtr is another freeblock (that is, if iPtr is not the freelist
+ ** pointer in the page header) then check to see if iStart should be
+ ** coalesced onto the end of iPtr.
+ */
+ if( iPtr>hdr+1 ){
+ int iPtrEnd = iPtr + get2byte(&data[iPtr+2]);
+ if( iPtrEnd+3>=iStart ){
+ if( iPtrEnd>iStart ) return SQLITE_CORRUPT_BKPT;
+ nFrag += iStart - iPtrEnd;
+ iSize = iEnd - iPtr;
+ iStart = iPtr;
+ }
+ }
+ if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_BKPT;
+ data[hdr+7] -= nFrag;
+ }
+ if( iStart==get2byte(&data[hdr+5]) ){
+ /* The new freeblock is at the beginning of the cell content area,
+ ** so just extend the cell content area rather than create another
+ ** freelist entry */
+ if( iPtr!=hdr+1 ) return SQLITE_CORRUPT_BKPT;
+ put2byte(&data[hdr+1], iFreeBlk);
+ put2byte(&data[hdr+5], iEnd);
+ }else{
+ /* Insert the new freeblock into the freelist */
+ put2byte(&data[iPtr], iStart);
+ put2byte(&data[iStart], iFreeBlk);
+ put2byte(&data[iStart+2], iSize);
+ }
+ pPage->nFree += iOrigSize;
return SQLITE_OK;
}
@@ -52935,16 +54563,32 @@ static int decodeFlags(MemPage *pPage, int flagByte){
pPage->childPtrSize = 4-4*pPage->leaf;
pBt = pPage->pBt;
if( flagByte==(PTF_LEAFDATA | PTF_INTKEY) ){
+ /* EVIDENCE-OF: R-03640-13415 A value of 5 means the page is an interior
+ ** table b-tree page. */
+ assert( (PTF_LEAFDATA|PTF_INTKEY)==5 );
+ /* EVIDENCE-OF: R-20501-61796 A value of 13 means the page is a leaf
+ ** table b-tree page. */
+ assert( (PTF_LEAFDATA|PTF_INTKEY|PTF_LEAF)==13 );
pPage->intKey = 1;
- pPage->hasData = pPage->leaf;
+ pPage->intKeyLeaf = pPage->leaf;
+ pPage->noPayload = !pPage->leaf;
pPage->maxLocal = pBt->maxLeaf;
pPage->minLocal = pBt->minLeaf;
}else if( flagByte==PTF_ZERODATA ){
+ /* EVIDENCE-OF: R-27225-53936 A value of 2 means the page is an interior
+ ** index b-tree page. */
+ assert( (PTF_ZERODATA)==2 );
+ /* EVIDENCE-OF: R-16571-11615 A value of 10 means the page is a leaf
+ ** index b-tree page. */
+ assert( (PTF_ZERODATA|PTF_LEAF)==10 );
pPage->intKey = 0;
- pPage->hasData = 0;
+ pPage->intKeyLeaf = 0;
+ pPage->noPayload = 0;
pPage->maxLocal = pBt->maxLocal;
pPage->minLocal = pBt->minLocal;
}else{
+ /* EVIDENCE-OF: R-47608-56469 Any other value for the b-tree page type is
+ ** an error. */
return SQLITE_CORRUPT_BKPT;
}
pPage->max1bytePayload = pBt->max1bytePayload;
@@ -52984,21 +54628,33 @@ static int btreeInitPage(MemPage *pPage){
hdr = pPage->hdrOffset;
data = pPage->aData;
+ /* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating
+ ** the b-tree page type. */
if( decodeFlags(pPage, data[hdr]) ) return SQLITE_CORRUPT_BKPT;
assert( pBt->pageSize>=512 && pBt->pageSize<=65536 );
pPage->maskPage = (u16)(pBt->pageSize - 1);
pPage->nOverflow = 0;
usableSize = pBt->usableSize;
- pPage->cellOffset = cellOffset = hdr + 12 - 4*pPage->leaf;
+ pPage->cellOffset = cellOffset = hdr + 8 + pPage->childPtrSize;
pPage->aDataEnd = &data[usableSize];
pPage->aCellIdx = &data[cellOffset];
+ /* EVIDENCE-OF: R-58015-48175 The two-byte integer at offset 5 designates
+ ** the start of the cell content area. A zero value for this integer is
+ ** interpreted as 65536. */
top = get2byteNotZero(&data[hdr+5]);
+ /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the
+ ** number of cells on the page. */
pPage->nCell = get2byte(&data[hdr+3]);
if( pPage->nCell>MX_CELL(pBt) ){
/* To many cells for a single page. The page must be corrupt */
return SQLITE_CORRUPT_BKPT;
}
testcase( pPage->nCell==MX_CELL(pBt) );
+ /* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only
+ ** possible for a root page of a table that contains no rows) then the
+ ** offset to the cell content area will equal the page size minus the
+ ** bytes of reserved space. */
+ assert( pPage->nCell>0 || top==usableSize || CORRUPT_DB );
/* A malformed database page might cause us to read past the end
** of page when parsing a cell.
@@ -53032,13 +54688,20 @@ static int btreeInitPage(MemPage *pPage){
}
#endif
- /* Compute the total free space on the page */
+ /* Compute the total free space on the page
+ ** EVIDENCE-OF: R-23588-34450 The two-byte integer at offset 1 gives the
+ ** start of the first freeblock on the page, or is zero if there are no
+ ** freeblocks. */
pc = get2byte(&data[hdr+1]);
- nFree = data[hdr+7] + top;
+ nFree = data[hdr+7] + top; /* Init nFree to non-freeblock free space */
while( pc>0 ){
u16 next, size;
if( pc<iCellFirst || pc>iCellLast ){
- /* Start of free block is off the page */
+ /* EVIDENCE-OF: R-55530-52930 In a well-formed b-tree page, there will
+ ** always be at least one cell before the first freeblock.
+ **
+ ** Or, the freeblock is off the end of the page
+ */
return SQLITE_CORRUPT_BKPT;
}
next = get2byte(&data[pc]);
@@ -53347,16 +55010,18 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
*/
if( isTempDb==0 && (isMemdb==0 || (vfsFlags&SQLITE_OPEN_URI)!=0) ){
if( vfsFlags & SQLITE_OPEN_SHAREDCACHE ){
+ int nFilename = sqlite3Strlen30(zFilename)+1;
int nFullPathname = pVfs->mxPathname+1;
- char *zFullPathname = sqlite3Malloc(nFullPathname);
+ char *zFullPathname = sqlite3Malloc(MAX(nFullPathname,nFilename));
MUTEX_LOGIC( sqlite3_mutex *mutexShared; )
+
p->sharable = 1;
if( !zFullPathname ){
sqlite3_free(p);
return SQLITE_NOMEM;
}
if( isMemdb ){
- memcpy(zFullPathname, zFilename, sqlite3Strlen30(zFilename)+1);
+ memcpy(zFullPathname, zFilename, nFilename);
}else{
rc = sqlite3OsFullPathname(pVfs, zFilename,
nFullPathname, zFullPathname);
@@ -53413,8 +55078,8 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
** the right size. This is to guard against size changes that result
** when compiling on a different architecture.
*/
- assert( sizeof(i64)==8 || sizeof(i64)==4 );
- assert( sizeof(u64)==8 || sizeof(u64)==4 );
+ assert( sizeof(i64)==8 );
+ assert( sizeof(u64)==8 );
assert( sizeof(u32)==4 );
assert( sizeof(u16)==2 );
assert( sizeof(Pgno)==4 );
@@ -53444,6 +55109,9 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
#ifdef SQLITE_SECURE_DELETE
pBt->btsFlags |= BTS_SECURE_DELETE;
#endif
+ /* EVIDENCE-OF: R-51873-39618 The page size for a database file is
+ ** determined by the 2-byte integer located at an offset of 16 bytes from
+ ** the beginning of the database file. */
pBt->pageSize = (zDbHeader[16]<<8) | (zDbHeader[17]<<16);
if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE
|| ((pBt->pageSize-1)&pBt->pageSize)!=0 ){
@@ -53462,6 +55130,9 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
#endif
nReserve = 0;
}else{
+ /* EVIDENCE-OF: R-37497-42412 The size of the reserved region is
+ ** determined by the one-byte unsigned integer found at an offset of 20
+ ** into the database file header. */
nReserve = zDbHeader[20];
pBt->btsFlags |= BTS_PAGESIZE_FIXED;
#ifndef SQLITE_OMIT_AUTOVACUUM
@@ -53596,7 +55267,8 @@ static int removeFromSharingList(BtShared *pBt){
/*
** Make sure pBt->pTmpSpace points to an allocation of
-** MX_CELL_SIZE(pBt) bytes.
+** MX_CELL_SIZE(pBt) bytes with a 4-byte prefix for a left-child
+** pointer.
*/
static void allocateTempSpace(BtShared *pBt){
if( !pBt->pTmpSpace ){
@@ -53611,8 +55283,16 @@ static void allocateTempSpace(BtShared *pBt){
** it into a database page. This is not actually a problem, but it
** does cause a valgrind error when the 1 or 2 bytes of unitialized
** data is passed to system call write(). So to avoid this error,
- ** zero the first 4 bytes of temp space here. */
- if( pBt->pTmpSpace ) memset(pBt->pTmpSpace, 0, 4);
+ ** zero the first 4 bytes of temp space here.
+ **
+ ** Also: Provide four bytes of initialized space before the
+ ** beginning of pTmpSpace as an area available to prepend the
+ ** left-child pointer to the beginning of a cell.
+ */
+ if( pBt->pTmpSpace ){
+ memset(pBt->pTmpSpace, 0, 8);
+ pBt->pTmpSpace += 4;
+ }
}
}
@@ -53620,8 +55300,11 @@ static void allocateTempSpace(BtShared *pBt){
** Free the pBt->pTmpSpace allocation
*/
static void freeTempSpace(BtShared *pBt){
- sqlite3PageFree( pBt->pTmpSpace);
- pBt->pTmpSpace = 0;
+ if( pBt->pTmpSpace ){
+ pBt->pTmpSpace -= 4;
+ sqlite3PageFree(pBt->pTmpSpace);
+ pBt->pTmpSpace = 0;
+ }
}
/*
@@ -53647,7 +55330,7 @@ SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){
** The call to sqlite3BtreeRollback() drops any table-locks held by
** this handle.
*/
- sqlite3BtreeRollback(p, SQLITE_OK);
+ sqlite3BtreeRollback(p, SQLITE_OK, 0);
sqlite3BtreeLeave(p);
/* If there are still other outstanding references to the shared-btree
@@ -53783,6 +55466,9 @@ SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve,
BtShared *pBt = p->pBt;
assert( nReserve>=-1 && nReserve<=255 );
sqlite3BtreeEnter(p);
+#if SQLITE_HAS_CODEC
+ if( nReserve>pBt->optimalReserve ) pBt->optimalReserve = (u8)nReserve;
+#endif
if( pBt->btsFlags & BTS_PAGESIZE_FIXED ){
sqlite3BtreeLeave(p);
return SQLITE_READONLY;
@@ -53794,7 +55480,7 @@ SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve,
if( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE &&
((pageSize-1)&pageSize)==0 ){
assert( (pageSize & 7)==0 );
- assert( !pBt->pPage1 && !pBt->pCursor );
+ assert( !pBt->pCursor );
pBt->pageSize = (u32)pageSize;
freeTempSpace(pBt);
}
@@ -53812,7 +55498,6 @@ SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree *p){
return p->pBt->pageSize;
}
-#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_DEBUG)
/*
** This function is similar to sqlite3BtreeGetReserve(), except that it
** may only be called if it is guaranteed that the b-tree mutex is already
@@ -53825,25 +55510,33 @@ SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree *p){
** database handle that owns *p, causing undefined behavior.
*/
SQLITE_PRIVATE int sqlite3BtreeGetReserveNoMutex(Btree *p){
+ int n;
assert( sqlite3_mutex_held(p->pBt->mutex) );
- return p->pBt->pageSize - p->pBt->usableSize;
+ n = p->pBt->pageSize - p->pBt->usableSize;
+ return n;
}
-#endif /* SQLITE_HAS_CODEC || SQLITE_DEBUG */
-#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) || !defined(SQLITE_OMIT_VACUUM)
/*
** Return the number of bytes of space at the end of every page that
** 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.
*/
-SQLITE_PRIVATE int sqlite3BtreeGetReserve(Btree *p){
+SQLITE_PRIVATE int sqlite3BtreeGetOptimalReserve(Btree *p){
int n;
sqlite3BtreeEnter(p);
- n = p->pBt->pageSize - p->pBt->usableSize;
+ n = sqlite3BtreeGetReserveNoMutex(p);
+#ifdef SQLITE_HAS_CODEC
+ if( n<p->pBt->optimalReserve ) n = p->pBt->optimalReserve;
+#endif
sqlite3BtreeLeave(p);
return n;
}
+
/*
** Set the maximum page count for a database if mxPage is positive.
** No changes are made if mxPage is 0 or negative.
@@ -53874,7 +55567,6 @@ SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree *p, int newFlag){
sqlite3BtreeLeave(p);
return b;
}
-#endif /* !defined(SQLITE_OMIT_PAGER_PRAGMAS) || !defined(SQLITE_OMIT_VACUUM) */
/*
** Change the 'auto-vacuum' property of the database. If the 'autoVacuum'
@@ -53959,6 +55651,9 @@ static int lockBtree(BtShared *pBt){
u32 usableSize;
u8 *page1 = pPage1->aData;
rc = SQLITE_NOTADB;
+ /* EVIDENCE-OF: R-43737-39999 Every valid SQLite database file begins
+ ** with the following 16 bytes (in hex): 53 51 4c 69 74 65 20 66 6f 72 6d
+ ** 61 74 20 33 00. */
if( memcmp(page1, zMagicHeader, 16)!=0 ){
goto page1_init_failed;
}
@@ -53999,15 +55694,21 @@ static int lockBtree(BtShared *pBt){
}
#endif
- /* The maximum embedded fraction must be exactly 25%. And the minimum
- ** embedded fraction must be 12.5% for both leaf-data and non-leaf-data.
+ /* EVIDENCE-OF: R-15465-20813 The maximum and minimum embedded payload
+ ** fractions and the leaf payload fraction values must be 64, 32, and 32.
+ **
** The original design allowed these amounts to vary, but as of
** version 3.6.0, we require them to be fixed.
*/
if( memcmp(&page1[21], "\100\040\040",3)!=0 ){
goto page1_init_failed;
}
+ /* EVIDENCE-OF: R-51873-39618 The page size for a database file is
+ ** determined by the 2-byte integer located at an offset of 16 bytes from
+ ** the beginning of the database file. */
pageSize = (page1[16]<<8) | (page1[17]<<16);
+ /* EVIDENCE-OF: R-25008-21688 The size of a page is a power of two
+ ** between 512 and 65536 inclusive. */
if( ((pageSize-1)&pageSize)!=0
|| pageSize>SQLITE_MAX_PAGE_SIZE
|| pageSize<=256
@@ -54015,6 +55716,13 @@ static int lockBtree(BtShared *pBt){
goto page1_init_failed;
}
assert( (pageSize & 7)==0 );
+ /* EVIDENCE-OF: R-59310-51205 The "reserved space" size in the 1-byte
+ ** integer at offset 20 is the number of bytes of space at the end of
+ ** each page to reserve for extensions.
+ **
+ ** EVIDENCE-OF: R-37497-42412 The size of the reserved region is
+ ** determined by the one-byte unsigned integer found at an offset of 20
+ ** into the database file header. */
usableSize = pageSize - page1[20];
if( (u32)pageSize!=pBt->pageSize ){
/* After reading the first page of the database assuming a page size
@@ -54035,6 +55743,9 @@ static int lockBtree(BtShared *pBt){
rc = SQLITE_CORRUPT_BKPT;
goto page1_init_failed;
}
+ /* EVIDENCE-OF: R-28312-64704 However, the usable size is not allowed to
+ ** be less than 480. In other words, if the page size is 512, then the
+ ** reserved space size cannot exceed 32. */
if( usableSize<480 ){
goto page1_init_failed;
}
@@ -54089,7 +55800,7 @@ page1_init_failed:
** false then all cursors are counted.
**
** For the purposes of this routine, a cursor is any cursor that
-** is capable of reading or writing to the databse. Cursors that
+** is capable of reading or writing to the database. Cursors that
** have been tripped into the CURSOR_FAULT state are not counted.
*/
static int countValidCursors(BtShared *pBt, int wrOnly){
@@ -54115,11 +55826,11 @@ static void unlockBtreeIfUnused(BtShared *pBt){
assert( sqlite3_mutex_held(pBt->mutex) );
assert( countValidCursors(pBt,0)==0 || pBt->inTransaction>TRANS_NONE );
if( pBt->inTransaction==TRANS_NONE && pBt->pPage1!=0 ){
- assert( pBt->pPage1->aData );
+ MemPage *pPage1 = pBt->pPage1;
+ assert( pPage1->aData );
assert( sqlite3PagerRefcount(pBt->pPager)==1 );
- assert( pBt->pPage1->aData );
- releasePage(pBt->pPage1);
pBt->pPage1 = 0;
+ releasePage(pPage1);
}
}
@@ -54553,7 +56264,7 @@ static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8);
** calling this function again), return SQLITE_DONE. Or, if an error
** occurs, return some other error code.
**
-** More specificly, this function attempts to re-organize the database so
+** More specifically, this function attempts to re-organize the database so
** that the last page of the file currently in use is no longer in use.
**
** Parameter nFin is the number of pages that this database would contain
@@ -54561,7 +56272,7 @@ static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8);
**
** If the bCommit parameter is non-zero, this function assumes that the
** caller will keep calling incrVacuumStep() until it returns SQLITE_DONE
-** or an error. bCommit is passed true for an auto-vacuum-on-commmit
+** or an error. bCommit is passed true for an auto-vacuum-on-commit
** operation, or false for an incremental vacuum.
*/
static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){
@@ -54915,6 +56626,7 @@ SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree *p, int bCleanup){
sqlite3BtreeLeave(p);
return rc;
}
+ p->iDataVersion--; /* Compensate for pPager->iDataVersion++; */
pBt->inTransaction = TRANS_READ;
btreeClearHasContent(pBt);
}
@@ -54940,60 +56652,91 @@ SQLITE_PRIVATE int sqlite3BtreeCommit(Btree *p){
/*
** This routine sets the state to CURSOR_FAULT and the error
-** code to errCode for every cursor on BtShared that pBtree
-** references.
-**
-** Every cursor is tripped, including cursors that belong
-** to other database connections that happen to be sharing
-** the cache with pBtree.
-**
-** This routine gets called when a rollback occurs.
-** All cursors using the same cache must be tripped
-** to prevent them from trying to use the btree after
-** the rollback. The rollback may have deleted tables
-** or moved root pages, so it is not sufficient to
-** save the state of the cursor. The cursor must be
-** invalidated.
-*/
-SQLITE_PRIVATE void sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode){
+** code to errCode for every cursor on any BtShared that pBtree
+** references. Or if the writeOnly flag is set to 1, then only
+** trip write cursors and leave read cursors unchanged.
+**
+** Every cursor is a candidate to be tripped, including cursors
+** that belong to other database connections that happen to be
+** sharing the cache with pBtree.
+**
+** This routine gets called when a rollback occurs. If the writeOnly
+** flag is true, then only write-cursors need be tripped - read-only
+** cursors save their current positions so that they may continue
+** following the rollback. Or, if writeOnly is false, all cursors are
+** tripped. In general, writeOnly is false if the transaction being
+** rolled back modified the database schema. In this case b-tree root
+** pages may be moved or deleted from the database altogether, making
+** it unsafe for read cursors to continue.
+**
+** If the writeOnly flag is true and an error is encountered while
+** saving the current position of a read-only cursor, all cursors,
+** including all read-cursors are tripped.
+**
+** SQLITE_OK is returned if successful, or if an error occurs while
+** saving a cursor position, an SQLite error code.
+*/
+SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int writeOnly){
BtCursor *p;
- if( pBtree==0 ) return;
- sqlite3BtreeEnter(pBtree);
- for(p=pBtree->pBt->pCursor; p; p=p->pNext){
- int i;
- sqlite3BtreeClearCursor(p);
- p->eState = CURSOR_FAULT;
- p->skipNext = errCode;
- for(i=0; i<=p->iPage; i++){
- releasePage(p->apPage[i]);
- p->apPage[i] = 0;
+ int rc = SQLITE_OK;
+
+ assert( (writeOnly==0 || writeOnly==1) && BTCF_WriteFlag==1 );
+ if( pBtree ){
+ sqlite3BtreeEnter(pBtree);
+ for(p=pBtree->pBt->pCursor; p; p=p->pNext){
+ int i;
+ if( writeOnly && (p->curFlags & BTCF_WriteFlag)==0 ){
+ if( p->eState==CURSOR_VALID || p->eState==CURSOR_SKIPNEXT ){
+ rc = saveCursorPosition(p);
+ if( rc!=SQLITE_OK ){
+ (void)sqlite3BtreeTripAllCursors(pBtree, rc, 0);
+ break;
+ }
+ }
+ }else{
+ sqlite3BtreeClearCursor(p);
+ p->eState = CURSOR_FAULT;
+ p->skipNext = errCode;
+ }
+ for(i=0; i<=p->iPage; i++){
+ releasePage(p->apPage[i]);
+ p->apPage[i] = 0;
+ }
}
+ sqlite3BtreeLeave(pBtree);
}
- sqlite3BtreeLeave(pBtree);
+ return rc;
}
/*
-** Rollback the transaction in progress. All cursors will be
-** invalided by this operation. Any attempt to use a cursor
-** that was open at the beginning of this operation will result
-** in an error.
+** Rollback the transaction in progress.
+**
+** If tripCode is not SQLITE_OK then cursors will be invalidated (tripped).
+** Only write cursors are tripped if writeOnly is true but all cursors are
+** tripped if writeOnly is false. Any attempt to use
+** a tripped cursor will result in an error.
**
** This will release the write lock on the database file. If there
** are no active cursors, it also releases the read lock.
*/
-SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p, int tripCode){
+SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p, int tripCode, int writeOnly){
int rc;
BtShared *pBt = p->pBt;
MemPage *pPage1;
+ assert( writeOnly==1 || writeOnly==0 );
+ assert( tripCode==SQLITE_ABORT_ROLLBACK || tripCode==SQLITE_OK );
sqlite3BtreeEnter(p);
if( tripCode==SQLITE_OK ){
rc = tripCode = saveAllCursors(pBt, 0, 0);
+ if( rc ) writeOnly = 0;
}else{
rc = SQLITE_OK;
}
if( tripCode ){
- sqlite3BtreeTripAllCursors(p, tripCode);
+ int rc2 = sqlite3BtreeTripAllCursors(p, tripCode, writeOnly);
+ assert( rc==SQLITE_OK || (writeOnly==0 && rc2==SQLITE_OK) );
+ if( rc2!=SQLITE_OK ) rc = rc2;
}
btreeIntegrity(p);
@@ -55028,7 +56771,7 @@ SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p, int tripCode){
}
/*
-** Start a statement subtransaction. The subtransaction can can be rolled
+** Start a statement subtransaction. The subtransaction can be rolled
** back independently of the main transaction. You must start a transaction
** before starting a subtransaction. The subtransaction is ended automatically
** if the main transaction commits or rolls back.
@@ -55160,6 +56903,10 @@ static int btreeCursor(
if( NEVER(wrFlag && (pBt->btsFlags & BTS_READ_ONLY)!=0) ){
return SQLITE_READONLY;
}
+ if( wrFlag ){
+ allocateTempSpace(pBt);
+ if( pBt->pTmpSpace==0 ) return SQLITE_NOMEM;
+ }
if( iTable==1 && btreePagecount(pBt)==0 ){
assert( wrFlag==0 );
iTable = 0;
@@ -55243,7 +56990,7 @@ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){
releasePage(pCur->apPage[i]);
}
unlockBtreeIfUnused(pBt);
- sqlite3DbFree(pBtree->db, pCur->aOverflow);
+ sqlite3_free(pCur->aOverflow);
/* sqlite3_free(pCur); */
sqlite3BtreeLeave(pBtree);
}
@@ -55262,7 +57009,7 @@ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){
** compiler to crash when getCellInfo() is implemented as a macro.
** But there is a measureable speed advantage to using the macro on gcc
** (when less compiler optimizations like -Os or -O0 are used and the
-** compiler is not doing agressive inlining.) So we use a real function
+** compiler is not doing aggressive inlining.) So we use a real function
** for MSVC and a macro for everything else. Ticket #2457.
*/
#ifndef NDEBUG
@@ -55324,13 +57071,9 @@ SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor *pCur){
*/
SQLITE_PRIVATE int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){
assert( cursorHoldsMutex(pCur) );
- assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID );
- if( pCur->eState!=CURSOR_VALID ){
- *pSize = 0;
- }else{
- getCellInfo(pCur);
- *pSize = pCur->info.nKey;
- }
+ assert( pCur->eState==CURSOR_VALID );
+ getCellInfo(pCur);
+ *pSize = pCur->info.nKey;
return SQLITE_OK;
}
@@ -55349,8 +57092,11 @@ SQLITE_PRIVATE int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){
SQLITE_PRIVATE int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
+ assert( pCur->iPage>=0 );
+ assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
+ assert( pCur->apPage[pCur->iPage]->intKeyLeaf==1 );
getCellInfo(pCur);
- *pSize = pCur->info.nData;
+ *pSize = pCur->info.nPayload;
return SQLITE_OK;
}
@@ -55479,7 +57225,7 @@ static int copyPayload(
**
** If the current cursor entry uses one or more overflow pages and the
** eOp argument is not 2, this function may allocate space for and lazily
-** popluates the overflow page-list cache array (BtCursor.aOverflow).
+** populates the overflow page-list cache array (BtCursor.aOverflow).
** Subsequent calls use this cache to make seeking to the supplied offset
** more efficient.
**
@@ -55501,30 +57247,28 @@ static int accessPayload(
){
unsigned char *aPayload;
int rc = SQLITE_OK;
- u32 nKey;
int iIdx = 0;
MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */
BtShared *pBt = pCur->pBt; /* Btree this cursor belongs to */
#ifdef SQLITE_DIRECT_OVERFLOW_READ
- int bEnd; /* True if reading to end of data */
+ unsigned char * const pBufStart = pBuf;
+ int bEnd; /* True if reading to end of data */
#endif
assert( pPage );
assert( pCur->eState==CURSOR_VALID );
assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
assert( cursorHoldsMutex(pCur) );
- assert( eOp!=2 || offset==0 ); /* Always start from beginning for eOp==2 */
+ assert( eOp!=2 || offset==0 ); /* Always start from beginning for eOp==2 */
getCellInfo(pCur);
- aPayload = pCur->info.pCell + pCur->info.nHeader;
- nKey = (pPage->intKey ? 0 : (int)pCur->info.nKey);
+ aPayload = pCur->info.pPayload;
#ifdef SQLITE_DIRECT_OVERFLOW_READ
- bEnd = (offset+amt==nKey+pCur->info.nData);
+ bEnd = offset+amt==pCur->info.nPayload;
#endif
+ assert( offset+amt <= pCur->info.nPayload );
- if( NEVER(offset+amt > nKey+pCur->info.nData)
- || &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize]
- ){
+ if( &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize] ){
/* Trying to read or write past the end of the data is an error */
return SQLITE_CORRUPT_BKPT;
}
@@ -55543,6 +57287,7 @@ static int accessPayload(
offset -= pCur->info.nLocal;
}
+
if( rc==SQLITE_OK && amt>0 ){
const u32 ovflSize = pBt->usableSize - 4; /* Bytes content per ovfl page */
Pgno nextPage;
@@ -55560,8 +57305,8 @@ static int accessPayload(
if( eOp!=2 && (pCur->curFlags & BTCF_ValidOvfl)==0 ){
int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize;
if( nOvfl>pCur->nOvflAlloc ){
- Pgno *aNew = (Pgno*)sqlite3DbRealloc(
- pCur->pBtree->db, pCur->aOverflow, nOvfl*2*sizeof(Pgno)
+ Pgno *aNew = (Pgno*)sqlite3Realloc(
+ pCur->aOverflow, nOvfl*2*sizeof(Pgno)
);
if( aNew==0 ){
rc = SQLITE_NOMEM;
@@ -55580,7 +57325,9 @@ static int accessPayload(
** entry for the first required overflow page is valid, skip
** directly to it.
*/
- if( (pCur->curFlags & BTCF_ValidOvfl)!=0 && pCur->aOverflow[offset/ovflSize] ){
+ if( (pCur->curFlags & BTCF_ValidOvfl)!=0
+ && pCur->aOverflow[offset/ovflSize]
+ ){
iIdx = (offset/ovflSize);
nextPage = pCur->aOverflow[iIdx];
offset = (offset%ovflSize);
@@ -55606,6 +57353,7 @@ static int accessPayload(
*/
assert( eOp!=2 );
assert( pCur->curFlags & BTCF_ValidOvfl );
+ assert( pCur->pBtree->db==pBt->db );
if( pCur->aOverflow[iIdx+1] ){
nextPage = pCur->aOverflow[iIdx+1];
}else{
@@ -55633,6 +57381,7 @@ static int accessPayload(
** 4) there is no open write-transaction, and
** 5) the database is not a WAL database,
** 6) all data from the page is being read.
+ ** 7) at least 4 bytes have already been read into the output buffer
**
** then data can be read directly from the database file into the
** output buffer, bypassing the page-cache altogether. This speeds
@@ -55644,9 +57393,11 @@ static int accessPayload(
&& pBt->inTransaction==TRANS_READ /* (4) */
&& (fd = sqlite3PagerFile(pBt->pPager))->pMethods /* (3) */
&& pBt->pPage1->aData[19]==0x01 /* (5) */
+ && &pBuf[-4]>=pBufStart /* (7) */
){
u8 aSave[4];
u8 *aWrite = &pBuf[-4];
+ assert( aWrite>=pBufStart ); /* hence (7) */
memcpy(aSave, aWrite, 4);
rc = sqlite3OsRead(fd, aWrite, a+4, (i64)pBt->pageSize*(nextPage-1));
nextPage = get4byte(aWrite);
@@ -55681,7 +57432,7 @@ static int accessPayload(
/*
** Read part of the key associated with cursor pCur. Exactly
-** "amt" bytes will be transfered into pBuf[]. The transfer
+** "amt" bytes will be transferred into pBuf[]. The transfer
** begins at "offset".
**
** The caller must ensure that pCur is pointing to a valid row
@@ -55751,14 +57502,19 @@ static const void *fetchPayload(
BtCursor *pCur, /* Cursor pointing to entry to read from */
u32 *pAmt /* Write the number of available bytes here */
){
+ u32 amt;
assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]);
assert( pCur->eState==CURSOR_VALID );
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
assert( cursorHoldsMutex(pCur) );
assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
assert( pCur->info.nSize>0 );
- *pAmt = pCur->info.nLocal;
- return (void*)(pCur->info.pCell + pCur->info.nHeader);
+ assert( pCur->info.pPayload>pCur->apPage[pCur->iPage]->aData || CORRUPT_DB );
+ assert( pCur->info.pPayload<pCur->apPage[pCur->iPage]->aDataEnd ||CORRUPT_DB);
+ amt = (int)(pCur->apPage[pCur->iPage]->aDataEnd - pCur->info.pPayload);
+ if( pCur->info.nLocal<amt ) amt = pCur->info.nLocal;
+ *pAmt = amt;
+ return (void*)pCur->info.pPayload;
}
@@ -55821,7 +57577,7 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
return SQLITE_OK;
}
-#if 0
+#if SQLITE_DEBUG
/*
** Page pParent is an internal (non-leaf) tree page. This function
** asserts that page number iChild is the left-child if the iIdx'th
@@ -55830,6 +57586,8 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
** the page.
*/
static void assertParentIndex(MemPage *pParent, int iIdx, Pgno iChild){
+ if( CORRUPT_DB ) return; /* The conditions tested below might not be true
+ ** in a corrupt database */
assert( iIdx<=pParent->nCell );
if( iIdx==pParent->nCell ){
assert( get4byte(&pParent->aData[pParent->hdrOffset+8])==iChild );
@@ -55854,19 +57612,11 @@ static void moveToParent(BtCursor *pCur){
assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPage>0 );
assert( pCur->apPage[pCur->iPage] );
-
- /* UPDATE: It is actually possible for the condition tested by the assert
- ** below to be untrue if the database file is corrupt. This can occur if
- ** one cursor has modified page pParent while a reference to it is held
- ** by a second cursor. Which can only happen if a single page is linked
- ** into more than one b-tree structure in a corrupt database. */
-#if 0
assertParentIndex(
pCur->apPage[pCur->iPage-1],
pCur->aiIdx[pCur->iPage-1],
pCur->apPage[pCur->iPage]->pgno
);
-#endif
testcase( pCur->aiIdx[pCur->iPage-1] > pCur->apPage[pCur->iPage-1]->nCell );
releasePage(pCur->apPage[pCur->iPage]);
@@ -56001,17 +57751,16 @@ static int moveToRightmost(BtCursor *pCur){
assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
- while( rc==SQLITE_OK && !(pPage = pCur->apPage[pCur->iPage])->leaf ){
+ while( !(pPage = pCur->apPage[pCur->iPage])->leaf ){
pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
pCur->aiIdx[pCur->iPage] = pPage->nCell;
rc = moveToChild(pCur, pgno);
+ if( rc ) return rc;
}
- if( rc==SQLITE_OK ){
- pCur->aiIdx[pCur->iPage] = pPage->nCell-1;
- pCur->info.nSize = 0;
- pCur->curFlags &= ~BTCF_ValidNKey;
- }
- return rc;
+ pCur->aiIdx[pCur->iPage] = pPage->nCell-1;
+ assert( pCur->info.nSize==0 );
+ assert( (pCur->curFlags & BTCF_ValidNKey)==0 );
+ return SQLITE_OK;
}
/* Move the cursor to the first entry in the table. Return SQLITE_OK
@@ -56142,7 +57891,7 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
if( pIdxKey ){
xRecordCompare = sqlite3VdbeFindCompare(pIdxKey);
- pIdxKey->isCorrupt = 0;
+ pIdxKey->errCode = 0;
assert( pIdxKey->default_rc==1
|| pIdxKey->default_rc==0
|| pIdxKey->default_rc==-1
@@ -56187,7 +57936,7 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
for(;;){
i64 nCellKey;
pCell = findCell(pPage, idx) + pPage->childPtrSize;
- if( pPage->hasData ){
+ if( pPage->intKeyLeaf ){
while( 0x80 <= *(pCell++) ){
if( pCell>=pPage->aDataEnd ) return SQLITE_CORRUPT_BKPT;
}
@@ -56235,14 +57984,14 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
** single byte varint and the record fits entirely on the main
** b-tree page. */
testcase( pCell+nCell+1==pPage->aDataEnd );
- c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey, 0);
+ c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey);
}else if( !(pCell[1] & 0x80)
&& (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal
){
/* The record-size field is a 2 byte varint and the record
** fits entirely on the main b-tree page. */
testcase( pCell+nCell+2==pPage->aDataEnd );
- c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey, 0);
+ c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey);
}else{
/* The record flows over onto one or more overflow pages. In
** this case the whole cell needs to be parsed, a buffer allocated
@@ -56263,10 +58012,13 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
sqlite3_free(pCellKey);
goto moveto_finish;
}
- c = xRecordCompare(nCell, pCellKey, pIdxKey, 0);
+ c = xRecordCompare(nCell, pCellKey, pIdxKey);
sqlite3_free(pCellKey);
}
- assert( pIdxKey->isCorrupt==0 || c==0 );
+ assert(
+ (pIdxKey->errCode!=SQLITE_CORRUPT || c==0)
+ && (pIdxKey->errCode!=SQLITE_NOMEM || pCur->pBtree->db->mallocFailed)
+ );
if( c<0 ){
lwr = idx+1;
}else if( c>0 ){
@@ -56276,7 +58028,7 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
*pRes = 0;
rc = SQLITE_OK;
pCur->aiIdx[pCur->iPage] = (u16)idx;
- if( pIdxKey->isCorrupt ) rc = SQLITE_CORRUPT;
+ if( pIdxKey->errCode ) rc = SQLITE_CORRUPT;
goto moveto_finish;
}
if( lwr>upr ) break;
@@ -56331,6 +58083,12 @@ SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor *pCur){
** was already pointing to the last entry in the database before
** this routine was called, then set *pRes=1.
**
+** The main entry point is sqlite3BtreeNext(). That routine is optimized
+** for the common case of merely incrementing the cell counter BtCursor.aiIdx
+** to the next cell on the current page. The (slower) btreeNext() helper
+** routine is called when it is necessary to move to a different page or
+** to restore the cursor.
+**
** The calling function will set *pRes to 0 or 1. The initial *pRes value
** will be 1 if the cursor being stepped corresponds to an SQL index and
** if this routine could have been skipped if that SQL index had been
@@ -56340,20 +58098,18 @@ SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor *pCur){
** SQLite btree implementation does not. (Note that the comdb2 btree
** implementation does use this hint, however.)
*/
-SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
+static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
int rc;
int idx;
MemPage *pPage;
assert( cursorHoldsMutex(pCur) );
- assert( pRes!=0 );
- assert( *pRes==0 || *pRes==1 );
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
+ assert( *pRes==0 );
if( pCur->eState!=CURSOR_VALID ){
- invalidateOverflowCache(pCur);
+ assert( (pCur->curFlags & BTCF_ValidOvfl)==0 );
rc = restoreCursorPosition(pCur);
if( rc!=SQLITE_OK ){
- *pRes = 0;
return rc;
}
if( CURSOR_INVALID==pCur->eState ){
@@ -56365,7 +58121,6 @@ SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
pCur->eState = CURSOR_VALID;
if( pCur->skipNext>0 ){
pCur->skipNext = 0;
- *pRes = 0;
return SQLITE_OK;
}
pCur->skipNext = 0;
@@ -56383,18 +58138,11 @@ SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
** page into more than one b-tree structure. */
testcase( idx>pPage->nCell );
- pCur->info.nSize = 0;
- pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
if( idx>=pPage->nCell ){
if( !pPage->leaf ){
rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8]));
- if( rc ){
- *pRes = 0;
- return rc;
- }
- rc = moveToLeftmost(pCur);
- *pRes = 0;
- return rc;
+ if( rc ) return rc;
+ return moveToLeftmost(pCur);
}
do{
if( pCur->iPage==0 ){
@@ -56405,29 +58153,52 @@ SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
moveToParent(pCur);
pPage = pCur->apPage[pCur->iPage];
}while( pCur->aiIdx[pCur->iPage]>=pPage->nCell );
- *pRes = 0;
if( pPage->intKey ){
- rc = sqlite3BtreeNext(pCur, pRes);
+ return sqlite3BtreeNext(pCur, pRes);
}else{
- rc = SQLITE_OK;
+ return SQLITE_OK;
}
- return rc;
}
+ if( pPage->leaf ){
+ return SQLITE_OK;
+ }else{
+ return moveToLeftmost(pCur);
+ }
+}
+SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
+ MemPage *pPage;
+ assert( cursorHoldsMutex(pCur) );
+ assert( pRes!=0 );
+ assert( *pRes==0 || *pRes==1 );
+ assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
+ pCur->info.nSize = 0;
+ pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
*pRes = 0;
+ if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur, pRes);
+ pPage = pCur->apPage[pCur->iPage];
+ if( (++pCur->aiIdx[pCur->iPage])>=pPage->nCell ){
+ pCur->aiIdx[pCur->iPage]--;
+ return btreeNext(pCur, pRes);
+ }
if( pPage->leaf ){
return SQLITE_OK;
+ }else{
+ return moveToLeftmost(pCur);
}
- rc = moveToLeftmost(pCur);
- return rc;
}
-
/*
** Step the cursor to the back to the previous entry in the database. If
** successful then set *pRes=0. If the cursor
** was already pointing to the first entry in the database before
** this routine was called, then set *pRes=1.
**
+** The main entry point is sqlite3BtreePrevious(). That routine is optimized
+** for the common case of merely decrementing the cell counter BtCursor.aiIdx
+** to the previous cell on the current page. The (slower) btreePrevious()
+** helper routine is called when it is necessary to move to a different page
+** or to restore the cursor.
+**
** The calling function will set *pRes to 0 or 1. The initial *pRes value
** will be 1 if the cursor being stepped corresponds to an SQL index and
** if this routine could have been skipped if that SQL index had been
@@ -56437,22 +58208,20 @@ SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
** SQLite btree implementation does not. (Note that the comdb2 btree
** implementation does use this hint, however.)
*/
-SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
+static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){
int rc;
MemPage *pPage;
assert( cursorHoldsMutex(pCur) );
assert( pRes!=0 );
- assert( *pRes==0 || *pRes==1 );
+ assert( *pRes==0 );
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
- pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl);
+ assert( (pCur->curFlags & (BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey))==0 );
+ assert( pCur->info.nSize==0 );
if( pCur->eState!=CURSOR_VALID ){
- if( ALWAYS(pCur->eState>=CURSOR_REQUIRESEEK) ){
- rc = btreeRestoreCursorPosition(pCur);
- if( rc!=SQLITE_OK ){
- *pRes = 0;
- return rc;
- }
+ rc = restoreCursorPosition(pCur);
+ if( rc!=SQLITE_OK ){
+ return rc;
}
if( CURSOR_INVALID==pCur->eState ){
*pRes = 1;
@@ -56463,7 +58232,6 @@ SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
pCur->eState = CURSOR_VALID;
if( pCur->skipNext<0 ){
pCur->skipNext = 0;
- *pRes = 0;
return SQLITE_OK;
}
pCur->skipNext = 0;
@@ -56475,10 +58243,7 @@ SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
if( !pPage->leaf ){
int idx = pCur->aiIdx[pCur->iPage];
rc = moveToChild(pCur, get4byte(findCell(pPage, idx)));
- if( rc ){
- *pRes = 0;
- return rc;
- }
+ if( rc ) return rc;
rc = moveToRightmost(pCur);
}else{
while( pCur->aiIdx[pCur->iPage]==0 ){
@@ -56489,8 +58254,8 @@ SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
}
moveToParent(pCur);
}
- pCur->info.nSize = 0;
- pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
+ assert( pCur->info.nSize==0 );
+ assert( (pCur->curFlags & (BTCF_ValidNKey|BTCF_ValidOvfl))==0 );
pCur->aiIdx[pCur->iPage]--;
pPage = pCur->apPage[pCur->iPage];
@@ -56500,9 +58265,25 @@ SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
rc = SQLITE_OK;
}
}
- *pRes = 0;
return rc;
}
+SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
+ assert( cursorHoldsMutex(pCur) );
+ assert( pRes!=0 );
+ assert( *pRes==0 || *pRes==1 );
+ assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
+ *pRes = 0;
+ pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey);
+ pCur->info.nSize = 0;
+ if( pCur->eState!=CURSOR_VALID
+ || pCur->aiIdx[pCur->iPage]==0
+ || pCur->apPage[pCur->iPage]->leaf==0
+ ){
+ return btreePrevious(pCur, pRes);
+ }
+ pCur->aiIdx[pCur->iPage]--;
+ return SQLITE_OK;
+}
/*
** Allocate a new page from the database file.
@@ -56546,6 +58327,8 @@ static int allocateBtreePage(
assert( eMode==BTALLOC_ANY || (nearby>0 && IfNotOmitAV(pBt->autoVacuum)) );
pPage1 = pBt->pPage1;
mxPage = btreePagecount(pBt);
+ /* EVIDENCE-OF: R-05119-02637 The 4-byte big-endian integer at offset 36
+ ** stores stores the total number of pages on the freelist. */
n = get4byte(&pPage1->aData[36]);
testcase( n==mxPage-1 );
if( n>=mxPage ){
@@ -56592,8 +58375,14 @@ static int allocateBtreePage(
do {
pPrevTrunk = pTrunk;
if( pPrevTrunk ){
+ /* EVIDENCE-OF: R-01506-11053 The first integer on a freelist trunk page
+ ** is the page number of the next freelist trunk page in the list or
+ ** zero if this is the last freelist trunk page. */
iTrunk = get4byte(&pPrevTrunk->aData[0]);
}else{
+ /* EVIDENCE-OF: R-59841-13798 The 4-byte big-endian integer at offset 32
+ ** stores the page number of the first page of the freelist, or zero if
+ ** the freelist is empty. */
iTrunk = get4byte(&pPage1->aData[32]);
}
testcase( iTrunk==mxPage );
@@ -56608,8 +58397,9 @@ static int allocateBtreePage(
}
assert( pTrunk!=0 );
assert( pTrunk->aData!=0 );
-
- k = get4byte(&pTrunk->aData[4]); /* # of leaves on this trunk page */
+ /* EVIDENCE-OF: R-13523-04394 The second integer on a freelist trunk page
+ ** is the number of leaf page pointers to follow. */
+ k = get4byte(&pTrunk->aData[4]);
if( k==0 && !searchList ){
/* The trunk has no leaves and the list is not being searched.
** So extract the trunk page itself and use it as the newly
@@ -56743,7 +58533,7 @@ static int allocateBtreePage(
memcpy(&aData[8+closest*4], &aData[4+k*4], 4);
}
put4byte(&aData[4], k-1);
- noContent = !btreeGetHasContent(pBt, *pPgno) ? PAGER_GET_NOCONTENT : 0;
+ noContent = !btreeGetHasContent(pBt, *pPgno)? PAGER_GET_NOCONTENT : 0;
rc = btreeGetPage(pBt, *pPgno, ppPage, noContent);
if( rc==SQLITE_OK ){
rc = sqlite3PagerWrite((*ppPage)->pDbPage);
@@ -56776,7 +58566,7 @@ static int allocateBtreePage(
** here are confined to those pages that lie between the end of the
** database image and the end of the database file.
*/
- int bNoContent = (0==IfNotOmitAV(pBt->bDoTruncate)) ? PAGER_GET_NOCONTENT : 0;
+ int bNoContent = (0==IfNotOmitAV(pBt->bDoTruncate))? PAGER_GET_NOCONTENT:0;
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
if( rc ) return rc;
@@ -56927,6 +58717,11 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
** for now. At some point in the future (once everyone has upgraded
** to 3.6.0 or later) we should consider fixing the conditional above
** to read "usableSize/4-2" instead of "usableSize/4-8".
+ **
+ ** EVIDENCE-OF: R-19920-11576 However, newer versions of SQLite still
+ ** avoid using the last six entries in the freelist trunk page array in
+ ** order that database files created by newer versions of SQLite can be
+ ** read by older versions of SQLite.
*/
rc = sqlite3PagerWrite(pTrunk->pDbPage);
if( rc==SQLITE_OK ){
@@ -56975,9 +58770,15 @@ static void freePage(MemPage *pPage, int *pRC){
}
/*
-** Free any overflow pages associated with the given Cell.
+** Free any overflow pages associated with the given Cell. Write the
+** local Cell size (the number of bytes on the original page, omitting
+** overflow) into *pnSize.
*/
-static int clearCell(MemPage *pPage, unsigned char *pCell){
+static int clearCell(
+ MemPage *pPage, /* The page that contains the Cell */
+ unsigned char *pCell, /* First byte of the Cell */
+ u16 *pnSize /* Write the size of the Cell here */
+){
BtShared *pBt = pPage->pBt;
CellInfo info;
Pgno ovflPgno;
@@ -56987,6 +58788,7 @@ static int clearCell(MemPage *pPage, unsigned char *pCell){
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
btreeParseCellPtr(pPage, pCell, &info);
+ *pnSize = info.nSize;
if( info.iOverflow==0 ){
return SQLITE_OK; /* No overflow pages. Return without doing anything */
}
@@ -57070,7 +58872,6 @@ static int fillInCell(
BtShared *pBt = pPage->pBt;
Pgno pgnoOvfl = 0;
int nHeader;
- CellInfo info;
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
@@ -57080,23 +58881,17 @@ static int fillInCell(
|| sqlite3PagerIswriteable(pPage->pDbPage) );
/* Fill in the header. */
- nHeader = 0;
- if( !pPage->leaf ){
- nHeader += 4;
- }
- if( pPage->hasData ){
- nHeader += putVarint32(&pCell[nHeader], nData+nZero);
+ nHeader = pPage->childPtrSize;
+ nPayload = nData + nZero;
+ if( pPage->intKeyLeaf ){
+ nHeader += putVarint32(&pCell[nHeader], nPayload);
}else{
- nData = nZero = 0;
+ assert( nData==0 );
+ assert( nZero==0 );
}
nHeader += putVarint(&pCell[nHeader], *(u64*)&nKey);
- btreeParseCellPtr(pPage, pCell, &info);
- assert( info.nHeader==nHeader );
- assert( info.nKey==nKey );
- assert( info.nData==(u32)(nData+nZero) );
- /* Fill in the payload */
- nPayload = nData + nZero;
+ /* Fill in the payload size */
if( pPage->intKey ){
pSrc = pData;
nSrc = nData;
@@ -57105,15 +58900,55 @@ static int fillInCell(
if( NEVER(nKey>0x7fffffff || pKey==0) ){
return SQLITE_CORRUPT_BKPT;
}
- nPayload += (int)nKey;
+ nPayload = (int)nKey;
pSrc = pKey;
nSrc = (int)nKey;
}
- *pnSize = info.nSize;
- spaceLeft = info.nLocal;
+ if( nPayload<=pPage->maxLocal ){
+ n = nHeader + nPayload;
+ testcase( n==3 );
+ testcase( n==4 );
+ if( n<4 ) n = 4;
+ *pnSize = n;
+ spaceLeft = nPayload;
+ pPrior = pCell;
+ }else{
+ int mn = pPage->minLocal;
+ n = mn + (nPayload - mn) % (pPage->pBt->usableSize - 4);
+ testcase( n==pPage->maxLocal );
+ testcase( n==pPage->maxLocal+1 );
+ if( n > pPage->maxLocal ) n = mn;
+ spaceLeft = n;
+ *pnSize = n + nHeader + 4;
+ pPrior = &pCell[nHeader+n];
+ }
pPayload = &pCell[nHeader];
- pPrior = &pCell[info.iOverflow];
+ /* At this point variables should be set as follows:
+ **
+ ** nPayload Total payload size in bytes
+ ** pPayload Begin writing payload here
+ ** spaceLeft Space available at pPayload. If nPayload>spaceLeft,
+ ** that means content must spill into overflow pages.
+ ** *pnSize Size of the local cell (not counting overflow pages)
+ ** pPrior Where to write the pgno of the first overflow page
+ **
+ ** Use a call to btreeParseCellPtr() to verify that the values above
+ ** were computed correctly.
+ */
+#if SQLITE_DEBUG
+ {
+ CellInfo info;
+ btreeParseCellPtr(pPage, pCell, &info);
+ assert( nHeader=(int)(info.pPayload - pCell) );
+ assert( info.nKey==nKey );
+ assert( *pnSize == info.nSize );
+ assert( spaceLeft == info.nLocal );
+ assert( pPrior == &pCell[info.iOverflow] );
+ }
+#endif
+
+ /* Write the payload into the local Cell and any extra into overflow pages */
while( nPayload>0 ){
if( spaceLeft==0 ){
#ifndef SQLITE_OMIT_AUTOVACUUM
@@ -57238,9 +59073,17 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
return;
}
pPage->nCell--;
- memmove(ptr, ptr+2, 2*(pPage->nCell - idx));
- put2byte(&data[hdr+3], pPage->nCell);
- pPage->nFree += 2;
+ if( pPage->nCell==0 ){
+ memset(&data[hdr+1], 0, 4);
+ data[hdr+7] = 0;
+ put2byte(&data[hdr+5], pPage->pBt->usableSize);
+ pPage->nFree = pPage->pBt->usableSize - pPage->hdrOffset
+ - pPage->childPtrSize - 8;
+ }else{
+ memmove(ptr, ptr+2, 2*(pPage->nCell - idx));
+ put2byte(&data[hdr+3], pPage->nCell);
+ pPage->nFree += 2;
+ }
}
/*
@@ -57254,11 +59097,6 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
** in pTemp or the original pCell) and also record its index.
** Allocating a new entry in pPage->aCell[] implies that
** pPage->nOverflow is incremented.
-**
-** If nSkip is non-zero, then do not copy the first nSkip bytes of the
-** cell. The caller will overwrite them after this function returns. If
-** nSkip is non-zero, then pCell may not point to an invalid memory location
-** (but pCell+nSkip is always valid).
*/
static void insertCell(
MemPage *pPage, /* Page into which we are copying */
@@ -57275,7 +59113,6 @@ static void insertCell(
int ins; /* Index in data[] where new cell pointer is inserted */
int cellOffset; /* Address of first cell pointer in data[] */
u8 *data; /* The content of the whole page */
- int nSkip = (iChild ? 4 : 0);
if( *pRC ) return;
@@ -57293,7 +59130,7 @@ static void insertCell(
assert( sz==cellSizePtr(pPage, pCell) || (sz==8 && iChild>0) );
if( pPage->nOverflow || sz+2>pPage->nFree ){
if( pTemp ){
- memcpy(pTemp+nSkip, pCell+nSkip, sz-nSkip);
+ memcpy(pTemp, pCell, sz);
pCell = pTemp;
}
if( iChild ){
@@ -57322,7 +59159,7 @@ static void insertCell(
assert( idx+sz <= (int)pPage->pBt->usableSize );
pPage->nCell++;
pPage->nFree -= (u16)(2 + sz);
- memcpy(&data[idx+nSkip], pCell+nSkip, sz-nSkip);
+ memcpy(&data[idx], pCell, sz);
if( iChild ){
put4byte(&data[idx], iChild);
}
@@ -57341,45 +59178,271 @@ static void insertCell(
}
/*
-** Add a list of cells to a page. The page should be initially empty.
-** The cells are guaranteed to fit on the page.
+** Array apCell[] contains pointers to nCell b-tree page cells. The
+** szCell[] array contains the size in bytes of each cell. This function
+** replaces the current contents of page pPg with the contents of the cell
+** array.
+**
+** Some of the cells in apCell[] may currently be stored in pPg. This
+** function works around problems caused by this by making a copy of any
+** such cells before overwriting the page data.
+**
+** The MemPage.nFree field is invalidated by this function. It is the
+** responsibility of the caller to set it correctly.
*/
-static void assemblePage(
- MemPage *pPage, /* The page to be assemblied */
- int nCell, /* The number of cells to add to this page */
- u8 **apCell, /* Pointers to cell bodies */
- u16 *aSize /* Sizes of the cells */
+static void rebuildPage(
+ MemPage *pPg, /* Edit this page */
+ int nCell, /* Final number of cells on page */
+ u8 **apCell, /* Array of cells */
+ u16 *szCell /* Array of cell sizes */
){
- int i; /* Loop counter */
- u8 *pCellptr; /* Address of next cell pointer */
- int cellbody; /* Address of next cell body */
- u8 * const data = pPage->aData; /* Pointer to data for pPage */
- const int hdr = pPage->hdrOffset; /* Offset of header on pPage */
- const int nUsable = pPage->pBt->usableSize; /* Usable size of page */
+ const int hdr = pPg->hdrOffset; /* Offset of header on pPg */
+ u8 * const aData = pPg->aData; /* Pointer to data for pPg */
+ const int usableSize = pPg->pBt->usableSize;
+ u8 * const pEnd = &aData[usableSize];
+ int i;
+ u8 *pCellptr = pPg->aCellIdx;
+ u8 *pTmp = sqlite3PagerTempSpace(pPg->pBt->pPager);
+ u8 *pData;
- assert( pPage->nOverflow==0 );
- assert( sqlite3_mutex_held(pPage->pBt->mutex) );
- assert( nCell>=0 && nCell<=(int)MX_CELL(pPage->pBt)
- && (int)MX_CELL(pPage->pBt)<=10921);
- assert( sqlite3PagerIswriteable(pPage->pDbPage) );
+ i = get2byte(&aData[hdr+5]);
+ memcpy(&pTmp[i], &aData[i], usableSize - i);
+
+ pData = pEnd;
+ for(i=0; i<nCell; i++){
+ u8 *pCell = apCell[i];
+ if( pCell>aData && pCell<pEnd ){
+ pCell = &pTmp[pCell - aData];
+ }
+ pData -= szCell[i];
+ memcpy(pData, pCell, szCell[i]);
+ put2byte(pCellptr, (pData - aData));
+ pCellptr += 2;
+ assert( szCell[i]==cellSizePtr(pPg, pCell) );
+ }
+
+ /* The pPg->nFree field is now set incorrectly. The caller will fix it. */
+ pPg->nCell = nCell;
+ pPg->nOverflow = 0;
- /* Check that the page has just been zeroed by zeroPage() */
- assert( pPage->nCell==0 );
- assert( get2byteNotZero(&data[hdr+5])==nUsable );
+ put2byte(&aData[hdr+1], 0);
+ put2byte(&aData[hdr+3], pPg->nCell);
+ put2byte(&aData[hdr+5], pData - aData);
+ aData[hdr+7] = 0x00;
+}
- pCellptr = &pPage->aCellIdx[nCell*2];
- cellbody = nUsable;
- for(i=nCell-1; i>=0; i--){
- u16 sz = aSize[i];
- pCellptr -= 2;
- cellbody -= sz;
- put2byte(pCellptr, cellbody);
- memcpy(&data[cellbody], apCell[i], sz);
+/*
+** Array apCell[] contains nCell pointers to b-tree cells. Array szCell
+** contains the size in bytes of each such cell. This function attempts to
+** add the cells stored in the array to page pPg. If it cannot (because
+** the page needs to be defragmented before the cells will fit), non-zero
+** is returned. Otherwise, if the cells are added successfully, zero is
+** returned.
+**
+** Argument pCellptr points to the first entry in the cell-pointer array
+** (part of page pPg) to populate. After cell apCell[0] is written to the
+** page body, a 16-bit offset is written to pCellptr. And so on, for each
+** cell in the array. It is the responsibility of the caller to ensure
+** that it is safe to overwrite this part of the cell-pointer array.
+**
+** When this function is called, *ppData points to the start of the
+** content area on page pPg. If the size of the content area is extended,
+** *ppData is updated to point to the new start of the content area
+** before returning.
+**
+** Finally, argument pBegin points to the byte immediately following the
+** end of the space required by this page for the cell-pointer area (for
+** all cells - not just those inserted by the current call). If the content
+** area must be extended to before this point in order to accomodate all
+** cells in apCell[], then the cells do not fit and non-zero is returned.
+*/
+static int pageInsertArray(
+ MemPage *pPg, /* Page to add cells to */
+ u8 *pBegin, /* End of cell-pointer array */
+ u8 **ppData, /* IN/OUT: Page content -area pointer */
+ u8 *pCellptr, /* Pointer to cell-pointer area */
+ int nCell, /* Number of cells to add to pPg */
+ u8 **apCell, /* Array of cells */
+ u16 *szCell /* Array of cell sizes */
+){
+ int i;
+ u8 *aData = pPg->aData;
+ u8 *pData = *ppData;
+ const int bFreelist = aData[1] || aData[2];
+ assert( CORRUPT_DB || pPg->hdrOffset==0 ); /* Never called on page 1 */
+ for(i=0; i<nCell; i++){
+ int sz = szCell[i];
+ int rc;
+ u8 *pSlot;
+ if( bFreelist==0 || (pSlot = pageFindSlot(pPg, sz, &rc, 0))==0 ){
+ pData -= sz;
+ if( pData<pBegin ) return 1;
+ pSlot = pData;
+ }
+ memcpy(pSlot, apCell[i], sz);
+ put2byte(pCellptr, (pSlot - aData));
+ pCellptr += 2;
}
- put2byte(&data[hdr+3], nCell);
- put2byte(&data[hdr+5], cellbody);
- pPage->nFree -= (nCell*2 + nUsable - cellbody);
- pPage->nCell = (u16)nCell;
+ *ppData = pData;
+ return 0;
+}
+
+/*
+** Array apCell[] contains nCell pointers to b-tree cells. Array szCell
+** contains the size in bytes of each such cell. This function adds the
+** space associated with each cell in the array that is currently stored
+** within the body of pPg to the pPg free-list. The cell-pointers and other
+** fields of the page are not updated.
+**
+** This function returns the total number of cells added to the free-list.
+*/
+static int pageFreeArray(
+ MemPage *pPg, /* Page to edit */
+ int nCell, /* Cells to delete */
+ u8 **apCell, /* Array of cells */
+ u16 *szCell /* Array of cell sizes */
+){
+ u8 * const aData = pPg->aData;
+ u8 * const pEnd = &aData[pPg->pBt->usableSize];
+ u8 * const pStart = &aData[pPg->hdrOffset + 8 + pPg->childPtrSize];
+ int nRet = 0;
+ int i;
+ u8 *pFree = 0;
+ int szFree = 0;
+
+ for(i=0; i<nCell; i++){
+ u8 *pCell = apCell[i];
+ if( pCell>=pStart && pCell<pEnd ){
+ int sz = szCell[i];
+ if( pFree!=(pCell + sz) ){
+ if( pFree ){
+ assert( pFree>aData && (pFree - aData)<65536 );
+ freeSpace(pPg, (u16)(pFree - aData), szFree);
+ }
+ pFree = pCell;
+ szFree = sz;
+ if( pFree+sz>pEnd ) return 0;
+ }else{
+ pFree = pCell;
+ szFree += sz;
+ }
+ nRet++;
+ }
+ }
+ if( pFree ){
+ assert( pFree>aData && (pFree - aData)<65536 );
+ freeSpace(pPg, (u16)(pFree - aData), szFree);
+ }
+ return nRet;
+}
+
+/*
+** apCell[] and szCell[] contains pointers to and sizes of all cells in the
+** pages being balanced. The current page, pPg, has pPg->nCell cells starting
+** with apCell[iOld]. After balancing, this page should hold nNew cells
+** starting at apCell[iNew].
+**
+** This routine makes the necessary adjustments to pPg so that it contains
+** the correct cells after being balanced.
+**
+** The pPg->nFree field is invalid when this function returns. It is the
+** responsibility of the caller to set it correctly.
+*/
+static void editPage(
+ MemPage *pPg, /* Edit this page */
+ int iOld, /* Index of first cell currently on page */
+ int iNew, /* Index of new first cell on page */
+ int nNew, /* Final number of cells on page */
+ u8 **apCell, /* Array of cells */
+ u16 *szCell /* Array of cell sizes */
+){
+ u8 * const aData = pPg->aData;
+ const int hdr = pPg->hdrOffset;
+ u8 *pBegin = &pPg->aCellIdx[nNew * 2];
+ int nCell = pPg->nCell; /* Cells stored on pPg */
+ u8 *pData;
+ u8 *pCellptr;
+ int i;
+ int iOldEnd = iOld + pPg->nCell + pPg->nOverflow;
+ int iNewEnd = iNew + nNew;
+
+#ifdef SQLITE_DEBUG
+ u8 *pTmp = sqlite3PagerTempSpace(pPg->pBt->pPager);
+ memcpy(pTmp, aData, pPg->pBt->usableSize);
+#endif
+
+ /* Remove cells from the start and end of the page */
+ if( iOld<iNew ){
+ int nShift = pageFreeArray(
+ pPg, iNew-iOld, &apCell[iOld], &szCell[iOld]
+ );
+ memmove(pPg->aCellIdx, &pPg->aCellIdx[nShift*2], nCell*2);
+ nCell -= nShift;
+ }
+ if( iNewEnd < iOldEnd ){
+ nCell -= pageFreeArray(
+ pPg, iOldEnd-iNewEnd, &apCell[iNewEnd], &szCell[iNewEnd]
+ );
+ }
+
+ pData = &aData[get2byteNotZero(&aData[hdr+5])];
+ if( pData<pBegin ) goto editpage_fail;
+
+ /* Add cells to the start of the page */
+ if( iNew<iOld ){
+ int nAdd = MIN(nNew,iOld-iNew);
+ assert( (iOld-iNew)<nNew || nCell==0 || CORRUPT_DB );
+ pCellptr = pPg->aCellIdx;
+ memmove(&pCellptr[nAdd*2], pCellptr, nCell*2);
+ if( pageInsertArray(
+ pPg, pBegin, &pData, pCellptr,
+ nAdd, &apCell[iNew], &szCell[iNew]
+ ) ) goto editpage_fail;
+ nCell += nAdd;
+ }
+
+ /* Add any overflow cells */
+ for(i=0; i<pPg->nOverflow; i++){
+ int iCell = (iOld + pPg->aiOvfl[i]) - iNew;
+ if( iCell>=0 && iCell<nNew ){
+ pCellptr = &pPg->aCellIdx[iCell * 2];
+ memmove(&pCellptr[2], pCellptr, (nCell - iCell) * 2);
+ nCell++;
+ if( pageInsertArray(
+ pPg, pBegin, &pData, pCellptr,
+ 1, &apCell[iCell + iNew], &szCell[iCell + iNew]
+ ) ) goto editpage_fail;
+ }
+ }
+
+ /* Append cells to the end of the page */
+ pCellptr = &pPg->aCellIdx[nCell*2];
+ if( pageInsertArray(
+ pPg, pBegin, &pData, pCellptr,
+ nNew-nCell, &apCell[iNew+nCell], &szCell[iNew+nCell]
+ ) ) goto editpage_fail;
+
+ pPg->nCell = nNew;
+ pPg->nOverflow = 0;
+
+ put2byte(&aData[hdr+3], pPg->nCell);
+ put2byte(&aData[hdr+5], pData - aData);
+
+#ifdef SQLITE_DEBUG
+ for(i=0; i<nNew && !CORRUPT_DB; i++){
+ u8 *pCell = apCell[i+iNew];
+ int iOff = get2byte(&pPg->aCellIdx[i*2]);
+ if( pCell>=aData && pCell<&aData[pPg->pBt->usableSize] ){
+ pCell = &pTmp[pCell - aData];
+ }
+ assert( 0==memcmp(pCell, &aData[iOff], szCell[i+iNew]) );
+ }
+#endif
+
+ return;
+ editpage_fail:
+ /* Unable to edit this page. Rebuild it from scratch instead. */
+ rebuildPage(pPg, nNew, &apCell[iNew], &szCell[iNew]);
}
/*
@@ -57433,7 +59496,7 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
assert( pPage->nOverflow==1 );
/* This error condition is now caught prior to reaching this function */
- if( pPage->nCell==0 ) return SQLITE_CORRUPT_BKPT;
+ if( NEVER(pPage->nCell==0) ) return SQLITE_CORRUPT_BKPT;
/* Allocate a new page. This page will become the right-sibling of
** pPage. Make the parent page writable, so that the new divider cell
@@ -57451,7 +59514,8 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
assert( sqlite3PagerIswriteable(pNew->pDbPage) );
assert( pPage->aData[0]==(PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF) );
zeroPage(pNew, PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF);
- assemblePage(pNew, 1, &pCell, &szCell);
+ rebuildPage(pNew, 1, &pCell, &szCell);
+ pNew->nFree = pBt->usableSize - pNew->cellOffset - 2 - szCell;
/* If this is an auto-vacuum database, update the pointer map
** with entries for the new page, and any pointer from the
@@ -57670,17 +59734,22 @@ static int balance_nonroot(
int iOvflSpace = 0; /* First unused byte of aOvflSpace[] */
int szScratch; /* Size of scratch memory requested */
MemPage *apOld[NB]; /* pPage and up to two siblings */
- MemPage *apCopy[NB]; /* Private copies of apOld[] pages */
MemPage *apNew[NB+2]; /* pPage and up to NB siblings after balancing */
u8 *pRight; /* Location in parent of right-sibling pointer */
u8 *apDiv[NB-1]; /* Divider cells in pParent */
int cntNew[NB+2]; /* Index in aCell[] of cell after i-th page */
- int szNew[NB+2]; /* Combined size of cells place on i-th page */
+ int cntOld[NB+2]; /* Old index in aCell[] after i-th page */
+ int szNew[NB+2]; /* Combined size of cells placed on i-th page */
u8 **apCell = 0; /* All cells begin balanced */
u16 *szCell; /* Local size of all cells in apCell[] */
u8 *aSpace1; /* Space for copies of dividers cells */
Pgno pgno; /* Temp var to store a page number in */
+ u8 abDone[NB+2]; /* True after i'th new page is populated */
+ Pgno aPgno[NB+2]; /* Page numbers of new pages before shuffling */
+ Pgno aPgOrder[NB+2]; /* Copy of aPgno[] used for sorting pages */
+ u16 aPgFlags[NB+2]; /* flags field of new pages before shuffling */
+ memset(abDone, 0, sizeof(abDone));
pBt = pParent->pBt;
assert( sqlite3_mutex_held(pBt->mutex) );
assert( sqlite3PagerIswriteable(pParent->pDbPage) );
@@ -57722,7 +59791,6 @@ static int balance_nonroot(
}else if( iParentIdx==i ){
nxDiv = i-2+bBulk;
}else{
- assert( bBulk==0 );
nxDiv = iParentIdx-1;
}
i = 2-bBulk;
@@ -57789,12 +59857,14 @@ static int balance_nonroot(
/*
** Allocate space for memory structures
*/
- k = pBt->pageSize + ROUND8(sizeof(MemPage));
szScratch =
nMaxCells*sizeof(u8*) /* apCell */
+ nMaxCells*sizeof(u16) /* szCell */
- + pBt->pageSize /* aSpace1 */
- + k*nOld; /* Page copies (apCopy) */
+ + pBt->pageSize; /* aSpace1 */
+
+ /* EVIDENCE-OF: R-28375-38319 SQLite will never request a scratch buffer
+ ** that is more than 6 times the database page size. */
+ assert( szScratch<=6*(int)pBt->pageSize );
apCell = sqlite3ScratchMalloc( szScratch );
if( apCell==0 ){
rc = SQLITE_NOMEM;
@@ -57807,8 +59877,8 @@ static int balance_nonroot(
/*
** Load pointers to all cells on sibling pages and the divider cells
** into the local apCell[] array. Make copies of the divider cells
- ** into space obtained from aSpace1[] and remove the divider cells
- ** from pParent.
+ ** into space obtained from aSpace1[]. The divider cells have already
+ ** been removed from pParent.
**
** If the siblings are on leaf pages, then the child pointers of the
** divider cells are stripped from the cells before they are copied
@@ -57821,18 +59891,10 @@ static int balance_nonroot(
** leafData: 1 if pPage holds key+data and pParent holds only keys.
*/
leafCorrection = apOld[0]->leaf*4;
- leafData = apOld[0]->hasData;
+ leafData = apOld[0]->intKeyLeaf;
for(i=0; i<nOld; i++){
int limit;
-
- /* Before doing anything else, take a copy of the i'th original sibling
- ** The rest of this function will use data from the copies rather
- ** that the original pages since the original pages will be in the
- ** process of being overwritten. */
- MemPage *pOld = apCopy[i] = (MemPage*)&aSpace1[pBt->pageSize + k*i];
- memcpy(pOld, apOld[i], sizeof(MemPage));
- pOld->aData = (void*)&pOld[1];
- memcpy(pOld->aData, apOld[i]->aData, pBt->pageSize);
+ MemPage *pOld = apOld[i];
limit = pOld->nCell+pOld->nOverflow;
if( pOld->nOverflow>0 ){
@@ -57853,6 +59915,7 @@ static int balance_nonroot(
nCell++;
}
}
+ cntOld[i] = nCell;
if( i<nOld-1 && !leafData){
u16 sz = (u16)szNew[i];
u8 *pTemp;
@@ -57875,7 +59938,11 @@ static int balance_nonroot(
}else{
assert( leafCorrection==4 );
if( szCell[nCell]<4 ){
- /* Do not allow any cells smaller than 4 bytes. */
+ /* Do not allow any cells smaller than 4 bytes. If a smaller cell
+ ** does exist, pad it with 0x00 bytes. */
+ assert( szCell[nCell]==3 );
+ assert( apCell[nCell]==&aSpace1[iSpace1-3] );
+ aSpace1[iSpace1++] = 0x00;
szCell[nCell] = 4;
}
}
@@ -57904,7 +59971,7 @@ static int balance_nonroot(
assert( i<nMaxCells );
subtotal += szCell[i] + 2;
if( subtotal > usableSpace ){
- szNew[k] = subtotal - szCell[i];
+ szNew[k] = subtotal - szCell[i] - 2;
cntNew[k] = i;
if( leafData ){ i--; }
subtotal = 0;
@@ -57918,9 +59985,10 @@ static int balance_nonroot(
/*
** The packing computed by the previous block is biased toward the siblings
- ** on the left side. The left siblings are always nearly full, while the
- ** right-most sibling might be nearly empty. This block of code attempts
- ** to adjust the packing of siblings to get a better balance.
+ ** on the left side (siblings with smaller keys). The left siblings are
+ ** always nearly full, while the right-most sibling might be nearly empty.
+ ** The next block of code attempts to adjust the packing of siblings to
+ ** get a better balance.
**
** This adjustment is more than an optimization. The packing above might
** be so out of balance as to be illegal. For example, the right-most
@@ -57949,22 +60017,18 @@ static int balance_nonroot(
szNew[i-1] = szLeft;
}
- /* Either we found one or more cells (cntnew[0])>0) or pPage is
- ** a virtual root page. A virtual root page is when the real root
- ** page is page 1 and we are the only child of that page.
- **
- ** UPDATE: The assert() below is not necessarily true if the database
- ** file is corrupt. The corruption will be detected and reported later
- ** in this procedure so there is no need to act upon it now.
+ /* Sanity check: For a non-corrupt database file one of the follwing
+ ** must be true:
+ ** (1) We found one or more cells (cntNew[0])>0), or
+ ** (2) pPage is a virtual root page. A virtual root page is when
+ ** the real root page is page 1 and we are the only child of
+ ** that page.
*/
-#if 0
- assert( cntNew[0]>0 || (pParent->pgno==1 && pParent->nCell==0) );
-#endif
-
- TRACE(("BALANCE: old: %d %d %d ",
- apOld[0]->pgno,
- nOld>=2 ? apOld[1]->pgno : 0,
- nOld>=3 ? apOld[2]->pgno : 0
+ assert( cntNew[0]>0 || (pParent->pgno==1 && pParent->nCell==0) || CORRUPT_DB);
+ TRACE(("BALANCE: old: %d(nc=%d) %d(nc=%d) %d(nc=%d)\n",
+ apOld[0]->pgno, apOld[0]->nCell,
+ nOld>=2 ? apOld[1]->pgno : 0, nOld>=2 ? apOld[1]->nCell : 0,
+ nOld>=3 ? apOld[2]->pgno : 0, nOld>=3 ? apOld[2]->nCell : 0
));
/*
@@ -57987,8 +60051,10 @@ static int balance_nonroot(
assert( i>0 );
rc = allocateBtreePage(pBt, &pNew, &pgno, (bBulk ? 1 : pgno), 0);
if( rc ) goto balance_cleanup;
+ zeroPage(pNew, pageFlags);
apNew[i] = pNew;
nNew++;
+ cntOld[i] = nCell;
/* Set the pointer-map entry for the new sibling page. */
if( ISAUTOVACUUM ){
@@ -58000,135 +60066,247 @@ static int balance_nonroot(
}
}
- /* Free any old pages that were not reused as new pages.
- */
- while( i<nOld ){
- freePage(apOld[i], &rc);
- if( rc ) goto balance_cleanup;
- releasePage(apOld[i]);
- apOld[i] = 0;
- i++;
- }
-
/*
- ** Put the new pages in accending order. This helps to
- ** keep entries in the disk file in order so that a scan
- ** of the table is a linear scan through the file. That
- ** in turn helps the operating system to deliver pages
- ** from the disk more rapidly.
+ ** Reassign page numbers so that the new pages are in ascending order.
+ ** This helps to keep entries in the disk file in order so that a scan
+ ** of the table is closer to a linear scan through the file. That in turn
+ ** helps the operating system to deliver pages from the disk more rapidly.
**
- ** An O(n^2) insertion sort algorithm is used, but since
- ** n is never more than NB (a small constant), that should
- ** not be a problem.
+ ** An O(n^2) insertion sort algorithm is used, but since n is never more
+ ** than (NB+2) (a small constant), that should not be a problem.
**
- ** When NB==3, this one optimization makes the database
- ** about 25% faster for large insertions and deletions.
+ ** When NB==3, this one optimization makes the database about 25% faster
+ ** for large insertions and deletions.
*/
- for(i=0; i<k-1; i++){
- int minV = apNew[i]->pgno;
- int minI = i;
- for(j=i+1; j<k; j++){
- if( apNew[j]->pgno<(unsigned)minV ){
- minI = j;
- minV = apNew[j]->pgno;
+ for(i=0; i<nNew; i++){
+ aPgOrder[i] = aPgno[i] = apNew[i]->pgno;
+ aPgFlags[i] = apNew[i]->pDbPage->flags;
+ for(j=0; j<i; j++){
+ if( aPgno[j]==aPgno[i] ){
+ /* This branch is taken if the set of sibling pages somehow contains
+ ** duplicate entries. This can happen if the database is corrupt.
+ ** It would be simpler to detect this as part of the loop below, but
+ ** we do the detection here in order to avoid populating the pager
+ ** cache with two separate objects associated with the same
+ ** page number. */
+ assert( CORRUPT_DB );
+ rc = SQLITE_CORRUPT_BKPT;
+ goto balance_cleanup;
}
}
- if( minI>i ){
- MemPage *pT;
- pT = apNew[i];
- apNew[i] = apNew[minI];
- apNew[minI] = pT;
+ }
+ for(i=0; i<nNew; i++){
+ int iBest = 0; /* aPgno[] index of page number to use */
+ for(j=1; j<nNew; j++){
+ if( aPgOrder[j]<aPgOrder[iBest] ) iBest = j;
+ }
+ pgno = aPgOrder[iBest];
+ aPgOrder[iBest] = 0xffffffff;
+ if( iBest!=i ){
+ if( iBest>i ){
+ sqlite3PagerRekey(apNew[iBest]->pDbPage, pBt->nPage+iBest+1, 0);
+ }
+ sqlite3PagerRekey(apNew[i]->pDbPage, pgno, aPgFlags[iBest]);
+ apNew[i]->pgno = pgno;
}
}
- TRACE(("new: %d(%d) %d(%d) %d(%d) %d(%d) %d(%d)\n",
- apNew[0]->pgno, szNew[0],
+
+ TRACE(("BALANCE: new: %d(%d nc=%d) %d(%d nc=%d) %d(%d nc=%d) "
+ "%d(%d nc=%d) %d(%d nc=%d)\n",
+ apNew[0]->pgno, szNew[0], cntNew[0],
nNew>=2 ? apNew[1]->pgno : 0, nNew>=2 ? szNew[1] : 0,
+ nNew>=2 ? cntNew[1] - cntNew[0] - !leafData : 0,
nNew>=3 ? apNew[2]->pgno : 0, nNew>=3 ? szNew[2] : 0,
+ nNew>=3 ? cntNew[2] - cntNew[1] - !leafData : 0,
nNew>=4 ? apNew[3]->pgno : 0, nNew>=4 ? szNew[3] : 0,
- nNew>=5 ? apNew[4]->pgno : 0, nNew>=5 ? szNew[4] : 0));
+ nNew>=4 ? cntNew[3] - cntNew[2] - !leafData : 0,
+ nNew>=5 ? apNew[4]->pgno : 0, nNew>=5 ? szNew[4] : 0,
+ nNew>=5 ? cntNew[4] - cntNew[3] - !leafData : 0
+ ));
assert( sqlite3PagerIswriteable(pParent->pDbPage) );
put4byte(pRight, apNew[nNew-1]->pgno);
- /*
- ** Evenly distribute the data in apCell[] across the new pages.
- ** Insert divider cells into pParent as necessary.
+ /* If the sibling pages are not leaves, ensure that the right-child pointer
+ ** of the right-most new sibling page is set to the value that was
+ ** originally in the same field of the right-most old sibling page. */
+ if( (pageFlags & PTF_LEAF)==0 && nOld!=nNew ){
+ MemPage *pOld = (nNew>nOld ? apNew : apOld)[nOld-1];
+ memcpy(&apNew[nNew-1]->aData[8], &pOld->aData[8], 4);
+ }
+
+ /* Make any required updates to pointer map entries associated with
+ ** cells stored on sibling pages following the balance operation. Pointer
+ ** map entries associated with divider cells are set by the insertCell()
+ ** routine. The associated pointer map entries are:
+ **
+ ** a) if the cell contains a reference to an overflow chain, the
+ ** entry associated with the first page in the overflow chain, and
+ **
+ ** b) if the sibling pages are not leaves, the child page associated
+ ** with the cell.
+ **
+ ** If the sibling pages are not leaves, then the pointer map entry
+ ** associated with the right-child of each sibling may also need to be
+ ** updated. This happens below, after the sibling pages have been
+ ** populated, not here.
*/
- j = 0;
- for(i=0; i<nNew; i++){
- /* Assemble the new sibling page. */
+ if( ISAUTOVACUUM ){
+ MemPage *pNew = apNew[0];
+ u8 *aOld = pNew->aData;
+ int cntOldNext = pNew->nCell + pNew->nOverflow;
+ int usableSize = pBt->usableSize;
+ int iNew = 0;
+ int iOld = 0;
+
+ for(i=0; i<nCell; i++){
+ u8 *pCell = apCell[i];
+ if( i==cntOldNext ){
+ MemPage *pOld = (++iOld)<nNew ? apNew[iOld] : apOld[iOld];
+ cntOldNext += pOld->nCell + pOld->nOverflow + !leafData;
+ aOld = pOld->aData;
+ }
+ if( i==cntNew[iNew] ){
+ pNew = apNew[++iNew];
+ if( !leafData ) continue;
+ }
+
+ /* Cell pCell is destined for new sibling page pNew. Originally, it
+ ** was either part of sibling page iOld (possibly an overflow cell),
+ ** or else the divider cell to the left of sibling page iOld. So,
+ ** if sibling page iOld had the same page number as pNew, and if
+ ** pCell really was a part of sibling page iOld (not a divider or
+ ** overflow cell), we can skip updating the pointer map entries. */
+ if( iOld>=nNew
+ || pNew->pgno!=aPgno[iOld]
+ || pCell<aOld
+ || pCell>=&aOld[usableSize]
+ ){
+ if( !leafCorrection ){
+ ptrmapPut(pBt, get4byte(pCell), PTRMAP_BTREE, pNew->pgno, &rc);
+ }
+ if( szCell[i]>pNew->minLocal ){
+ ptrmapPutOvflPtr(pNew, pCell, &rc);
+ }
+ }
+ }
+ }
+
+ /* Insert new divider cells into pParent. */
+ for(i=0; i<nNew-1; i++){
+ u8 *pCell;
+ u8 *pTemp;
+ int sz;
MemPage *pNew = apNew[i];
+ j = cntNew[i];
+
assert( j<nMaxCells );
- zeroPage(pNew, pageFlags);
- assemblePage(pNew, cntNew[i]-j, &apCell[j], &szCell[j]);
- assert( pNew->nCell>0 || (nNew==1 && cntNew[0]==0) );
- assert( pNew->nOverflow==0 );
+ pCell = apCell[j];
+ sz = szCell[j] + leafCorrection;
+ pTemp = &aOvflSpace[iOvflSpace];
+ if( !pNew->leaf ){
+ memcpy(&pNew->aData[8], pCell, 4);
+ }else if( leafData ){
+ /* If the tree is a leaf-data tree, and the siblings are leaves,
+ ** then there is no divider cell in apCell[]. Instead, the divider
+ ** cell consists of the integer key for the right-most cell of
+ ** the sibling-page assembled above only.
+ */
+ CellInfo info;
+ j--;
+ btreeParseCellPtr(pNew, apCell[j], &info);
+ pCell = pTemp;
+ sz = 4 + putVarint(&pCell[4], info.nKey);
+ pTemp = 0;
+ }else{
+ pCell -= 4;
+ /* Obscure case for non-leaf-data trees: If the cell at pCell was
+ ** previously stored on a leaf node, and its reported size was 4
+ ** bytes, then it may actually be smaller than this
+ ** (see btreeParseCellPtr(), 4 bytes is the minimum size of
+ ** any cell). But it is important to pass the correct size to
+ ** insertCell(), so reparse the cell now.
+ **
+ ** Note that this can never happen in an SQLite data file, as all
+ ** cells are at least 4 bytes. It only happens in b-trees used
+ ** to evaluate "IN (SELECT ...)" and similar clauses.
+ */
+ if( szCell[j]==4 ){
+ assert(leafCorrection==4);
+ sz = cellSizePtr(pParent, pCell);
+ }
+ }
+ iOvflSpace += sz;
+ assert( sz<=pBt->maxLocal+23 );
+ assert( iOvflSpace <= (int)pBt->pageSize );
+ insertCell(pParent, nxDiv+i, pCell, sz, pTemp, pNew->pgno, &rc);
+ if( rc!=SQLITE_OK ) goto balance_cleanup;
+ assert( sqlite3PagerIswriteable(pParent->pDbPage) );
+ }
- j = cntNew[i];
+ /* Now update the actual sibling pages. The order in which they are updated
+ ** is important, as this code needs to avoid disrupting any page from which
+ ** cells may still to be read. In practice, this means:
+ **
+ ** (1) If cells are moving left (from apNew[iPg] to apNew[iPg-1])
+ ** then it is not safe to update page apNew[iPg] until after
+ ** the left-hand sibling apNew[iPg-1] has been updated.
+ **
+ ** (2) If cells are moving right (from apNew[iPg] to apNew[iPg+1])
+ ** then it is not safe to update page apNew[iPg] until after
+ ** the right-hand sibling apNew[iPg+1] has been updated.
+ **
+ ** If neither of the above apply, the page is safe to update.
+ **
+ ** The iPg value in the following loop starts at nNew-1 goes down
+ ** to 0, then back up to nNew-1 again, thus making two passes over
+ ** the pages. On the initial downward pass, only condition (1) above
+ ** needs to be tested because (2) will always be true from the previous
+ ** step. On the upward pass, both conditions are always true, so the
+ ** upwards pass simply processes pages that were missed on the downward
+ ** pass.
+ */
+ for(i=1-nNew; i<nNew; i++){
+ int iPg = i<0 ? -i : i;
+ assert( iPg>=0 && iPg<nNew );
+ if( abDone[iPg] ) continue; /* Skip pages already processed */
+ if( i>=0 /* On the upwards pass, or... */
+ || cntOld[iPg-1]>=cntNew[iPg-1] /* Condition (1) is true */
+ ){
+ int iNew;
+ int iOld;
+ int nNewCell;
- /* If the sibling page assembled above was not the right-most sibling,
- ** insert a divider cell into the parent page.
- */
- assert( i<nNew-1 || j==nCell );
- if( j<nCell ){
- u8 *pCell;
- u8 *pTemp;
- int sz;
+ /* Verify condition (1): If cells are moving left, update iPg
+ ** only after iPg-1 has already been updated. */
+ assert( iPg==0 || cntOld[iPg-1]>=cntNew[iPg-1] || abDone[iPg-1] );
- assert( j<nMaxCells );
- pCell = apCell[j];
- sz = szCell[j] + leafCorrection;
- pTemp = &aOvflSpace[iOvflSpace];
- if( !pNew->leaf ){
- memcpy(&pNew->aData[8], pCell, 4);
- }else if( leafData ){
- /* If the tree is a leaf-data tree, and the siblings are leaves,
- ** then there is no divider cell in apCell[]. Instead, the divider
- ** cell consists of the integer key for the right-most cell of
- ** the sibling-page assembled above only.
- */
- CellInfo info;
- j--;
- btreeParseCellPtr(pNew, apCell[j], &info);
- pCell = pTemp;
- sz = 4 + putVarint(&pCell[4], info.nKey);
- pTemp = 0;
+ /* Verify condition (2): If cells are moving right, update iPg
+ ** only after iPg+1 has already been updated. */
+ assert( cntNew[iPg]>=cntOld[iPg] || abDone[iPg+1] );
+
+ if( iPg==0 ){
+ iNew = iOld = 0;
+ nNewCell = cntNew[0];
}else{
- pCell -= 4;
- /* Obscure case for non-leaf-data trees: If the cell at pCell was
- ** previously stored on a leaf node, and its reported size was 4
- ** bytes, then it may actually be smaller than this
- ** (see btreeParseCellPtr(), 4 bytes is the minimum size of
- ** any cell). But it is important to pass the correct size to
- ** insertCell(), so reparse the cell now.
- **
- ** Note that this can never happen in an SQLite data file, as all
- ** cells are at least 4 bytes. It only happens in b-trees used
- ** to evaluate "IN (SELECT ...)" and similar clauses.
- */
- if( szCell[j]==4 ){
- assert(leafCorrection==4);
- sz = cellSizePtr(pParent, pCell);
- }
+ iOld = iPg<nOld ? (cntOld[iPg-1] + !leafData) : nCell;
+ iNew = cntNew[iPg-1] + !leafData;
+ nNewCell = cntNew[iPg] - iNew;
}
- iOvflSpace += sz;
- assert( sz<=pBt->maxLocal+23 );
- assert( iOvflSpace <= (int)pBt->pageSize );
- insertCell(pParent, nxDiv, pCell, sz, pTemp, pNew->pgno, &rc);
- if( rc!=SQLITE_OK ) goto balance_cleanup;
- assert( sqlite3PagerIswriteable(pParent->pDbPage) );
- j++;
- nxDiv++;
+ editPage(apNew[iPg], iOld, iNew, nNewCell, apCell, szCell);
+ abDone[iPg]++;
+ apNew[iPg]->nFree = usableSpace-szNew[iPg];
+ assert( apNew[iPg]->nOverflow==0 );
+ assert( apNew[iPg]->nCell==nNewCell );
}
}
- assert( j==nCell );
+
+ /* All pages have been processed exactly once */
+ assert( memcmp(abDone, "\01\01\01\01\01", nNew)==0 );
+
assert( nOld>0 );
assert( nNew>0 );
- if( (pageFlags & PTF_LEAF)==0 ){
- u8 *zChild = &apCopy[nOld-1]->aData[8];
- memcpy(&apNew[nNew-1]->aData[8], zChild, 4);
- }
if( isRoot && pParent->nCell==0 && pParent->hdrOffset<=apNew[0]->nFree ){
/* The root page of the b-tree now contains no cells. The only sibling
@@ -58141,126 +60319,50 @@ static int balance_nonroot(
** sets all pointer-map entries corresponding to database image pages
** for which the pointer is stored within the content being copied.
**
- ** The second assert below verifies that the child page is defragmented
- ** (it must be, as it was just reconstructed using assemblePage()). This
- ** is important if the parent page happens to be page 1 of the database
- ** image. */
+ ** It is critical that the child page be defragmented before being
+ ** copied into the parent, because if the parent is page 1 then it will
+ ** by smaller than the child due to the database header, and so all the
+ ** free space needs to be up front.
+ */
assert( nNew==1 );
+ rc = defragmentPage(apNew[0]);
+ testcase( rc!=SQLITE_OK );
assert( apNew[0]->nFree ==
- (get2byte(&apNew[0]->aData[5])-apNew[0]->cellOffset-apNew[0]->nCell*2)
+ (get2byte(&apNew[0]->aData[5])-apNew[0]->cellOffset-apNew[0]->nCell*2)
+ || rc!=SQLITE_OK
);
copyNodeContent(apNew[0], pParent, &rc);
freePage(apNew[0], &rc);
- }else if( ISAUTOVACUUM ){
- /* Fix the pointer-map entries for all the cells that were shifted around.
- ** There are several different types of pointer-map entries that need to
- ** be dealt with by this routine. Some of these have been set already, but
- ** many have not. The following is a summary:
- **
- ** 1) The entries associated with new sibling pages that were not
- ** siblings when this function was called. These have already
- ** been set. We don't need to worry about old siblings that were
- ** moved to the free-list - the freePage() code has taken care
- ** of those.
- **
- ** 2) The pointer-map entries associated with the first overflow
- ** page in any overflow chains used by new divider cells. These
- ** have also already been taken care of by the insertCell() code.
- **
- ** 3) If the sibling pages are not leaves, then the child pages of
- ** cells stored on the sibling pages may need to be updated.
- **
- ** 4) If the sibling pages are not internal intkey nodes, then any
- ** overflow pages used by these cells may need to be updated
- ** (internal intkey nodes never contain pointers to overflow pages).
- **
- ** 5) If the sibling pages are not leaves, then the pointer-map
- ** entries for the right-child pages of each sibling may need
- ** to be updated.
- **
- ** Cases 1 and 2 are dealt with above by other code. The next
- ** block deals with cases 3 and 4 and the one after that, case 5. Since
- ** setting a pointer map entry is a relatively expensive operation, this
- ** code only sets pointer map entries for child or overflow pages that have
- ** actually moved between pages. */
- MemPage *pNew = apNew[0];
- MemPage *pOld = apCopy[0];
- int nOverflow = pOld->nOverflow;
- int iNextOld = pOld->nCell + nOverflow;
- int iOverflow = (nOverflow ? pOld->aiOvfl[0] : -1);
- j = 0; /* Current 'old' sibling page */
- k = 0; /* Current 'new' sibling page */
- for(i=0; i<nCell; i++){
- int isDivider = 0;
- while( i==iNextOld ){
- /* Cell i is the cell immediately following the last cell on old
- ** sibling page j. If the siblings are not leaf pages of an
- ** intkey b-tree, then cell i was a divider cell. */
- assert( j+1 < ArraySize(apCopy) );
- assert( j+1 < nOld );
- pOld = apCopy[++j];
- iNextOld = i + !leafData + pOld->nCell + pOld->nOverflow;
- if( pOld->nOverflow ){
- nOverflow = pOld->nOverflow;
- iOverflow = i + !leafData + pOld->aiOvfl[0];
- }
- isDivider = !leafData;
- }
-
- assert(nOverflow>0 || iOverflow<i );
- assert(nOverflow<2 || pOld->aiOvfl[0]==pOld->aiOvfl[1]-1);
- assert(nOverflow<3 || pOld->aiOvfl[1]==pOld->aiOvfl[2]-1);
- if( i==iOverflow ){
- isDivider = 1;
- if( (--nOverflow)>0 ){
- iOverflow++;
- }
- }
-
- if( i==cntNew[k] ){
- /* Cell i is the cell immediately following the last cell on new
- ** sibling page k. If the siblings are not leaf pages of an
- ** intkey b-tree, then cell i is a divider cell. */
- pNew = apNew[++k];
- if( !leafData ) continue;
- }
- assert( j<nOld );
- assert( k<nNew );
-
- /* If the cell was originally divider cell (and is not now) or
- ** an overflow cell, or if the cell was located on a different sibling
- ** page before the balancing, then the pointer map entries associated
- ** with any child or overflow pages need to be updated. */
- if( isDivider || pOld->pgno!=pNew->pgno ){
- if( !leafCorrection ){
- ptrmapPut(pBt, get4byte(apCell[i]), PTRMAP_BTREE, pNew->pgno, &rc);
- }
- if( szCell[i]>pNew->minLocal ){
- ptrmapPutOvflPtr(pNew, apCell[i], &rc);
- }
- }
+ }else if( ISAUTOVACUUM && !leafCorrection ){
+ /* Fix the pointer map entries associated with the right-child of each
+ ** sibling page. All other pointer map entries have already been taken
+ ** care of. */
+ for(i=0; i<nNew; i++){
+ u32 key = get4byte(&apNew[i]->aData[8]);
+ ptrmapPut(pBt, key, PTRMAP_BTREE, apNew[i]->pgno, &rc);
}
+ }
- if( !leafCorrection ){
- for(i=0; i<nNew; i++){
- u32 key = get4byte(&apNew[i]->aData[8]);
- ptrmapPut(pBt, key, PTRMAP_BTREE, apNew[i]->pgno, &rc);
- }
- }
+ assert( pParent->isInit );
+ TRACE(("BALANCE: finished: old=%d new=%d cells=%d\n",
+ nOld, nNew, nCell));
+
+ /* Free any old pages that were not reused as new pages.
+ */
+ for(i=nNew; i<nOld; i++){
+ freePage(apOld[i], &rc);
+ }
#if 0
+ if( ISAUTOVACUUM && rc==SQLITE_OK && apNew[0]->isInit ){
/* The ptrmapCheckPages() contains assert() statements that verify that
** all pointer map pages are set correctly. This is helpful while
** debugging. This is usually disabled because a corrupt database may
** cause an assert() statement to fail. */
ptrmapCheckPages(apNew, nNew);
ptrmapCheckPages(&pParent, 1);
-#endif
}
-
- assert( pParent->isInit );
- TRACE(("BALANCE: finished: old=%d new=%d cells=%d\n",
- nOld, nNew, nCell));
+#endif
/*
** Cleanup before returning.
@@ -58397,7 +60499,7 @@ static int balance(BtCursor *pCur){
rc = sqlite3PagerWrite(pParent->pDbPage);
if( rc==SQLITE_OK ){
#ifndef SQLITE_OMIT_QUICKBALANCE
- if( pPage->hasData
+ if( pPage->intKeyLeaf
&& pPage->nOverflow==1
&& pPage->aiOvfl[0]==pPage->nCell
&& pParent->pgno!=1
@@ -58406,7 +60508,7 @@ static int balance(BtCursor *pCur){
/* Call balance_quick() to create a new sibling of pPage on which
** to store the overflow cell. balance_quick() inserts a new cell
** into pParent, which may cause pParent overflow. If this
- ** happens, the next interation of the do-loop will balance pParent
+ ** happens, the next iteration of the do-loop will balance pParent
** use either balance_nonroot() or balance_deeper(). Until this
** happens, the overflow cell is stored in the aBalanceQuickSpace[]
** buffer.
@@ -58439,7 +60541,8 @@ static int balance(BtCursor *pCur){
** pSpace buffer passed to the latter call to balance_nonroot().
*/
u8 *pSpace = sqlite3PageMalloc(pCur->pBt->pageSize);
- rc = balance_nonroot(pParent, iIdx, pSpace, iPage==1, pCur->hints);
+ rc = balance_nonroot(pParent, iIdx, pSpace, iPage==1,
+ pCur->hints&BTREE_BULKLOAD);
if( pFree ){
/* If pFree is not NULL, it points to the pSpace buffer used
** by a previous call to balance_nonroot(). Its contents are
@@ -58460,6 +60563,7 @@ static int balance(BtCursor *pCur){
/* The next iteration of the do-loop balances the parent page. */
releasePage(pPage);
pCur->iPage--;
+ assert( pCur->iPage>=0 );
}
}while( rc==SQLITE_OK );
@@ -58483,7 +60587,7 @@ static int balance(BtCursor *pCur){
** MovetoUnpacked() to seek cursor pCur to (pKey, nKey) has already
** been performed. seekResult is the search result returned (a negative
** number if pCur points at an entry that is smaller than (pKey, nKey), or
-** a positive value if pCur points at an etry that is larger than
+** a positive value if pCur points at an entry that is larger than
** (pKey, nKey)).
**
** If the seekResult parameter is non-zero, then the caller guarantees that
@@ -58516,7 +60620,8 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
}
assert( cursorHoldsMutex(pCur) );
- assert( (pCur->curFlags & BTCF_WriteFlag)!=0 && pBt->inTransaction==TRANS_WRITE
+ assert( (pCur->curFlags & BTCF_WriteFlag)!=0
+ && pBt->inTransaction==TRANS_WRITE
&& (pBt->btsFlags & BTS_READ_ONLY)==0 );
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
@@ -58549,7 +60654,8 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
/* If the cursor is currently on the last row and we are appending a
** new row onto the end, set the "loc" to avoid an unnecessary btreeMoveto()
** call */
- if( (pCur->curFlags&BTCF_ValidNKey)!=0 && nKey>0 && pCur->info.nKey==nKey-1 ){
+ if( (pCur->curFlags&BTCF_ValidNKey)!=0 && nKey>0
+ && pCur->info.nKey==nKey-1 ){
loc = -1;
}
}
@@ -58568,9 +60674,8 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
pCur->pgnoRoot, nKey, nData, pPage->pgno,
loc==0 ? "overwrite" : "new entry"));
assert( pPage->isInit );
- allocateTempSpace(pBt);
newCell = pBt->pTmpSpace;
- if( newCell==0 ) return SQLITE_NOMEM;
+ assert( newCell!=0 );
rc = fillInCell(pPage, newCell, pKey, nKey, pData, nData, nZero, &szNew);
if( rc ) goto end_insert;
assert( szNew==cellSizePtr(pPage, newCell) );
@@ -58587,8 +60692,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
if( !pPage->leaf ){
memcpy(newCell, oldCell, 4);
}
- szOld = cellSizePtr(pPage, oldCell);
- rc = clearCell(pPage, oldCell);
+ rc = clearCell(pPage, oldCell, &szOld);
dropCell(pPage, idx, szOld, &rc);
if( rc ) goto end_insert;
}else if( loc<0 && pPage->nCell>0 ){
@@ -58640,7 +60744,7 @@ end_insert:
/*
** Delete the entry that the cursor is pointing to. The cursor
-** is left pointing at a arbitrary location.
+** is left pointing at an arbitrary location.
*/
SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur){
Btree *p = pCur->pBtree;
@@ -58650,6 +60754,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur){
unsigned char *pCell; /* Pointer to cell to delete */
int iCellIdx; /* Index of cell to delete */
int iCellDepth; /* Depth of node containing pCell */
+ u16 szCell; /* Size of the cell being deleted */
assert( cursorHoldsMutex(pCur) );
assert( pBt->inTransaction==TRANS_WRITE );
@@ -58698,8 +60803,8 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur){
rc = sqlite3PagerWrite(pPage->pDbPage);
if( rc ) return rc;
- rc = clearCell(pPage, pCell);
- dropCell(pPage, iCellIdx, cellSizePtr(pPage, pCell), &rc);
+ rc = clearCell(pPage, pCell, &szCell);
+ dropCell(pPage, iCellIdx, szCell, &rc);
if( rc ) return rc;
/* If the cell deleted was not located on a leaf page, then the cursor
@@ -58716,10 +60821,8 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur){
pCell = findCell(pLeaf, pLeaf->nCell-1);
nCell = cellSizePtr(pLeaf, pCell);
assert( MX_CELL_SIZE(pBt) >= nCell );
-
- allocateTempSpace(pBt);
pTmp = pBt->pTmpSpace;
-
+ assert( pTmp!=0 );
rc = sqlite3PagerWrite(pLeaf->pDbPage);
insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n, &rc);
dropCell(pLeaf, pLeaf->nCell-1, nCell, &rc);
@@ -58931,14 +61034,19 @@ static int clearDatabasePage(
unsigned char *pCell;
int i;
int hdr;
+ u16 szCell;
assert( sqlite3_mutex_held(pBt->mutex) );
if( pgno>btreePagecount(pBt) ){
return SQLITE_CORRUPT_BKPT;
}
-
rc = getAndInitPage(pBt, pgno, &pPage, 0);
if( rc ) return rc;
+ if( pPage->bBusy ){
+ rc = SQLITE_CORRUPT_BKPT;
+ goto cleardatabasepage_out;
+ }
+ pPage->bBusy = 1;
hdr = pPage->hdrOffset;
for(i=0; i<pPage->nCell; i++){
pCell = findCell(pPage, i);
@@ -58946,7 +61054,7 @@ static int clearDatabasePage(
rc = clearDatabasePage(pBt, get4byte(pCell), 1, pnChange);
if( rc ) goto cleardatabasepage_out;
}
- rc = clearCell(pPage, pCell);
+ rc = clearCell(pPage, pCell, &szCell);
if( rc ) goto cleardatabasepage_out;
}
if( !pPage->leaf ){
@@ -58963,6 +61071,7 @@ static int clearDatabasePage(
}
cleardatabasepage_out:
+ pPage->bBusy = 0;
releasePage(pPage);
return rc;
}
@@ -59152,6 +61261,13 @@ SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
** The schema layer numbers meta values differently. At the schema
** layer (and the SetCookie and ReadCookie opcodes) the number of
** free pages is not visible. So Cookie[0] is the same as Meta[1].
+**
+** This routine treats Meta[BTREE_DATA_VERSION] as a special case. Instead
+** of reading the value out of the header, it instead loads the "DataVersion"
+** from the pager. The BTREE_DATA_VERSION value is not actually stored in the
+** database file. It is a number computed by the pager. But its access
+** pattern is the same as header meta values, and so it is convenient to
+** read it from this routine.
*/
SQLITE_PRIVATE void sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){
BtShared *pBt = p->pBt;
@@ -59162,7 +61278,11 @@ SQLITE_PRIVATE void sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){
assert( pBt->pPage1 );
assert( idx>=0 && idx<=15 );
- *pMeta = get4byte(&pBt->pPage1->aData[36 + idx*4]);
+ if( idx==BTREE_DATA_VERSION ){
+ *pMeta = sqlite3PagerDataVersion(pBt->pPager) + p->iDataVersion;
+ }else{
+ *pMeta = get4byte(&pBt->pPage1->aData[36 + idx*4]);
+ }
/* If auto-vacuum is disabled in this build and this is an auto-vacuum
** database, mark the database as read-only. */
@@ -59253,7 +61373,7 @@ SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){
if( pCur->iPage==0 ){
/* All pages of the b-tree have been visited. Return successfully. */
*pnEntry = nEntry;
- return SQLITE_OK;
+ return moveToRoot(pCur);
}
moveToParent(pCur);
}while ( pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell );
@@ -59292,11 +61412,11 @@ SQLITE_PRIVATE Pager *sqlite3BtreePager(Btree *p){
*/
static void checkAppendMsg(
IntegrityCk *pCheck,
- char *zMsg1,
const char *zFormat,
...
){
va_list ap;
+ char zBuf[200];
if( !pCheck->mxErr ) return;
pCheck->mxErr--;
pCheck->nErr++;
@@ -59304,8 +61424,9 @@ static void checkAppendMsg(
if( pCheck->errMsg.nChar ){
sqlite3StrAccumAppend(&pCheck->errMsg, "\n", 1);
}
- if( zMsg1 ){
- sqlite3StrAccumAppendAll(&pCheck->errMsg, zMsg1);
+ if( pCheck->zPfx ){
+ sqlite3_snprintf(sizeof(zBuf), zBuf, pCheck->zPfx, pCheck->v1, pCheck->v2);
+ sqlite3StrAccumAppendAll(&pCheck->errMsg, zBuf);
}
sqlite3VXPrintf(&pCheck->errMsg, 1, zFormat, ap);
va_end(ap);
@@ -59338,19 +61459,19 @@ static void setPageReferenced(IntegrityCk *pCheck, Pgno iPg){
/*
** Add 1 to the reference count for page iPage. If this is the second
** reference to the page, add an error message to pCheck->zErrMsg.
-** Return 1 if there are 2 ore more references to the page and 0 if
+** Return 1 if there are 2 or more references to the page and 0 if
** if this is the first reference to the page.
**
** Also check that the page number is in bounds.
*/
-static int checkRef(IntegrityCk *pCheck, Pgno iPage, char *zContext){
+static int checkRef(IntegrityCk *pCheck, Pgno iPage){
if( iPage==0 ) return 1;
if( iPage>pCheck->nPage ){
- checkAppendMsg(pCheck, zContext, "invalid page number %d", iPage);
+ checkAppendMsg(pCheck, "invalid page number %d", iPage);
return 1;
}
if( getPageReferenced(pCheck, iPage) ){
- checkAppendMsg(pCheck, zContext, "2nd reference to page %d", iPage);
+ checkAppendMsg(pCheck, "2nd reference to page %d", iPage);
return 1;
}
setPageReferenced(pCheck, iPage);
@@ -59367,8 +61488,7 @@ static void checkPtrmap(
IntegrityCk *pCheck, /* Integrity check context */
Pgno iChild, /* Child page number */
u8 eType, /* Expected pointer map type */
- Pgno iParent, /* Expected pointer map parent page number */
- char *zContext /* Context description (used for error msg) */
+ Pgno iParent /* Expected pointer map parent page number */
){
int rc;
u8 ePtrmapType;
@@ -59377,12 +61497,12 @@ static void checkPtrmap(
rc = ptrmapGet(pCheck->pBt, iChild, &ePtrmapType, &iPtrmapParent);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ) pCheck->mallocFailed = 1;
- checkAppendMsg(pCheck, zContext, "Failed to read ptrmap key=%d", iChild);
+ checkAppendMsg(pCheck, "Failed to read ptrmap key=%d", iChild);
return;
}
if( ePtrmapType!=eType || iPtrmapParent!=iParent ){
- checkAppendMsg(pCheck, zContext,
+ checkAppendMsg(pCheck,
"Bad ptr map entry key=%d expected=(%d,%d) got=(%d,%d)",
iChild, eType, iParent, ePtrmapType, iPtrmapParent);
}
@@ -59397,8 +61517,7 @@ static void checkList(
IntegrityCk *pCheck, /* Integrity checking context */
int isFreeList, /* True for a freelist. False for overflow page list */
int iPage, /* Page number for first page in the list */
- int N, /* Expected number of pages in the list */
- char *zContext /* Context for error messages */
+ int N /* Expected number of pages in the list */
){
int i;
int expected = N;
@@ -59407,14 +61526,14 @@ static void checkList(
DbPage *pOvflPage;
unsigned char *pOvflData;
if( iPage<1 ){
- checkAppendMsg(pCheck, zContext,
+ checkAppendMsg(pCheck,
"%d of %d pages missing from overflow list starting at %d",
N+1, expected, iFirst);
break;
}
- if( checkRef(pCheck, iPage, zContext) ) break;
+ if( checkRef(pCheck, iPage) ) break;
if( sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage) ){
- checkAppendMsg(pCheck, zContext, "failed to get page %d", iPage);
+ checkAppendMsg(pCheck, "failed to get page %d", iPage);
break;
}
pOvflData = (unsigned char *)sqlite3PagerGetData(pOvflPage);
@@ -59422,11 +61541,11 @@ static void checkList(
int n = get4byte(&pOvflData[4]);
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pCheck->pBt->autoVacuum ){
- checkPtrmap(pCheck, iPage, PTRMAP_FREEPAGE, 0, zContext);
+ checkPtrmap(pCheck, iPage, PTRMAP_FREEPAGE, 0);
}
#endif
if( n>(int)pCheck->pBt->usableSize/4-2 ){
- checkAppendMsg(pCheck, zContext,
+ checkAppendMsg(pCheck,
"freelist leaf count too big on page %d", iPage);
N--;
}else{
@@ -59434,10 +61553,10 @@ static void checkList(
Pgno iFreePage = get4byte(&pOvflData[8+i*4]);
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pCheck->pBt->autoVacuum ){
- checkPtrmap(pCheck, iFreePage, PTRMAP_FREEPAGE, 0, zContext);
+ checkPtrmap(pCheck, iFreePage, PTRMAP_FREEPAGE, 0);
}
#endif
- checkRef(pCheck, iFreePage, zContext);
+ checkRef(pCheck, iFreePage);
}
N -= n;
}
@@ -59450,7 +61569,7 @@ static void checkList(
*/
if( pCheck->pBt->autoVacuum && N>0 ){
i = get4byte(pOvflData);
- checkPtrmap(pCheck, i, PTRMAP_OVERFLOW2, iPage, zContext);
+ checkPtrmap(pCheck, i, PTRMAP_OVERFLOW2, iPage);
}
}
#endif
@@ -59460,6 +61579,57 @@ static void checkList(
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
+/*
+** An implementation of a min-heap.
+**
+** aHeap[0] is the number of elements on the heap. aHeap[1] is the
+** root element. The daughter nodes of aHeap[N] are aHeap[N*2]
+** and aHeap[N*2+1].
+**
+** The heap property is this: Every node is less than or equal to both
+** of its daughter nodes. A consequence of the heap property is that the
+** root node aHeap[1] is always the minimum value currently in the heap.
+**
+** The btreeHeapInsert() routine inserts an unsigned 32-bit number onto
+** the heap, preserving the heap property. The btreeHeapPull() routine
+** removes the root element from the heap (the minimum value in the heap)
+** and then moves other nodes around as necessary to preserve the heap
+** property.
+**
+** This heap is used for cell overlap and coverage testing. Each u32
+** entry represents the span of a cell or freeblock on a btree page.
+** The upper 16 bits are the index of the first byte of a range and the
+** lower 16 bits are the index of the last byte of that range.
+*/
+static void btreeHeapInsert(u32 *aHeap, u32 x){
+ u32 j, i = ++aHeap[0];
+ aHeap[i] = x;
+ while( (j = i/2)>0 && aHeap[j]>aHeap[i] ){
+ x = aHeap[j];
+ aHeap[j] = aHeap[i];
+ aHeap[i] = x;
+ i = j;
+ }
+}
+static int btreeHeapPull(u32 *aHeap, u32 *pOut){
+ u32 j, i, x;
+ if( (x = aHeap[0])==0 ) return 0;
+ *pOut = aHeap[1];
+ aHeap[1] = aHeap[x];
+ aHeap[x] = 0xffffffff;
+ aHeap[0]--;
+ i = 1;
+ while( (j = i*2)<=aHeap[0] ){
+ if( aHeap[j]>aHeap[j+1] ) j++;
+ if( aHeap[i]<aHeap[j] ) break;
+ x = aHeap[i];
+ aHeap[i] = aHeap[j];
+ aHeap[j] = x;
+ i = j;
+ }
+ return 1;
+}
+
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
/*
** Do various sanity checks on a single page of a tree. Return
@@ -59482,7 +61652,6 @@ static void checkList(
static int checkTreePage(
IntegrityCk *pCheck, /* Context for the sanity check */
int iPage, /* Page number of the page to check */
- char *zParentContext, /* Parent context */
i64 *pnParentMinKey,
i64 *pnParentMaxKey
){
@@ -59493,23 +61662,27 @@ static int checkTreePage(
u8 *data;
BtShared *pBt;
int usableSize;
- char zContext[100];
- char *hit = 0;
+ u32 *heap = 0;
+ u32 x, prev = 0;
i64 nMinKey = 0;
i64 nMaxKey = 0;
-
- sqlite3_snprintf(sizeof(zContext), zContext, "Page %d: ", iPage);
+ const char *saved_zPfx = pCheck->zPfx;
+ int saved_v1 = pCheck->v1;
+ int saved_v2 = pCheck->v2;
/* Check that the page exists
*/
pBt = pCheck->pBt;
usableSize = pBt->usableSize;
if( iPage==0 ) return 0;
- if( checkRef(pCheck, iPage, zParentContext) ) return 0;
+ if( checkRef(pCheck, iPage) ) return 0;
+ pCheck->zPfx = "Page %d: ";
+ pCheck->v1 = iPage;
if( (rc = btreeGetPage(pBt, (Pgno)iPage, &pPage, 0))!=0 ){
- checkAppendMsg(pCheck, zContext,
+ checkAppendMsg(pCheck,
"unable to get the page. error code=%d", rc);
- return 0;
+ depth = -1;
+ goto end_of_check;
}
/* Clear MemPage.isInit to make sure the corruption detection code in
@@ -59517,10 +61690,11 @@ static int checkTreePage(
pPage->isInit = 0;
if( (rc = btreeInitPage(pPage))!=0 ){
assert( rc==SQLITE_CORRUPT ); /* The only possible error from InitPage */
- checkAppendMsg(pCheck, zContext,
+ checkAppendMsg(pCheck,
"btreeInitPage() returns error code %d", rc);
releasePage(pPage);
- return 0;
+ depth = -1;
+ goto end_of_check;
}
/* Check out all the cells.
@@ -59533,23 +61707,23 @@ static int checkTreePage(
/* Check payload overflow pages
*/
- sqlite3_snprintf(sizeof(zContext), zContext,
- "On tree page %d cell %d: ", iPage, i);
+ pCheck->zPfx = "On tree page %d cell %d: ";
+ pCheck->v1 = iPage;
+ pCheck->v2 = i;
pCell = findCell(pPage,i);
btreeParseCellPtr(pPage, pCell, &info);
- sz = info.nData;
- if( !pPage->intKey ) sz += (int)info.nKey;
+ sz = info.nPayload;
/* For intKey pages, check that the keys are in order.
*/
- else if( i==0 ) nMinKey = nMaxKey = info.nKey;
- else{
- if( info.nKey <= nMaxKey ){
- checkAppendMsg(pCheck, zContext,
- "Rowid %lld out of order (previous was %lld)", info.nKey, nMaxKey);
+ if( pPage->intKey ){
+ if( i==0 ){
+ nMinKey = nMaxKey = info.nKey;
+ }else if( info.nKey <= nMaxKey ){
+ checkAppendMsg(pCheck,
+ "Rowid %lld out of order (previous was %lld)", info.nKey, nMaxKey);
}
nMaxKey = info.nKey;
}
- assert( sz==info.nPayload );
if( (sz>info.nLocal)
&& (&pCell[info.iOverflow]<=&pPage->aData[pBt->usableSize])
){
@@ -59557,10 +61731,10 @@ static int checkTreePage(
Pgno pgnoOvfl = get4byte(&pCell[info.iOverflow]);
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum ){
- checkPtrmap(pCheck, pgnoOvfl, PTRMAP_OVERFLOW1, iPage, zContext);
+ checkPtrmap(pCheck, pgnoOvfl, PTRMAP_OVERFLOW1, iPage);
}
#endif
- checkList(pCheck, 0, pgnoOvfl, nPage, zContext);
+ checkList(pCheck, 0, pgnoOvfl, nPage);
}
/* Check sanity of left child page.
@@ -59569,12 +61743,12 @@ static int checkTreePage(
pgno = get4byte(pCell);
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum ){
- checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage, zContext);
+ checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage);
}
#endif
- d2 = checkTreePage(pCheck, pgno, zContext, &nMinKey, i==0 ? NULL : &nMaxKey);
+ d2 = checkTreePage(pCheck, pgno, &nMinKey, i==0?NULL:&nMaxKey);
if( i>0 && d2!=depth ){
- checkAppendMsg(pCheck, zContext, "Child page depth differs");
+ checkAppendMsg(pCheck, "Child page depth differs");
}
depth = d2;
}
@@ -59582,37 +61756,39 @@ static int checkTreePage(
if( !pPage->leaf ){
pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
- sqlite3_snprintf(sizeof(zContext), zContext,
- "On page %d at right child: ", iPage);
+ pCheck->zPfx = "On page %d at right child: ";
+ pCheck->v1 = iPage;
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum ){
- checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage, zContext);
+ checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage);
}
#endif
- checkTreePage(pCheck, pgno, zContext, NULL, !pPage->nCell ? NULL : &nMaxKey);
+ checkTreePage(pCheck, pgno, NULL, !pPage->nCell?NULL:&nMaxKey);
}
/* For intKey leaf pages, check that the min/max keys are in order
** with any left/parent/right pages.
*/
+ pCheck->zPfx = "Page %d: ";
+ pCheck->v1 = iPage;
if( pPage->leaf && pPage->intKey ){
/* if we are a left child page */
if( pnParentMinKey ){
/* if we are the left most child page */
if( !pnParentMaxKey ){
if( nMaxKey > *pnParentMinKey ){
- checkAppendMsg(pCheck, zContext,
+ checkAppendMsg(pCheck,
"Rowid %lld out of order (max larger than parent min of %lld)",
nMaxKey, *pnParentMinKey);
}
}else{
if( nMinKey <= *pnParentMinKey ){
- checkAppendMsg(pCheck, zContext,
+ checkAppendMsg(pCheck,
"Rowid %lld out of order (min less than parent min of %lld)",
nMinKey, *pnParentMinKey);
}
if( nMaxKey > *pnParentMaxKey ){
- checkAppendMsg(pCheck, zContext,
+ checkAppendMsg(pCheck,
"Rowid %lld out of order (max larger than parent max of %lld)",
nMaxKey, *pnParentMaxKey);
}
@@ -59621,7 +61797,7 @@ static int checkTreePage(
/* else if we're a right child page */
} else if( pnParentMaxKey ){
if( nMinKey <= *pnParentMaxKey ){
- checkAppendMsg(pCheck, zContext,
+ checkAppendMsg(pCheck,
"Rowid %lld out of order (min less than parent max of %lld)",
nMinKey, *pnParentMaxKey);
}
@@ -59632,59 +61808,91 @@ static int checkTreePage(
*/
data = pPage->aData;
hdr = pPage->hdrOffset;
- hit = sqlite3PageMalloc( pBt->pageSize );
- if( hit==0 ){
+ heap = (u32*)sqlite3PageMalloc( pBt->pageSize );
+ pCheck->zPfx = 0;
+ if( heap==0 ){
pCheck->mallocFailed = 1;
}else{
int contentOffset = get2byteNotZero(&data[hdr+5]);
assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */
- memset(hit+contentOffset, 0, usableSize-contentOffset);
- memset(hit, 1, contentOffset);
+ heap[0] = 0;
+ btreeHeapInsert(heap, contentOffset-1);
+ /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the
+ ** number of cells on the page. */
nCell = get2byte(&data[hdr+3]);
+ /* EVIDENCE-OF: R-23882-45353 The cell pointer array of a b-tree page
+ ** immediately follows the b-tree page header. */
cellStart = hdr + 12 - 4*pPage->leaf;
+ /* EVIDENCE-OF: R-02776-14802 The cell pointer array consists of K 2-byte
+ ** integer offsets to the cell contents. */
for(i=0; i<nCell; i++){
int pc = get2byte(&data[cellStart+i*2]);
u32 size = 65536;
- int j;
if( pc<=usableSize-4 ){
size = cellSizePtr(pPage, &data[pc]);
}
if( (int)(pc+size-1)>=usableSize ){
- checkAppendMsg(pCheck, 0,
+ pCheck->zPfx = 0;
+ checkAppendMsg(pCheck,
"Corruption detected in cell %d on page %d",i,iPage);
}else{
- for(j=pc+size-1; j>=pc; j--) hit[j]++;
+ btreeHeapInsert(heap, (pc<<16)|(pc+size-1));
}
}
+ /* EVIDENCE-OF: R-20690-50594 The second field of the b-tree page header
+ ** is the offset of the first freeblock, or zero if there are no
+ ** freeblocks on the page. */
i = get2byte(&data[hdr+1]);
while( i>0 ){
int size, j;
assert( i<=usableSize-4 ); /* Enforced by btreeInitPage() */
size = get2byte(&data[i+2]);
assert( i+size<=usableSize ); /* Enforced by btreeInitPage() */
- for(j=i+size-1; j>=i; j--) hit[j]++;
+ btreeHeapInsert(heap, (i<<16)|(i+size-1));
+ /* EVIDENCE-OF: R-58208-19414 The first 2 bytes of a freeblock are a
+ ** big-endian integer which is the offset in the b-tree page of the next
+ ** freeblock in the chain, or zero if the freeblock is the last on the
+ ** chain. */
j = get2byte(&data[i]);
+ /* EVIDENCE-OF: R-06866-39125 Freeblocks are always connected in order of
+ ** increasing offset. */
assert( j==0 || j>i+size ); /* Enforced by btreeInitPage() */
assert( j<=usableSize-4 ); /* Enforced by btreeInitPage() */
i = j;
}
- for(i=cnt=0; i<usableSize; i++){
- if( hit[i]==0 ){
- cnt++;
- }else if( hit[i]>1 ){
- checkAppendMsg(pCheck, 0,
- "Multiple uses for byte %d of page %d", i, iPage);
+ cnt = 0;
+ assert( heap[0]>0 );
+ assert( (heap[1]>>16)==0 );
+ btreeHeapPull(heap,&prev);
+ while( btreeHeapPull(heap,&x) ){
+ if( (prev&0xffff)+1>(x>>16) ){
+ checkAppendMsg(pCheck,
+ "Multiple uses for byte %u of page %d", x>>16, iPage);
break;
+ }else{
+ cnt += (x>>16) - (prev&0xffff) - 1;
+ prev = x;
}
}
- if( cnt!=data[hdr+7] ){
- checkAppendMsg(pCheck, 0,
+ cnt += usableSize - (prev&0xffff) - 1;
+ /* EVIDENCE-OF: R-43263-13491 The total number of bytes in all fragments
+ ** is stored in the fifth field of the b-tree page header.
+ ** EVIDENCE-OF: R-07161-27322 The one-byte integer at offset 7 gives the
+ ** number of fragmented free bytes within the cell content area.
+ */
+ if( heap[0]==0 && cnt!=data[hdr+7] ){
+ checkAppendMsg(pCheck,
"Fragmentation of %d bytes reported as %d on page %d",
cnt, data[hdr+7], iPage);
}
}
- sqlite3PageFree(hit);
+ sqlite3PageFree(heap);
releasePage(pPage);
+
+end_of_check:
+ pCheck->zPfx = saved_zPfx;
+ pCheck->v1 = saved_v1;
+ pCheck->v2 = saved_v2;
return depth+1;
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
@@ -59725,6 +61933,9 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
sCheck.mxErr = mxErr;
sCheck.nErr = 0;
sCheck.mallocFailed = 0;
+ sCheck.zPfx = 0;
+ sCheck.v1 = 0;
+ sCheck.v2 = 0;
*pnErr = 0;
if( sCheck.nPage==0 ){
sqlite3BtreeLeave(p);
@@ -59739,13 +61950,14 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
}
i = PENDING_BYTE_PAGE(pBt);
if( i<=sCheck.nPage ) setPageReferenced(&sCheck, i);
- sqlite3StrAccumInit(&sCheck.errMsg, zErr, sizeof(zErr), SQLITE_MAX_LENGTH);
- sCheck.errMsg.useMalloc = 2;
+ sqlite3StrAccumInit(&sCheck.errMsg, 0, zErr, sizeof(zErr), SQLITE_MAX_LENGTH);
/* Check the integrity of the freelist
*/
+ sCheck.zPfx = "Main freelist: ";
checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]),
- get4byte(&pBt->pPage1->aData[36]), "Main freelist: ");
+ get4byte(&pBt->pPage1->aData[36]));
+ sCheck.zPfx = 0;
/* Check all the tables.
*/
@@ -59753,10 +61965,12 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
if( aRoot[i]==0 ) continue;
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum && aRoot[i]>1 ){
- checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0, 0);
+ checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0);
}
#endif
- checkTreePage(&sCheck, aRoot[i], "List of tree roots: ", NULL, NULL);
+ sCheck.zPfx = "List of tree roots: ";
+ checkTreePage(&sCheck, aRoot[i], NULL, NULL);
+ sCheck.zPfx = 0;
}
/* Make sure every page in the file is referenced
@@ -59764,7 +61978,7 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){
#ifdef SQLITE_OMIT_AUTOVACUUM
if( getPageReferenced(&sCheck, i)==0 ){
- checkAppendMsg(&sCheck, 0, "Page %d is never used", i);
+ checkAppendMsg(&sCheck, "Page %d is never used", i);
}
#else
/* If the database supports auto-vacuum, make sure no tables contain
@@ -59772,11 +61986,11 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
*/
if( getPageReferenced(&sCheck, i)==0 &&
(PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){
- checkAppendMsg(&sCheck, 0, "Page %d is never used", i);
+ checkAppendMsg(&sCheck, "Page %d is never used", i);
}
if( getPageReferenced(&sCheck, i)!=0 &&
(PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){
- checkAppendMsg(&sCheck, 0, "Pointer map page %d is referenced", i);
+ checkAppendMsg(&sCheck, "Pointer map page %d is referenced", i);
}
#endif
}
@@ -59786,7 +62000,7 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
** of the integrity check.
*/
if( NEVER(nRef != sqlite3PagerRefcount(pBt->pPager)) ){
- checkAppendMsg(&sCheck, 0,
+ checkAppendMsg(&sCheck,
"Outstanding page count goes from %d to %d during this analysis",
nRef, sqlite3PagerRefcount(pBt->pPager)
);
@@ -59982,7 +62196,7 @@ SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void
** required in case any of them are holding references to an xFetch
** version of the b-tree page modified by the accessPayload call below.
**
- ** Note that pCsr must be open on a BTREE_INTKEY table and saveCursorPosition()
+ ** Note that pCsr must be open on a INTKEY table and saveCursorPosition()
** and hence saveAllCursors() cannot fail on a BTREE_INTKEY table, hence
** saveAllCursors can only return SQLITE_OK.
*/
@@ -60053,14 +62267,23 @@ SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){
}
/*
-** set the mask of hint flags for cursor pCsr. Currently the only valid
-** values are 0 and BTREE_BULKLOAD.
+** set the mask of hint flags for cursor pCsr.
*/
SQLITE_PRIVATE void sqlite3BtreeCursorHints(BtCursor *pCsr, unsigned int mask){
- assert( mask==BTREE_BULKLOAD || mask==0 );
+ assert( mask==BTREE_BULKLOAD || mask==BTREE_SEEK_EQ || mask==0 );
pCsr->hints = mask;
}
+#ifdef SQLITE_DEBUG
+/*
+** Return true if the cursor has a hint specified. This routine is
+** only used from within assert() statements
+*/
+SQLITE_PRIVATE int sqlite3BtreeCursorHasHint(BtCursor *pCsr, unsigned int mask){
+ return (pCsr->hints & mask)!=0;
+}
+#endif
+
/*
** Return true if the given Btree is read-only.
*/
@@ -60068,6 +62291,11 @@ SQLITE_PRIVATE int sqlite3BtreeIsReadonly(Btree *p){
return (p->pBt->btsFlags & BTS_READ_ONLY)!=0;
}
+/*
+** Return the size of the header added to each page by this module.
+*/
+SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); }
+
/************** End of btree.c ***********************************************/
/************** Begin file backup.c ******************************************/
/*
@@ -60157,12 +62385,12 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
int rc = 0;
pParse = sqlite3StackAllocZero(pErrorDb, sizeof(*pParse));
if( pParse==0 ){
- sqlite3Error(pErrorDb, SQLITE_NOMEM, "out of memory");
+ sqlite3ErrorWithMsg(pErrorDb, SQLITE_NOMEM, "out of memory");
rc = SQLITE_NOMEM;
}else{
pParse->db = pDb;
if( sqlite3OpenTempDatabase(pParse) ){
- sqlite3Error(pErrorDb, pParse->rc, "%s", pParse->zErrMsg);
+ sqlite3ErrorWithMsg(pErrorDb, pParse->rc, "%s", pParse->zErrMsg);
rc = SQLITE_ERROR;
}
sqlite3DbFree(pErrorDb, pParse->zErrMsg);
@@ -60175,7 +62403,7 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
}
if( i<0 ){
- sqlite3Error(pErrorDb, SQLITE_ERROR, "unknown database %s", zDb);
+ sqlite3ErrorWithMsg(pErrorDb, SQLITE_ERROR, "unknown database %s", zDb);
return 0;
}
@@ -60193,6 +62421,20 @@ static int setDestPgsz(sqlite3_backup *p){
}
/*
+** Check that there is no open read-transaction on the b-tree passed as the
+** second argument. If there is not, return SQLITE_OK. Otherwise, if there
+** is an open read-transaction, return SQLITE_ERROR and leave an error
+** message in database handle db.
+*/
+static int checkReadTransaction(sqlite3 *db, Btree *p){
+ if( sqlite3BtreeIsInReadTrans(p) ){
+ sqlite3ErrorWithMsg(db, SQLITE_ERROR, "destination database is in use");
+ return SQLITE_ERROR;
+ }
+ return SQLITE_OK;
+}
+
+/*
** Create an sqlite3_backup process to copy the contents of zSrcDb from
** connection handle pSrcDb to zDestDb in pDestDb. If successful, return
** a pointer to the new sqlite3_backup object.
@@ -60200,7 +62442,7 @@ static int setDestPgsz(sqlite3_backup *p){
** If an error occurs, NULL is returned and an error code and error message
** stored in database handle pDestDb.
*/
-SQLITE_API sqlite3_backup *sqlite3_backup_init(
+SQLITE_API sqlite3_backup *SQLITE_STDCALL sqlite3_backup_init(
sqlite3* pDestDb, /* Database to write to */
const char *zDestDb, /* Name of database within pDestDb */
sqlite3* pSrcDb, /* Database connection to read from */
@@ -60208,6 +62450,13 @@ SQLITE_API sqlite3_backup *sqlite3_backup_init(
){
sqlite3_backup *p; /* Value to return */
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(pSrcDb)||!sqlite3SafetyCheckOk(pDestDb) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
+
/* Lock the source database handle. The destination database
** handle is not locked in this routine, but it is locked in
** sqlite3_backup_step(). The user is required to ensure that no
@@ -60220,7 +62469,7 @@ SQLITE_API sqlite3_backup *sqlite3_backup_init(
sqlite3_mutex_enter(pDestDb->mutex);
if( pSrcDb==pDestDb ){
- sqlite3Error(
+ sqlite3ErrorWithMsg(
pDestDb, SQLITE_ERROR, "source and destination must be distinct"
);
p = 0;
@@ -60231,7 +62480,7 @@ SQLITE_API sqlite3_backup *sqlite3_backup_init(
** sqlite3_backup_finish(). */
p = (sqlite3_backup *)sqlite3MallocZero(sizeof(sqlite3_backup));
if( !p ){
- sqlite3Error(pDestDb, SQLITE_NOMEM, 0);
+ sqlite3Error(pDestDb, SQLITE_NOMEM);
}
}
@@ -60244,12 +62493,15 @@ SQLITE_API sqlite3_backup *sqlite3_backup_init(
p->iNext = 1;
p->isAttached = 0;
- if( 0==p->pSrc || 0==p->pDest || setDestPgsz(p)==SQLITE_NOMEM ){
+ if( 0==p->pSrc || 0==p->pDest
+ || setDestPgsz(p)==SQLITE_NOMEM
+ || checkReadTransaction(pDestDb, p->pDest)!=SQLITE_OK
+ ){
/* One (or both) of the named databases did not exist or an OOM
- ** error was hit. The error has already been written into the
- ** pDestDb handle. All that is left to do here is free the
- ** sqlite3_backup structure.
- */
+ ** error was hit. Or there is a transaction open on the destination
+ ** database. The error has already been written into the pDestDb
+ ** handle. All that is left to do here is free the sqlite3_backup
+ ** structure. */
sqlite3_free(p);
p = 0;
}
@@ -60293,7 +62545,7 @@ static int backupOnePage(
** guaranteed that the shared-mutex is held by this thread, handle
** p->pSrc may not actually be the owner. */
int nSrcReserve = sqlite3BtreeGetReserveNoMutex(p->pSrc);
- int nDestReserve = sqlite3BtreeGetReserve(p->pDest);
+ int nDestReserve = sqlite3BtreeGetOptimalReserve(p->pDest);
#endif
int rc = SQLITE_OK;
i64 iOff;
@@ -60398,12 +62650,15 @@ static void attachBackupObject(sqlite3_backup *p){
/*
** Copy nPage pages from the source b-tree to the destination.
*/
-SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
+SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage){
int rc;
int destMode; /* Destination journal mode */
int pgszSrc = 0; /* Source page size */
int pgszDest = 0; /* Destination page size */
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( p==0 ) return SQLITE_MISUSE_BKPT;
+#endif
sqlite3_mutex_enter(p->pSrcDb->mutex);
sqlite3BtreeEnter(p->pSrc);
if( p->pDestDb ){
@@ -60640,7 +62895,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
/*
** Release all resources associated with an sqlite3_backup* handle.
*/
-SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p){
+SQLITE_API int SQLITE_STDCALL sqlite3_backup_finish(sqlite3_backup *p){
sqlite3_backup **pp; /* Ptr to head of pagers backup list */
sqlite3 *pSrcDb; /* Source database connection */
int rc; /* Value to return */
@@ -60667,12 +62922,12 @@ SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p){
}
/* If a transaction is still open on the Btree, roll it back. */
- sqlite3BtreeRollback(p->pDest, SQLITE_OK);
+ sqlite3BtreeRollback(p->pDest, SQLITE_OK, 0);
/* Set the error code of the destination database handle. */
rc = (p->rc==SQLITE_DONE) ? SQLITE_OK : p->rc;
if( p->pDestDb ){
- sqlite3Error(p->pDestDb, rc, 0);
+ sqlite3Error(p->pDestDb, rc);
/* Exit the mutexes and free the backup context structure. */
sqlite3LeaveMutexAndCloseZombie(p->pDestDb);
@@ -60692,7 +62947,13 @@ SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p){
** Return the number of pages still to be backed up as of the most recent
** call to sqlite3_backup_step().
*/
-SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p){
+SQLITE_API int SQLITE_STDCALL sqlite3_backup_remaining(sqlite3_backup *p){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( p==0 ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
return p->nRemaining;
}
@@ -60700,7 +62961,13 @@ SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p){
** Return the total number of pages in the source database as of the most
** recent call to sqlite3_backup_step().
*/
-SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p){
+SQLITE_API int SQLITE_STDCALL sqlite3_backup_pagecount(sqlite3_backup *p){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( p==0 ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
return p->nPagecount;
}
@@ -60845,29 +63112,40 @@ copy_finished:
** this: assert( sqlite3VdbeCheckMemInvariants(pMem) );
*/
SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){
- /* The MEM_Dyn bit is set if and only if Mem.xDel is a non-NULL destructor
- ** function for Mem.z
+ /* If MEM_Dyn is set then Mem.xDel!=0.
+ ** Mem.xDel is might not be initialized if MEM_Dyn is clear.
*/
assert( (p->flags & MEM_Dyn)==0 || p->xDel!=0 );
- assert( (p->flags & MEM_Dyn)!=0 || p->xDel==0 );
+
+ /* MEM_Dyn may only be set if Mem.szMalloc==0. In this way we
+ ** ensure that if Mem.szMalloc>0 then it is safe to do
+ ** Mem.z = Mem.zMalloc without having to check Mem.flags&MEM_Dyn.
+ ** That saves a few cycles in inner loops. */
+ assert( (p->flags & MEM_Dyn)==0 || p->szMalloc==0 );
+
+ /* Cannot be both MEM_Int and MEM_Real at the same time */
+ assert( (p->flags & (MEM_Int|MEM_Real))!=(MEM_Int|MEM_Real) );
+
+ /* The szMalloc field holds the correct memory allocation size */
+ assert( p->szMalloc==0
+ || p->szMalloc==sqlite3DbMallocSize(p->db,p->zMalloc) );
/* If p holds a string or blob, the Mem.z must point to exactly
** one of the following:
**
** (1) Memory in Mem.zMalloc and managed by the Mem object
** (2) Memory to be freed using Mem.xDel
- ** (3) An ephermal string or blob
+ ** (3) An ephemeral string or blob
** (4) A static string or blob
*/
- if( (p->flags & (MEM_Str|MEM_Blob)) && p->z!=0 ){
+ if( (p->flags & (MEM_Str|MEM_Blob)) && p->n>0 ){
assert(
- ((p->z==p->zMalloc)? 1 : 0) +
+ ((p->szMalloc>0 && p->z==p->zMalloc)? 1 : 0) +
((p->flags&MEM_Dyn)!=0 ? 1 : 0) +
((p->flags&MEM_Ephem)!=0 ? 1 : 0) +
((p->flags&MEM_Static)!=0 ? 1 : 0) == 1
);
}
-
return 1;
}
#endif
@@ -60921,7 +63199,7 @@ SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
** blob if bPreserve is true. If bPreserve is false, any prior content
** in pMem->z is discarded.
*/
-SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
+SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
assert( sqlite3VdbeCheckMemInvariants(pMem) );
assert( (pMem->flags&MEM_RowSet)==0 );
@@ -60930,24 +63208,28 @@ SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
assert( bPreserve==0 || pMem->flags&(MEM_Blob|MEM_Str) );
testcase( bPreserve && pMem->z==0 );
- if( pMem->zMalloc==0 || sqlite3DbMallocSize(pMem->db, pMem->zMalloc)<n ){
+ assert( pMem->szMalloc==0
+ || pMem->szMalloc==sqlite3DbMallocSize(pMem->db, pMem->zMalloc) );
+ if( pMem->szMalloc<n ){
if( n<32 ) n = 32;
- if( bPreserve && pMem->z==pMem->zMalloc ){
+ if( bPreserve && pMem->szMalloc>0 && pMem->z==pMem->zMalloc ){
pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n);
bPreserve = 0;
}else{
- sqlite3DbFree(pMem->db, pMem->zMalloc);
+ if( pMem->szMalloc>0 ) sqlite3DbFree(pMem->db, pMem->zMalloc);
pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n);
}
if( pMem->zMalloc==0 ){
- VdbeMemRelease(pMem);
+ sqlite3VdbeMemSetNull(pMem);
pMem->z = 0;
- pMem->flags = MEM_Null;
+ pMem->szMalloc = 0;
return SQLITE_NOMEM;
+ }else{
+ pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc);
}
}
- if( pMem->z && bPreserve && pMem->z!=pMem->zMalloc ){
+ if( bPreserve && pMem->z && pMem->z!=pMem->zMalloc ){
memcpy(pMem->zMalloc, pMem->z, pMem->n);
}
if( (pMem->flags&MEM_Dyn)!=0 ){
@@ -60957,15 +63239,37 @@ SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
pMem->z = pMem->zMalloc;
pMem->flags &= ~(MEM_Dyn|MEM_Ephem|MEM_Static);
- pMem->xDel = 0;
return SQLITE_OK;
}
/*
-** Make the given Mem object MEM_Dyn. In other words, make it so
-** that any TEXT or BLOB content is stored in memory obtained from
-** malloc(). In this way, we know that the memory is safe to be
-** overwritten or altered.
+** Change the pMem->zMalloc allocation to be at least szNew bytes.
+** If pMem->zMalloc already meets or exceeds the requested size, this
+** routine is a no-op.
+**
+** Any prior string or blob content in the pMem object may be discarded.
+** The pMem->xDel destructor is called, if it exists. Though MEM_Str
+** and MEM_Blob values may be discarded, MEM_Int, MEM_Real, and MEM_Null
+** values are preserved.
+**
+** Return SQLITE_OK on success or an error code (probably SQLITE_NOMEM)
+** if unable to complete the resizing.
+*/
+SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){
+ assert( szNew>0 );
+ assert( (pMem->flags & MEM_Dyn)==0 || pMem->szMalloc==0 );
+ if( pMem->szMalloc<szNew ){
+ return sqlite3VdbeMemGrow(pMem, szNew, 0);
+ }
+ assert( (pMem->flags & MEM_Dyn)==0 );
+ pMem->z = pMem->zMalloc;
+ pMem->flags &= (MEM_Null|MEM_Int|MEM_Real);
+ return SQLITE_OK;
+}
+
+/*
+** Change pMem so that its MEM_Str or MEM_Blob value is stored in
+** MEM.zMalloc, where it can be safely written.
**
** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails.
*/
@@ -60975,17 +63279,18 @@ SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){
assert( (pMem->flags&MEM_RowSet)==0 );
ExpandBlob(pMem);
f = pMem->flags;
- if( (f&(MEM_Str|MEM_Blob)) && pMem->z!=pMem->zMalloc ){
+ if( (f&(MEM_Str|MEM_Blob)) && (pMem->szMalloc==0 || pMem->z!=pMem->zMalloc) ){
if( sqlite3VdbeMemGrow(pMem, pMem->n + 2, 1) ){
return SQLITE_NOMEM;
}
pMem->z[pMem->n] = 0;
pMem->z[pMem->n+1] = 0;
pMem->flags |= MEM_Term;
+ }
+ pMem->flags &= ~MEM_Ephem;
#ifdef SQLITE_DEBUG
- pMem->pScopyFrom = 0;
+ pMem->pScopyFrom = 0;
#endif
- }
return SQLITE_OK;
}
@@ -61019,15 +63324,11 @@ SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *pMem){
}
#endif
-
/*
-** Make sure the given Mem is \u0000 terminated.
+** It is already known that pMem contains an unterminated string.
+** Add the zero terminator.
*/
-SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem *pMem){
- assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
- if( (pMem->flags & MEM_Term)!=0 || (pMem->flags & MEM_Str)==0 ){
- return SQLITE_OK; /* Nothing to do */
- }
+static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){
if( sqlite3VdbeMemGrow(pMem, pMem->n+2, 1) ){
return SQLITE_NOMEM;
}
@@ -61038,20 +63339,34 @@ SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem *pMem){
}
/*
+** Make sure the given Mem is \u0000 terminated.
+*/
+SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem *pMem){
+ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
+ testcase( (pMem->flags & (MEM_Term|MEM_Str))==(MEM_Term|MEM_Str) );
+ testcase( (pMem->flags & (MEM_Term|MEM_Str))==0 );
+ if( (pMem->flags & (MEM_Term|MEM_Str))!=MEM_Str ){
+ return SQLITE_OK; /* Nothing to do */
+ }else{
+ return vdbeMemAddTerminator(pMem);
+ }
+}
+
+/*
** Add MEM_Str to the set of representations for the given Mem. Numbers
** are converted using sqlite3_snprintf(). Converting a BLOB to a string
** is a no-op.
**
-** Existing representations MEM_Int and MEM_Real are *not* invalidated.
+** Existing representations MEM_Int and MEM_Real are invalidated if
+** bForce is true but are retained if bForce is false.
**
** A MEM_Null value will never be passed to this function. This function is
** used for converting values to text for returning to the user (i.e. via
** sqlite3_value_text()), or for ensuring that values to be used as btree
** keys are strings. In the former case a NULL pointer is returned the
-** user and the later is an internal programming error.
+** user and the latter is an internal programming error.
*/
-SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, int enc){
- int rc = SQLITE_OK;
+SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){
int fg = pMem->flags;
const int nByte = 32;
@@ -61063,11 +63378,11 @@ SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, int enc){
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
- if( sqlite3VdbeMemGrow(pMem, nByte, 0) ){
+ if( sqlite3VdbeMemClearAndResize(pMem, nByte) ){
return SQLITE_NOMEM;
}
- /* For a Real or Integer, use sqlite3_mprintf() to produce the UTF-8
+ /* For a Real or Integer, use sqlite3_snprintf() to produce the UTF-8
** string representation of the value. Then, if the required encoding
** is UTF-16le or UTF-16be do a translation.
**
@@ -61077,13 +63392,14 @@ SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, int enc){
sqlite3_snprintf(nByte, pMem->z, "%lld", pMem->u.i);
}else{
assert( fg & MEM_Real );
- sqlite3_snprintf(nByte, pMem->z, "%!.15g", pMem->r);
+ sqlite3_snprintf(nByte, pMem->z, "%!.15g", pMem->u.r);
}
pMem->n = sqlite3Strlen30(pMem->z);
pMem->enc = SQLITE_UTF8;
pMem->flags |= MEM_Str|MEM_Term;
+ if( bForce ) pMem->flags &= ~(MEM_Int|MEM_Real);
sqlite3VdbeChangeEncoding(pMem, enc);
- return rc;
+ return SQLITE_OK;
}
/*
@@ -61098,59 +63414,90 @@ SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
int rc = SQLITE_OK;
if( ALWAYS(pFunc && pFunc->xFinalize) ){
sqlite3_context ctx;
+ Mem t;
assert( (pMem->flags & MEM_Null)!=0 || pFunc==pMem->u.pDef );
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
memset(&ctx, 0, sizeof(ctx));
- ctx.s.flags = MEM_Null;
- ctx.s.db = pMem->db;
+ memset(&t, 0, sizeof(t));
+ t.flags = MEM_Null;
+ t.db = pMem->db;
+ ctx.pOut = &t;
ctx.pMem = pMem;
ctx.pFunc = pFunc;
pFunc->xFinalize(&ctx); /* IMP: R-24505-23230 */
- assert( 0==(pMem->flags&MEM_Dyn) && !pMem->xDel );
- sqlite3DbFree(pMem->db, pMem->zMalloc);
- memcpy(pMem, &ctx.s, sizeof(ctx.s));
+ assert( (pMem->flags & MEM_Dyn)==0 );
+ if( pMem->szMalloc>0 ) sqlite3DbFree(pMem->db, pMem->zMalloc);
+ memcpy(pMem, &t, sizeof(t));
rc = ctx.isError;
}
return rc;
}
/*
-** If the memory cell contains a string value that must be freed by
-** invoking an external callback, free it now. Calling this function
-** does not free any Mem.zMalloc buffer.
+** If the memory cell contains a value that must be freed by
+** invoking the external callback in Mem.xDel, then this routine
+** will free that value. It also sets Mem.flags to MEM_Null.
+**
+** This is a helper routine for sqlite3VdbeMemSetNull() and
+** for sqlite3VdbeMemRelease(). Use those other routines as the
+** entry point for releasing Mem resources.
*/
-SQLITE_PRIVATE void sqlite3VdbeMemReleaseExternal(Mem *p){
+static SQLITE_NOINLINE void vdbeMemClearExternAndSetNull(Mem *p){
assert( p->db==0 || sqlite3_mutex_held(p->db->mutex) );
+ assert( VdbeMemDynamic(p) );
if( p->flags&MEM_Agg ){
sqlite3VdbeMemFinalize(p, p->u.pDef);
assert( (p->flags & MEM_Agg)==0 );
- sqlite3VdbeMemRelease(p);
- }else if( p->flags&MEM_Dyn ){
+ testcase( p->flags & MEM_Dyn );
+ }
+ if( p->flags&MEM_Dyn ){
assert( (p->flags&MEM_RowSet)==0 );
assert( p->xDel!=SQLITE_DYNAMIC && p->xDel!=0 );
p->xDel((void *)p->z);
- p->xDel = 0;
}else if( p->flags&MEM_RowSet ){
sqlite3RowSetClear(p->u.pRowSet);
}else if( p->flags&MEM_Frame ){
- sqlite3VdbeMemSetNull(p);
+ VdbeFrame *pFrame = p->u.pFrame;
+ pFrame->pParent = pFrame->v->pDelFrame;
+ pFrame->v->pDelFrame = pFrame;
}
+ p->flags = MEM_Null;
}
/*
-** Release any memory held by the Mem. This may leave the Mem in an
-** inconsistent state, for example with (Mem.z==0) and
-** (Mem.flags==MEM_Str).
+** Release memory held by the Mem p, both external memory cleared
+** by p->xDel and memory in p->zMalloc.
+**
+** This is a helper routine invoked by sqlite3VdbeMemRelease() in
+** the unusual case where there really is memory in p that needs
+** to be freed.
*/
-SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p){
- assert( sqlite3VdbeCheckMemInvariants(p) );
- VdbeMemRelease(p);
- if( p->zMalloc ){
+static SQLITE_NOINLINE void vdbeMemClear(Mem *p){
+ if( VdbeMemDynamic(p) ){
+ vdbeMemClearExternAndSetNull(p);
+ }
+ if( p->szMalloc ){
sqlite3DbFree(p->db, p->zMalloc);
- p->zMalloc = 0;
+ p->szMalloc = 0;
}
p->z = 0;
- assert( p->xDel==0 ); /* Zeroed by VdbeMemRelease() above */
+}
+
+/*
+** Release any memory resources held by the Mem. Both the memory that is
+** free by Mem.xDel and the Mem.zMalloc allocation are freed.
+**
+** Use this routine prior to clean up prior to abandoning a Mem, or to
+** reset a Mem back to its minimum memory utilization.
+**
+** Use sqlite3VdbeMemSetNull() to release just the Mem.xDel space
+** prior to inserting new content into the Mem.
+*/
+SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p){
+ assert( sqlite3VdbeCheckMemInvariants(p) );
+ if( VdbeMemDynamic(p) || p->szMalloc ){
+ vdbeMemClear(p);
+ }
}
/*
@@ -61189,7 +63536,7 @@ static i64 doubleToInt64(double r){
** If pMem is an integer, then the value is exact. If pMem is
** a floating-point then the value returned is the integer part.
** If pMem is a string or blob, then we make an attempt to convert
-** it into a integer and return that. If pMem represents an
+** it into an integer and return that. If pMem represents an
** an SQL-NULL value, return 0.
**
** If pMem represents a string value, its encoding might be changed.
@@ -61202,11 +63549,10 @@ SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem *pMem){
if( flags & MEM_Int ){
return pMem->u.i;
}else if( flags & MEM_Real ){
- return doubleToInt64(pMem->r);
+ return doubleToInt64(pMem->u.r);
}else if( flags & (MEM_Str|MEM_Blob) ){
i64 value = 0;
assert( pMem->z || pMem->n==0 );
- testcase( pMem->z==0 );
sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc);
return value;
}else{
@@ -61224,7 +63570,7 @@ SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
if( pMem->flags & MEM_Real ){
- return pMem->r;
+ return pMem->u.r;
}else if( pMem->flags & MEM_Int ){
return (double)pMem->u.i;
}else if( pMem->flags & (MEM_Str|MEM_Blob) ){
@@ -61243,12 +63589,13 @@ SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){
** MEM_Int if we can.
*/
SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem *pMem){
+ i64 ix;
assert( pMem->flags & MEM_Real );
assert( (pMem->flags & MEM_RowSet)==0 );
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
- pMem->u.i = doubleToInt64(pMem->r);
+ ix = doubleToInt64(pMem->u.r);
/* Only mark the value as an integer if
**
@@ -61260,11 +63607,9 @@ SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem *pMem){
** the second condition under the assumption that addition overflow causes
** values to wrap around.
*/
- if( pMem->r==(double)pMem->u.i
- && pMem->u.i>SMALLEST_INT64
- && pMem->u.i<LARGEST_INT64
- ){
- pMem->flags |= MEM_Int;
+ if( pMem->u.r==ix && ix>SMALLEST_INT64 && ix<LARGEST_INT64 ){
+ pMem->u.i = ix;
+ MemSetTypeFlag(pMem, MEM_Int);
}
}
@@ -61289,7 +63634,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem *pMem){
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
- pMem->r = sqlite3VdbeRealValue(pMem);
+ pMem->u.r = sqlite3VdbeRealValue(pMem);
MemSetTypeFlag(pMem, MEM_Real);
return SQLITE_OK;
}
@@ -61309,7 +63654,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){
if( 0==sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc) ){
MemSetTypeFlag(pMem, MEM_Int);
}else{
- pMem->r = sqlite3VdbeRealValue(pMem);
+ pMem->u.r = sqlite3VdbeRealValue(pMem);
MemSetTypeFlag(pMem, MEM_Real);
sqlite3VdbeIntegerAffinity(pMem);
}
@@ -61320,18 +63665,80 @@ SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){
}
/*
+** Cast the datatype of the value in pMem according to the affinity
+** "aff". Casting is different from applying affinity in that a cast
+** is forced. In other words, the value is converted into the desired
+** affinity even if that results in loss of data. This routine is
+** used (for example) to implement the SQL "cast()" operator.
+*/
+SQLITE_PRIVATE void sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){
+ if( pMem->flags & MEM_Null ) return;
+ switch( aff ){
+ case SQLITE_AFF_NONE: { /* Really a cast to BLOB */
+ if( (pMem->flags & MEM_Blob)==0 ){
+ sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding);
+ assert( pMem->flags & MEM_Str || pMem->db->mallocFailed );
+ MemSetTypeFlag(pMem, MEM_Blob);
+ }else{
+ pMem->flags &= ~(MEM_TypeMask&~MEM_Blob);
+ }
+ break;
+ }
+ case SQLITE_AFF_NUMERIC: {
+ sqlite3VdbeMemNumerify(pMem);
+ break;
+ }
+ case SQLITE_AFF_INTEGER: {
+ sqlite3VdbeMemIntegerify(pMem);
+ break;
+ }
+ case SQLITE_AFF_REAL: {
+ sqlite3VdbeMemRealify(pMem);
+ break;
+ }
+ default: {
+ assert( aff==SQLITE_AFF_TEXT );
+ assert( MEM_Str==(MEM_Blob>>3) );
+ pMem->flags |= (pMem->flags&MEM_Blob)>>3;
+ sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding);
+ assert( pMem->flags & MEM_Str || pMem->db->mallocFailed );
+ pMem->flags &= ~(MEM_Int|MEM_Real|MEM_Blob|MEM_Zero);
+ break;
+ }
+ }
+}
+
+/*
+** Initialize bulk memory to be a consistent Mem object.
+**
+** The minimum amount of initialization feasible is performed.
+*/
+SQLITE_PRIVATE void sqlite3VdbeMemInit(Mem *pMem, sqlite3 *db, u16 flags){
+ assert( (flags & ~MEM_TypeMask)==0 );
+ pMem->flags = flags;
+ pMem->db = db;
+ pMem->szMalloc = 0;
+}
+
+
+/*
** Delete any previous value and set the value stored in *pMem to NULL.
+**
+** This routine calls the Mem.xDel destructor to dispose of values that
+** require the destructor. But it preserves the Mem.zMalloc memory allocation.
+** To free all resources, use sqlite3VdbeMemRelease(), which both calls this
+** routine to invoke the destructor and deallocates Mem.zMalloc.
+**
+** Use this routine to reset the Mem prior to insert a new value.
+**
+** Use sqlite3VdbeMemRelease() to complete erase the Mem prior to abandoning it.
*/
SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem *pMem){
- if( pMem->flags & MEM_Frame ){
- VdbeFrame *pFrame = pMem->u.pFrame;
- pFrame->pParent = pFrame->v->pDelFrame;
- pFrame->v->pDelFrame = pFrame;
- }
- if( pMem->flags & MEM_RowSet ){
- sqlite3RowSetClear(pMem->u.pRowSet);
+ if( VdbeMemDynamic(pMem) ){
+ vdbeMemClearExternAndSetNull(pMem);
+ }else{
+ pMem->flags = MEM_Null;
}
- MemSetTypeFlag(pMem, MEM_Null);
}
SQLITE_PRIVATE void sqlite3ValueSetNull(sqlite3_value *p){
sqlite3VdbeMemSetNull((Mem*)p);
@@ -61348,14 +63755,18 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){
if( n<0 ) n = 0;
pMem->u.nZero = n;
pMem->enc = SQLITE_UTF8;
+ pMem->z = 0;
+}
-#ifdef SQLITE_OMIT_INCRBLOB
- sqlite3VdbeMemGrow(pMem, n, 0);
- if( pMem->z ){
- pMem->n = n;
- memset(pMem->z, 0, n);
- }
-#endif
+/*
+** The pMem is known to contain content that needs to be destroyed prior
+** to a value change. So invoke the destructor, then set the value to
+** a 64-bit integer.
+*/
+static SQLITE_NOINLINE void vdbeReleaseAndSetInt64(Mem *pMem, i64 val){
+ sqlite3VdbeMemSetNull(pMem);
+ pMem->u.i = val;
+ pMem->flags = MEM_Int;
}
/*
@@ -61363,9 +63774,12 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){
** manifest type INTEGER.
*/
SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){
- sqlite3VdbeMemRelease(pMem);
- pMem->u.i = val;
- pMem->flags = MEM_Int;
+ if( VdbeMemDynamic(pMem) ){
+ vdbeReleaseAndSetInt64(pMem, val);
+ }else{
+ pMem->u.i = val;
+ pMem->flags = MEM_Int;
+ }
}
#ifndef SQLITE_OMIT_FLOATING_POINT
@@ -61374,11 +63788,9 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){
** manifest type REAL.
*/
SQLITE_PRIVATE void sqlite3VdbeMemSetDouble(Mem *pMem, double val){
- if( sqlite3IsNaN(val) ){
- sqlite3VdbeMemSetNull(pMem);
- }else{
- sqlite3VdbeMemRelease(pMem);
- pMem->r = val;
+ sqlite3VdbeMemSetNull(pMem);
+ if( !sqlite3IsNaN(val) ){
+ pMem->u.r = val;
pMem->flags = MEM_Real;
}
}
@@ -61396,10 +63808,11 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetRowSet(Mem *pMem){
pMem->zMalloc = sqlite3DbMallocRaw(db, 64);
if( db->mallocFailed ){
pMem->flags = MEM_Null;
+ pMem->szMalloc = 0;
}else{
assert( pMem->zMalloc );
- pMem->u.pRowSet = sqlite3RowSetInit(db, pMem->zMalloc,
- sqlite3DbMallocSize(db, pMem->zMalloc));
+ pMem->szMalloc = sqlite3DbMallocSize(db, pMem->zMalloc);
+ pMem->u.pRowSet = sqlite3RowSetInit(db, pMem->zMalloc, pMem->szMalloc);
assert( pMem->u.pRowSet!=0 );
pMem->flags = MEM_RowSet;
}
@@ -61423,7 +63836,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem *p){
#ifdef SQLITE_DEBUG
/*
-** This routine prepares a memory cell for modication by breaking
+** This routine prepares a memory cell for modification by breaking
** its link to a shallow copy and by marking any current shallow
** copies of this cell as invalid.
**
@@ -61456,9 +63869,9 @@ SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){
*/
SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){
assert( (pFrom->flags & MEM_RowSet)==0 );
- VdbeMemRelease(pTo);
+ assert( pTo->db==pFrom->db );
+ if( VdbeMemDynamic(pTo) ) vdbeMemClearExternAndSetNull(pTo);
memcpy(pTo, pFrom, MEMCELLSIZE);
- pTo->xDel = 0;
if( (pFrom->flags&MEM_Static)==0 ){
pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Ephem);
assert( srcType==MEM_Ephem || srcType==MEM_Static );
@@ -61473,12 +63886,11 @@ SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int sr
SQLITE_PRIVATE int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){
int rc = SQLITE_OK;
+ assert( pTo->db==pFrom->db );
assert( (pFrom->flags & MEM_RowSet)==0 );
- VdbeMemRelease(pTo);
+ if( VdbeMemDynamic(pTo) ) vdbeMemClearExternAndSetNull(pTo);
memcpy(pTo, pFrom, MEMCELLSIZE);
pTo->flags &= ~MEM_Dyn;
- pTo->xDel = 0;
-
if( pTo->flags&(MEM_Str|MEM_Blob) ){
if( 0==(pFrom->flags&MEM_Static) ){
pTo->flags |= MEM_Ephem;
@@ -61503,8 +63915,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemMove(Mem *pTo, Mem *pFrom){
sqlite3VdbeMemRelease(pTo);
memcpy(pTo, pFrom, sizeof(Mem));
pFrom->flags = MEM_Null;
- pFrom->xDel = 0;
- pFrom->zMalloc = 0;
+ pFrom->szMalloc = 0;
}
/*
@@ -61551,7 +63962,8 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
if( nByte<0 ){
assert( enc!=0 );
if( enc==SQLITE_UTF8 ){
- for(nByte=0; nByte<=iLimit && z[nByte]; nByte++){}
+ nByte = sqlite3Strlen30(z);
+ if( nByte>iLimit ) nByte = iLimit+1;
}else{
for(nByte=0; nByte<=iLimit && (z[nByte] | z[nByte+1]); nByte+=2){}
}
@@ -61570,14 +63982,17 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
if( nByte>iLimit ){
return SQLITE_TOOBIG;
}
- if( sqlite3VdbeMemGrow(pMem, nAlloc, 0) ){
+ testcase( nAlloc==0 );
+ testcase( nAlloc==31 );
+ testcase( nAlloc==32 );
+ if( sqlite3VdbeMemClearAndResize(pMem, MAX(nAlloc,32)) ){
return SQLITE_NOMEM;
}
memcpy(pMem->z, z, nAlloc);
}else if( xDel==SQLITE_DYNAMIC ){
sqlite3VdbeMemRelease(pMem);
pMem->zMalloc = pMem->z = (char *)z;
- pMem->xDel = 0;
+ pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc);
}else{
sqlite3VdbeMemRelease(pMem);
pMem->z = (char *)z;
@@ -61609,8 +64024,11 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
** key is true to get the key or false to get data. The result is written
** into the pMem element.
**
-** The pMem structure is assumed to be uninitialized. Any prior content
-** is overwritten without being freed.
+** The pMem object must have been initialized. This routine will use
+** pMem->zMalloc to hold the content from the btree, if possible. New
+** pMem->zMalloc space will be allocated if necessary. The calling routine
+** is responsible for making sure that the pMem object is eventually
+** destroyed.
**
** If this routine fails for any reason (malloc returns NULL or unable
** to read from the disk) then the pMem is left in an inconsistent state.
@@ -61627,6 +64045,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(
int rc = SQLITE_OK; /* Return code */
assert( sqlite3BtreeCursorIsValid(pCur) );
+ assert( !VdbeMemDynamic(pMem) );
/* Note: the calls to BtreeKeyFetch() and DataFetch() below assert()
** that both the BtShared and database handle mutexes are held. */
@@ -61639,54 +64058,50 @@ SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(
assert( zData!=0 );
if( offset+amt<=available ){
- sqlite3VdbeMemRelease(pMem);
pMem->z = &zData[offset];
pMem->flags = MEM_Blob|MEM_Ephem;
pMem->n = (int)amt;
- }else if( SQLITE_OK==(rc = sqlite3VdbeMemGrow(pMem, amt+2, 0)) ){
- if( key ){
- rc = sqlite3BtreeKey(pCur, offset, amt, pMem->z);
- }else{
- rc = sqlite3BtreeData(pCur, offset, amt, pMem->z);
- }
- if( rc==SQLITE_OK ){
- pMem->z[amt] = 0;
- pMem->z[amt+1] = 0;
- pMem->flags = MEM_Blob|MEM_Term;
- pMem->n = (int)amt;
- }else{
- sqlite3VdbeMemRelease(pMem);
+ }else{
+ pMem->flags = MEM_Null;
+ if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+2)) ){
+ if( key ){
+ rc = sqlite3BtreeKey(pCur, offset, amt, pMem->z);
+ }else{
+ rc = sqlite3BtreeData(pCur, offset, amt, pMem->z);
+ }
+ if( rc==SQLITE_OK ){
+ pMem->z[amt] = 0;
+ pMem->z[amt+1] = 0;
+ pMem->flags = MEM_Blob|MEM_Term;
+ pMem->n = (int)amt;
+ }else{
+ sqlite3VdbeMemRelease(pMem);
+ }
}
}
return rc;
}
-/* This function is only available internally, it is not part of the
-** external API. It works in a similar way to sqlite3_value_text(),
-** except the data returned is in the encoding specified by the second
-** parameter, which must be one of SQLITE_UTF16BE, SQLITE_UTF16LE or
-** SQLITE_UTF8.
-**
-** (2006-02-16:) The enc value can be or-ed with SQLITE_UTF16_ALIGNED.
-** If that is the case, then the result must be aligned on an even byte
-** boundary.
+/*
+** The pVal argument is known to be a value other than NULL.
+** Convert it into a string with encoding enc and return a pointer
+** to a zero-terminated version of that string.
*/
-SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
- if( !pVal ) return 0;
-
+static SQLITE_NOINLINE const void *valueToText(sqlite3_value* pVal, u8 enc){
+ assert( pVal!=0 );
assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) );
assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) );
assert( (pVal->flags & MEM_RowSet)==0 );
-
- if( pVal->flags&MEM_Null ){
- return 0;
- }
- assert( (MEM_Blob>>3) == MEM_Str );
- pVal->flags |= (pVal->flags & MEM_Blob)>>3;
- ExpandBlob(pVal);
- if( pVal->flags&MEM_Str ){
- sqlite3VdbeChangeEncoding(pVal, enc & ~SQLITE_UTF16_ALIGNED);
+ assert( (pVal->flags & (MEM_Null))==0 );
+ if( pVal->flags & (MEM_Blob|MEM_Str) ){
+ pVal->flags |= MEM_Str;
+ if( pVal->flags & MEM_Zero ){
+ sqlite3VdbeMemExpandBlob(pVal);
+ }
+ if( pVal->enc != (enc & ~SQLITE_UTF16_ALIGNED) ){
+ sqlite3VdbeChangeEncoding(pVal, enc & ~SQLITE_UTF16_ALIGNED);
+ }
if( (enc & SQLITE_UTF16_ALIGNED)!=0 && 1==(1&SQLITE_PTR_TO_INT(pVal->z)) ){
assert( (pVal->flags & (MEM_Ephem|MEM_Static))!=0 );
if( sqlite3VdbeMemMakeWriteable(pVal)!=SQLITE_OK ){
@@ -61695,8 +64110,7 @@ SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
}
sqlite3VdbeMemNulTerminate(pVal); /* IMP: R-31275-44060 */
}else{
- assert( (pVal->flags&MEM_Blob)==0 );
- sqlite3VdbeMemStringify(pVal, enc);
+ sqlite3VdbeMemStringify(pVal, enc, 0);
assert( 0==(1&SQLITE_PTR_TO_INT(pVal->z)) );
}
assert(pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) || pVal->db==0
@@ -61708,6 +64122,30 @@ SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
}
}
+/* This function is only available internally, it is not part of the
+** external API. It works in a similar way to sqlite3_value_text(),
+** except the data returned is in the encoding specified by the second
+** parameter, which must be one of SQLITE_UTF16BE, SQLITE_UTF16LE or
+** SQLITE_UTF8.
+**
+** (2006-02-16:) The enc value can be or-ed with SQLITE_UTF16_ALIGNED.
+** If that is the case, then the result must be aligned on an even byte
+** boundary.
+*/
+SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
+ if( !pVal ) return 0;
+ assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) );
+ assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) );
+ assert( (pVal->flags & MEM_RowSet)==0 );
+ if( (pVal->flags&(MEM_Str|MEM_Term))==(MEM_Str|MEM_Term) && pVal->enc==enc ){
+ return pVal->z;
+ }
+ if( pVal->flags&MEM_Null ){
+ return 0;
+ }
+ return valueToText(pVal, enc);
+}
+
/*
** Create a new sqlite3_value object.
*/
@@ -61739,7 +64177,7 @@ struct ValueNewStat4Ctx {
** Otherwise, if the second argument is non-zero, then this function is
** being called indirectly by sqlite3Stat4ProbeSetValue(). If it has not
** already been allocated, allocate the UnpackedRecord structure that
-** that function will return to its caller here. Then return a pointer
+** that function will return to its caller here. Then return a pointer to
** an sqlite3_value within the UnpackedRecord.a[] array.
*/
static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
@@ -61784,6 +64222,113 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
}
/*
+** The expression object indicated by the second argument is guaranteed
+** to be a scalar SQL function. If
+**
+** * all function arguments are SQL literals,
+** * the SQLITE_FUNC_CONSTANT function flag is set, and
+** * the SQLITE_FUNC_NEEDCOLL function flag is not set,
+**
+** then this routine attempts to invoke the SQL function. Assuming no
+** error occurs, output parameter (*ppVal) is set to point to a value
+** object containing the result before returning SQLITE_OK.
+**
+** Affinity aff is applied to the result of the function before returning.
+** If the result is a text value, the sqlite3_value object uses encoding
+** enc.
+**
+** If the conditions above are not met, this function returns SQLITE_OK
+** and sets (*ppVal) to NULL. Or, if an error occurs, (*ppVal) is set to
+** NULL and an SQLite error code returned.
+*/
+#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+static int valueFromFunction(
+ sqlite3 *db, /* The database connection */
+ Expr *p, /* The expression to evaluate */
+ u8 enc, /* Encoding to use */
+ u8 aff, /* Affinity to use */
+ sqlite3_value **ppVal, /* Write the new value here */
+ struct ValueNewStat4Ctx *pCtx /* Second argument for valueNew() */
+){
+ sqlite3_context ctx; /* Context object for function invocation */
+ sqlite3_value **apVal = 0; /* Function arguments */
+ int nVal = 0; /* Size of apVal[] array */
+ FuncDef *pFunc = 0; /* Function definition */
+ sqlite3_value *pVal = 0; /* New value */
+ int rc = SQLITE_OK; /* Return code */
+ int nName; /* Size of function name in bytes */
+ ExprList *pList = 0; /* Function arguments */
+ int i; /* Iterator variable */
+
+ assert( pCtx!=0 );
+ assert( (p->flags & EP_TokenOnly)==0 );
+ pList = p->x.pList;
+ if( pList ) nVal = pList->nExpr;
+ nName = sqlite3Strlen30(p->u.zToken);
+ pFunc = sqlite3FindFunction(db, p->u.zToken, nName, nVal, enc, 0);
+ assert( pFunc );
+ if( (pFunc->funcFlags & SQLITE_FUNC_CONSTANT)==0
+ || (pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)
+ ){
+ return SQLITE_OK;
+ }
+
+ if( pList ){
+ apVal = (sqlite3_value**)sqlite3DbMallocZero(db, sizeof(apVal[0]) * nVal);
+ if( apVal==0 ){
+ rc = SQLITE_NOMEM;
+ goto value_from_function_out;
+ }
+ for(i=0; i<nVal; i++){
+ rc = sqlite3ValueFromExpr(db, pList->a[i].pExpr, enc, aff, &apVal[i]);
+ if( apVal[i]==0 || rc!=SQLITE_OK ) goto value_from_function_out;
+ }
+ }
+
+ pVal = valueNew(db, pCtx);
+ if( pVal==0 ){
+ rc = SQLITE_NOMEM;
+ goto value_from_function_out;
+ }
+
+ assert( pCtx->pParse->rc==SQLITE_OK );
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.pOut = pVal;
+ ctx.pFunc = pFunc;
+ pFunc->xFunc(&ctx, nVal, apVal);
+ if( ctx.isError ){
+ rc = ctx.isError;
+ sqlite3ErrorMsg(pCtx->pParse, "%s", sqlite3_value_text(pVal));
+ }else{
+ sqlite3ValueApplyAffinity(pVal, aff, SQLITE_UTF8);
+ assert( rc==SQLITE_OK );
+ rc = sqlite3VdbeChangeEncoding(pVal, enc);
+ if( rc==SQLITE_OK && sqlite3VdbeMemTooBig(pVal) ){
+ rc = SQLITE_TOOBIG;
+ pCtx->pParse->nErr++;
+ }
+ }
+ pCtx->pParse->rc = rc;
+
+ value_from_function_out:
+ if( rc!=SQLITE_OK ){
+ pVal = 0;
+ }
+ if( apVal ){
+ for(i=0; i<nVal; i++){
+ sqlite3ValueFree(apVal[i]);
+ }
+ sqlite3DbFree(db, apVal);
+ }
+
+ *ppVal = pVal;
+ return rc;
+}
+#else
+# define valueFromFunction(a,b,c,d,e,f) SQLITE_OK
+#endif /* defined(SQLITE_ENABLE_STAT3_OR_STAT4) */
+
+/*
** Extract a value from the supplied expression in the manner described
** above sqlite3ValueFromExpr(). Allocate the sqlite3_value object
** using valueNew().
@@ -61812,9 +64357,26 @@ static int valueFromExpr(
*ppVal = 0;
return SQLITE_OK;
}
- op = pExpr->op;
+ while( (op = pExpr->op)==TK_UPLUS ) pExpr = pExpr->pLeft;
if( NEVER(op==TK_REGISTER) ) op = pExpr->op2;
+ /* Compressed expressions only appear when parsing the DEFAULT clause
+ ** on a table column definition, and hence only when pCtx==0. This
+ ** check ensures that an EP_TokenOnly expression is never passed down
+ ** into valueFromFunction(). */
+ assert( (pExpr->flags & EP_TokenOnly)==0 || pCtx==0 );
+
+ if( op==TK_CAST ){
+ u8 aff = sqlite3AffinityType(pExpr->u.zToken,0);
+ rc = valueFromExpr(db, pExpr->pLeft, enc, aff, ppVal, pCtx);
+ testcase( rc!=SQLITE_OK );
+ if( *ppVal ){
+ sqlite3VdbeMemCast(*ppVal, aff, SQLITE_UTF8);
+ sqlite3ValueApplyAffinity(*ppVal, affinity, SQLITE_UTF8);
+ }
+ return rc;
+ }
+
/* Handle negative integers in a single step. This is needed in the
** case when the value is -9223372036854775808.
*/
@@ -61851,14 +64413,14 @@ static int valueFromExpr(
&& pVal!=0
){
sqlite3VdbeMemNumerify(pVal);
- if( pVal->u.i==SMALLEST_INT64 ){
- pVal->flags &= ~MEM_Int;
- pVal->flags |= MEM_Real;
- pVal->r = (double)SMALLEST_INT64;
+ if( pVal->flags & MEM_Real ){
+ pVal->u.r = -pVal->u.r;
+ }else if( pVal->u.i==SMALLEST_INT64 ){
+ pVal->u.r = -(double)SMALLEST_INT64;
+ MemSetTypeFlag(pVal, MEM_Real);
}else{
pVal->u.i = -pVal->u.i;
}
- pVal->r = -pVal->r;
sqlite3ValueApplyAffinity(pVal, affinity, enc);
}
}else if( op==TK_NULL ){
@@ -61880,6 +64442,12 @@ static int valueFromExpr(
}
#endif
+#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+ else if( op==TK_FUNCTION && pCtx!=0 ){
+ rc = valueFromFunction(db, pExpr, enc, affinity, &pVal, pCtx);
+ }
+#endif
+
*ppVal = pVal;
return rc;
@@ -61949,7 +64517,7 @@ static void recordFunc(
sqlite3_result_error_nomem(context);
}else{
aRet[0] = nSerial+1;
- sqlite3PutVarint(&aRet[1], iSerial);
+ putVarint32(&aRet[1], iSerial);
sqlite3VdbeSerialPut(&aRet[1+nSerial], argv[0], iSerial);
sqlite3_result_blob(context, aRet, nRet, SQLITE_TRANSIENT);
sqlite3DbFree(db, aRet);
@@ -62166,7 +64734,7 @@ SQLITE_PRIVATE void sqlite3Stat4ProbeFree(UnpackedRecord *pRec){
Mem *aMem = pRec->aMem;
sqlite3 *db = aMem[0].db;
for(i=0; i<nCol; i++){
- sqlite3DbFree(db, aMem[i].zMalloc);
+ sqlite3VdbeMemRelease(&aMem[i]);
}
sqlite3KeyInfoUnref(pRec->pKeyInfo);
sqlite3DbFree(db, pRec);
@@ -62226,9 +64794,7 @@ SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){
**
*************************************************************************
** This file contains code used for creating, destroying, and populating
-** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.) Prior
-** to version 2.8.7, all this code was combined into the vdbe.c source file.
-** But that file was getting too big so this subroutines were split out.
+** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.)
*/
/*
@@ -62271,7 +64837,7 @@ SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepa
/*
** Return the SQL associated with a prepared statement
*/
-SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt){
+SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt){
Vdbe *p = (Vdbe *)pStmt;
return (p && p->isPrepareV2) ? p->zSql : 0;
}
@@ -62612,6 +65178,7 @@ static Op *opIterNext(VdbeOpIter *p){
*/
SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
int hasAbort = 0;
+ int hasFkCounter = 0;
Op *pOp;
VdbeOpIter sIter;
memset(&sIter, 0, sizeof(sIter));
@@ -62620,15 +65187,17 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
while( (pOp = opIterNext(&sIter))!=0 ){
int opcode = pOp->opcode;
if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename
-#ifndef SQLITE_OMIT_FOREIGN_KEY
- || (opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1)
-#endif
|| ((opcode==OP_Halt || opcode==OP_HaltIfNull)
&& ((pOp->p1&0xff)==SQLITE_CONSTRAINT && pOp->p2==OE_Abort))
){
hasAbort = 1;
break;
}
+#ifndef SQLITE_OMIT_FOREIGN_KEY
+ if( opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1 ){
+ hasFkCounter = 1;
+ }
+#endif
}
sqlite3DbFree(v->db, sIter.apSub);
@@ -62637,7 +65206,7 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
** through all opcodes and hasAbort may be set incorrectly. Return
** true for this case to prevent the assert() in the callers frame
** from failing. */
- return ( v->db->mallocFailed || hasAbort==mayAbort );
+ return ( v->db->mallocFailed || hasAbort==mayAbort || hasFkCounter );
}
#endif /* SQLITE_DEBUG - the sqlite3AssertMayAbort() function */
@@ -62813,6 +65382,34 @@ SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp,
return addr;
}
+#if defined(SQLITE_ENABLE_STMT_SCANSTATUS)
+/*
+** Add an entry to the array of counters managed by sqlite3_stmt_scanstatus().
+*/
+SQLITE_PRIVATE void sqlite3VdbeScanStatus(
+ Vdbe *p, /* VM to add scanstatus() to */
+ int addrExplain, /* Address of OP_Explain (or 0) */
+ int addrLoop, /* Address of loop counter */
+ int addrVisit, /* Address of rows visited counter */
+ LogEst nEst, /* Estimated number of output rows */
+ const char *zName /* Name of table or index being scanned */
+){
+ int nByte = (p->nScan+1) * sizeof(ScanStatus);
+ ScanStatus *aNew;
+ aNew = (ScanStatus*)sqlite3DbRealloc(p->db, p->aScan, nByte);
+ if( aNew ){
+ ScanStatus *pNew = &aNew[p->nScan++];
+ pNew->addrExplain = addrExplain;
+ pNew->addrLoop = addrLoop;
+ pNew->addrVisit = addrVisit;
+ pNew->nEst = nEst;
+ pNew->zName = sqlite3DbStrDup(p->db, zName);
+ p->aScan = aNew;
+ }
+}
+#endif
+
+
/*
** Change the value of the P1 operand for a specific instruction.
** This routine is useful when a large program is loaded from a
@@ -62912,7 +65509,7 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
sqlite3ValueFree((sqlite3_value*)p4);
}else{
Mem *p = (Mem*)p4;
- sqlite3DbFree(db, p->zMalloc);
+ if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc);
sqlite3DbFree(db, p);
}
break;
@@ -62968,7 +65565,8 @@ SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe *p, int addr){
}
/*
-** Remove the last opcode inserted
+** If the last opcode is "op" and it is not a jump destination,
+** then remove it. Return true if and only if an opcode was removed.
*/
SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){
if( (p->nOp-1)>(p->pParse->iFixedOp) && p->aOp[p->nOp-1].opcode==op ){
@@ -63109,7 +65707,7 @@ SQLITE_PRIVATE void sqlite3VdbeSetLineNumber(Vdbe *v, int iLine){
** routine, then a pointer to a dummy VdbeOp will be returned. That opcode
** is readable but not writable, though it is cast to a writable value.
** The return of a dummy opcode allows the call to continue functioning
-** after a OOM fault without having to check to see if the return from
+** after an OOM fault without having to check to see if the return from
** this routine is a valid pointer. But because the dummy.opcode is 0,
** dummy will never be written to. This is verified by code inspection and
** by running with Valgrind.
@@ -63290,7 +65888,7 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
}else if( pMem->flags & MEM_Int ){
sqlite3_snprintf(nTemp, zTemp, "%lld", pMem->u.i);
}else if( pMem->flags & MEM_Real ){
- sqlite3_snprintf(nTemp, zTemp, "%.16g", pMem->r);
+ sqlite3_snprintf(nTemp, zTemp, "%.16g", pMem->u.r);
}else if( pMem->flags & MEM_Null ){
sqlite3_snprintf(nTemp, zTemp, "NULL");
}else{
@@ -63302,7 +65900,7 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
#ifndef SQLITE_OMIT_VIRTUALTABLE
case P4_VTAB: {
sqlite3_vtab *pVtab = pOp->p4.pVtab->pVtab;
- sqlite3_snprintf(nTemp, zTemp, "vtab:%p:%p", pVtab, pVtab->pModule);
+ sqlite3_snprintf(nTemp, zTemp, "vtab:%p", pVtab);
break;
}
#endif
@@ -63440,16 +66038,16 @@ SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){
*/
static void releaseMemArray(Mem *p, int N){
if( p && N ){
- Mem *pEnd;
+ Mem *pEnd = &p[N];
sqlite3 *db = p->db;
u8 malloc_failed = db->mallocFailed;
if( db->pnBytesFreed ){
- for(pEnd=&p[N]; p<pEnd; p++){
- sqlite3DbFree(db, p->zMalloc);
- }
+ do{
+ if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc);
+ }while( (++p)<pEnd );
return;
}
- for(pEnd=&p[N]; p<pEnd; p++){
+ do{
assert( (&p[1])==pEnd || p[0].db==p[1].db );
assert( sqlite3VdbeCheckMemInvariants(p) );
@@ -63471,13 +66069,13 @@ static void releaseMemArray(Mem *p, int N){
testcase( p->flags & MEM_RowSet );
if( p->flags&(MEM_Agg|MEM_Dyn|MEM_Frame|MEM_RowSet) ){
sqlite3VdbeMemRelease(p);
- }else if( p->zMalloc ){
+ }else if( p->szMalloc ){
sqlite3DbFree(db, p->zMalloc);
- p->zMalloc = 0;
+ p->szMalloc = 0;
}
p->flags = MEM_Undefined;
- }
+ }while( (++p)<pEnd );
db->mallocFailed = malloc_failed;
}
}
@@ -63640,7 +66238,7 @@ SQLITE_PRIVATE int sqlite3VdbeList(
pMem->u.i = pOp->p3; /* P3 */
pMem++;
- if( sqlite3VdbeMemGrow(pMem, 32, 0) ){ /* P4 */
+ if( sqlite3VdbeMemClearAndResize(pMem, 32) ){ /* P4 */
assert( p->db->mallocFailed );
return SQLITE_ERROR;
}
@@ -63656,7 +66254,7 @@ SQLITE_PRIVATE int sqlite3VdbeList(
pMem++;
if( p->explain==1 ){
- if( sqlite3VdbeMemGrow(pMem, 4, 0) ){
+ if( sqlite3VdbeMemClearAndResize(pMem, 4) ){
assert( p->db->mallocFailed );
return SQLITE_ERROR;
}
@@ -63667,7 +66265,7 @@ SQLITE_PRIVATE int sqlite3VdbeList(
pMem++;
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
- if( sqlite3VdbeMemGrow(pMem, 500, 0) ){
+ if( sqlite3VdbeMemClearAndResize(pMem, 500) ){
assert( p->db->mallocFailed );
return SQLITE_ERROR;
}
@@ -63820,13 +66418,13 @@ SQLITE_PRIVATE void sqlite3VdbeRewind(Vdbe *p){
/*
** Prepare a virtual machine for execution for the first time after
** creating the virtual machine. This involves things such
-** as allocating stack space and initializing the program counter.
+** as allocating registers and initializing the program counter.
** After the VDBE has be prepped, it can be executed by one or more
** calls to sqlite3VdbeExec().
**
-** This function may be called exact once on a each virtual machine.
+** This function may be called exactly once on each virtual machine.
** After this routine is called the VM has been "packaged" and is ready
-** to run. After this routine is called, futher calls to
+** to run. After this routine is called, further calls to
** sqlite3VdbeAddOp() functions are prohibited. This routine disconnects
** the Vdbe from the Parse object that helped generate it so that the
** the Vdbe becomes an independent entity and the Parse object can be
@@ -63910,6 +66508,9 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
p->apCsr = allocSpace(p->apCsr, nCursor*sizeof(VdbeCursor*),
&zCsr, zEnd, &nByte);
p->aOnceFlag = allocSpace(p->aOnceFlag, nOnce, &zCsr, zEnd, &nByte);
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ p->anExec = allocSpace(p->anExec, p->nOp*sizeof(i64), &zCsr, zEnd, &nByte);
+#endif
if( nByte ){
p->pFree = sqlite3DbMallocZero(db, nByte);
}
@@ -63926,7 +66527,7 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
p->aVar[n].db = db;
}
}
- if( p->azVar ){
+ if( p->azVar && pParse->nzVar>0 ){
p->nzVar = pParse->nzVar;
memcpy(p->azVar, pParse->azVar, p->nzVar*sizeof(p->azVar[0]));
memset(pParse->azVar, 0, pParse->nzVar*sizeof(pParse->azVar[0]));
@@ -63960,23 +66561,43 @@ SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
sqlite3BtreeCloseCursor(pCx->pCursor);
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
- if( pCx->pVtabCursor ){
+ else if( pCx->pVtabCursor ){
sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor;
const sqlite3_module *pModule = pVtabCursor->pVtab->pModule;
- p->inVtabMethod = 1;
+ assert( pVtabCursor->pVtab->nRef>0 );
+ pVtabCursor->pVtab->nRef--;
pModule->xClose(pVtabCursor);
- p->inVtabMethod = 0;
}
#endif
}
/*
+** Close all cursors in the current frame.
+*/
+static void closeCursorsInFrame(Vdbe *p){
+ if( p->apCsr ){
+ int i;
+ for(i=0; i<p->nCursor; i++){
+ VdbeCursor *pC = p->apCsr[i];
+ if( pC ){
+ sqlite3VdbeFreeCursor(p, pC);
+ p->apCsr[i] = 0;
+ }
+ }
+ }
+}
+
+/*
** Copy the values stored in the VdbeFrame structure to its Vdbe. This
** is used, for example, when a trigger sub-program is halted to restore
** control to the main program.
*/
SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){
Vdbe *v = pFrame->v;
+ closeCursorsInFrame(v);
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ v->anExec = pFrame->anExec;
+#endif
v->aOnceFlag = pFrame->aOnceFlag;
v->nOnceFlag = pFrame->nOnceFlag;
v->aOp = pFrame->aOp;
@@ -63987,6 +66608,7 @@ SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){
v->nCursor = pFrame->nCursor;
v->db->lastRowid = pFrame->lastRowid;
v->nChange = pFrame->nChange;
+ v->db->nChange = pFrame->nDbChange;
return pFrame->pc;
}
@@ -64003,20 +66625,11 @@ static void closeAllCursors(Vdbe *p){
VdbeFrame *pFrame;
for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent);
sqlite3VdbeFrameRestore(pFrame);
+ p->pFrame = 0;
+ p->nFrame = 0;
}
- p->pFrame = 0;
- p->nFrame = 0;
-
- if( p->apCsr ){
- int i;
- for(i=0; i<p->nCursor; i++){
- VdbeCursor *pC = p->apCsr[i];
- if( pC ){
- sqlite3VdbeFreeCursor(p, pC);
- p->apCsr[i] = 0;
- }
- }
- }
+ assert( p->nFrame==0 );
+ closeCursorsInFrame(p);
if( p->aMem ){
releaseMemArray(&p->aMem[1], p->nMem);
}
@@ -64027,16 +66640,12 @@ static void closeAllCursors(Vdbe *p){
}
/* Delete any auxdata allocations made by the VM */
- sqlite3VdbeDeleteAuxData(p, -1, 0);
+ if( p->pAuxData ) sqlite3VdbeDeleteAuxData(p, -1, 0);
assert( p->pAuxData==0 );
}
/*
-** Clean up the VM after execution.
-**
-** This routine will automatically close any cursors, lists, and/or
-** sorters that were left open. It also deletes the values of
-** variables in the aVar[] array.
+** Clean up the VM after a single run.
*/
static void Cleanup(Vdbe *p){
sqlite3 *db = p->db;
@@ -64204,7 +66813,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
/* The complex case - There is a multi-file write-transaction active.
** This requires a master journal file to ensure the transaction is
- ** committed atomicly.
+ ** committed atomically.
*/
#ifndef SQLITE_OMIT_DISKIO
else{
@@ -64323,7 +66932,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
** doing this the directory is synced again before any individual
** transaction files are deleted.
*/
- rc = sqlite3OsDelete(pVfs, zMaster, 1);
+ rc = sqlite3OsDelete(pVfs, zMaster, needSync);
sqlite3DbFree(db, zMaster);
zMaster = 0;
if( rc ){
@@ -64557,6 +67166,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
sqlite3CloseSavepoints(db);
db->autoCommit = 1;
+ p->nChange = 0;
}
}
}
@@ -64597,6 +67207,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
}else if( rc!=SQLITE_OK ){
p->rc = rc;
sqlite3RollbackAll(db, SQLITE_OK);
+ p->nChange = 0;
}else{
db->nDeferredCons = 0;
db->nDeferredImmCons = 0;
@@ -64605,6 +67216,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
}
}else{
sqlite3RollbackAll(db, SQLITE_OK);
+ p->nChange = 0;
}
db->nStatement = 0;
}else if( eStatementOp==0 ){
@@ -64616,6 +67228,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
sqlite3CloseSavepoints(db);
db->autoCommit = 1;
+ p->nChange = 0;
}
}
@@ -64636,6 +67249,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
sqlite3CloseSavepoints(db);
db->autoCommit = 1;
+ p->nChange = 0;
}
}
@@ -64711,7 +67325,7 @@ SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p){
db->mallocFailed = mallocFailed;
db->errCode = rc;
}else{
- sqlite3Error(db, rc, 0);
+ sqlite3Error(db, rc);
}
return rc;
}
@@ -64774,7 +67388,7 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){
** to sqlite3_step(). For consistency (since sqlite3_step() was
** called), set the database error in this case as well.
*/
- sqlite3Error(db, p->rc, p->zErrMsg ? "%s" : 0, p->zErrMsg);
+ sqlite3ErrorWithMsg(db, p->rc, p->zErrMsg ? "%s" : 0, p->zErrMsg);
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = 0;
}
@@ -64852,7 +67466,7 @@ SQLITE_PRIVATE int sqlite3VdbeFinalize(Vdbe *p){
** from left to right), or
**
** * the corresponding bit in argument mask is clear (where the first
-** function parameter corrsponds to bit 0 etc.).
+** function parameter corresponds to bit 0 etc.).
*/
SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(Vdbe *pVdbe, int iOp, int mask){
AuxData **pp = &pVdbe->pAuxData;
@@ -64897,9 +67511,11 @@ SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
sqlite3DbFree(db, p->aColName);
sqlite3DbFree(db, p->zSql);
sqlite3DbFree(db, p->pFree);
-#if defined(SQLITE_ENABLE_TREE_EXPLAIN)
- sqlite3DbFree(db, p->zExplain);
- sqlite3DbFree(db, p->pExplain);
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ for(i=0; i<p->nScan; i++){
+ sqlite3DbFree(db, p->aScan[i].zName);
+ }
+ sqlite3DbFree(db, p->aScan);
#endif
}
@@ -64928,6 +67544,57 @@ SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe *p){
}
/*
+** The cursor "p" has a pending seek operation that has not yet been
+** carried out. Seek the cursor now. If an error occurs, return
+** the appropriate error code.
+*/
+static int SQLITE_NOINLINE handleDeferredMoveto(VdbeCursor *p){
+ int res, rc;
+#ifdef SQLITE_TEST
+ extern int sqlite3_search_count;
+#endif
+ assert( p->deferredMoveto );
+ assert( p->isTable );
+ rc = sqlite3BtreeMovetoUnpacked(p->pCursor, 0, p->movetoTarget, 0, &res);
+ if( rc ) return rc;
+ if( res!=0 ) return SQLITE_CORRUPT_BKPT;
+#ifdef SQLITE_TEST
+ sqlite3_search_count++;
+#endif
+ p->deferredMoveto = 0;
+ p->cacheStatus = CACHE_STALE;
+ return SQLITE_OK;
+}
+
+/*
+** Something has moved cursor "p" out of place. Maybe the row it was
+** pointed to was deleted out from under it. Or maybe the btree was
+** rebalanced. Whatever the cause, try to restore "p" to the place it
+** is supposed to be pointing. If the row was deleted out from under the
+** cursor, set the cursor to point to a NULL row.
+*/
+static int SQLITE_NOINLINE handleMovedCursor(VdbeCursor *p){
+ int isDifferentRow, rc;
+ assert( p->pCursor!=0 );
+ assert( sqlite3BtreeCursorHasMoved(p->pCursor) );
+ rc = sqlite3BtreeCursorRestore(p->pCursor, &isDifferentRow);
+ p->cacheStatus = CACHE_STALE;
+ if( isDifferentRow ) p->nullRow = 1;
+ return rc;
+}
+
+/*
+** Check to ensure that the cursor is valid. Restore the cursor
+** if need be. Return any I/O error from the restore operation.
+*/
+SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor *p){
+ if( sqlite3BtreeCursorHasMoved(p->pCursor) ){
+ return handleMovedCursor(p);
+ }
+ return SQLITE_OK;
+}
+
+/*
** Make sure the cursor p is ready to read or write the row to which it
** was last positioned. Return an error code if an OOM fault or I/O error
** prevents us from positioning the cursor to its correct position.
@@ -64942,29 +67609,10 @@ SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe *p){
*/
SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor *p){
if( p->deferredMoveto ){
- int res, rc;
-#ifdef SQLITE_TEST
- extern int sqlite3_search_count;
-#endif
- assert( p->isTable );
- rc = sqlite3BtreeMovetoUnpacked(p->pCursor, 0, p->movetoTarget, 0, &res);
- if( rc ) return rc;
- p->lastRowid = p->movetoTarget;
- if( res!=0 ) return SQLITE_CORRUPT_BKPT;
- p->rowidIsValid = 1;
-#ifdef SQLITE_TEST
- sqlite3_search_count++;
-#endif
- p->deferredMoveto = 0;
- p->cacheStatus = CACHE_STALE;
- }else if( p->pCursor ){
- int hasMoved;
- int rc = sqlite3BtreeCursorHasMoved(p->pCursor, &hasMoved);
- if( rc ) return rc;
- if( hasMoved ){
- p->cacheStatus = CACHE_STALE;
- if( hasMoved==2 ) p->nullRow = 1;
- }
+ return handleDeferredMoveto(p);
+ }
+ if( p->pCursor && sqlite3BtreeCursorHasMoved(p->pCursor) ){
+ return handleMovedCursor(p);
}
return SQLITE_OK;
}
@@ -65027,9 +67675,7 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
i64 i = pMem->u.i;
u64 u;
if( i<0 ){
- if( i<(-MAX_6BYTE) ) return 6;
- /* Previous test prevents: u = -(-9223372036854775808) */
- u = -i;
+ u = ~i;
}else{
u = i;
}
@@ -65140,17 +67786,18 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(u8 *buf, Mem *pMem, u32 serial_type){
u64 v;
u32 i;
if( serial_type==7 ){
- assert( sizeof(v)==sizeof(pMem->r) );
- memcpy(&v, &pMem->r, sizeof(v));
+ assert( sizeof(v)==sizeof(pMem->u.r) );
+ memcpy(&v, &pMem->u.r, sizeof(v));
swapMixedEndianFloat(v);
}else{
v = pMem->u.i;
}
len = i = sqlite3VdbeSerialTypeLen(serial_type);
- while( i-- ){
- buf[i] = (u8)(v&0xFF);
+ assert( i>0 );
+ do{
+ buf[--i] = (u8)(v&0xFF);
v >>= 8;
- }
+ }while( i );
return len;
}
@@ -65174,51 +67821,101 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(u8 *buf, Mem *pMem, u32 serial_type){
#define TWO_BYTE_INT(x) (256*(i8)((x)[0])|(x)[1])
#define THREE_BYTE_INT(x) (65536*(i8)((x)[0])|((x)[1]<<8)|(x)[2])
#define FOUR_BYTE_UINT(x) (((u32)(x)[0]<<24)|((x)[1]<<16)|((x)[2]<<8)|(x)[3])
+#define FOUR_BYTE_INT(x) (16777216*(i8)((x)[0])|((x)[1]<<16)|((x)[2]<<8)|(x)[3])
/*
** Deserialize the data blob pointed to by buf as serial type serial_type
** and store the result in pMem. Return the number of bytes read.
+**
+** This function is implemented as two separate routines for performance.
+** The few cases that require local variables are broken out into a separate
+** routine so that in most cases the overhead of moving the stack pointer
+** is avoided.
*/
+static u32 SQLITE_NOINLINE serialGet(
+ const unsigned char *buf, /* Buffer to deserialize from */
+ u32 serial_type, /* Serial type to deserialize */
+ Mem *pMem /* Memory cell to write value into */
+){
+ u64 x = FOUR_BYTE_UINT(buf);
+ u32 y = FOUR_BYTE_UINT(buf+4);
+ x = (x<<32) + y;
+ if( serial_type==6 ){
+ /* EVIDENCE-OF: R-29851-52272 Value is a big-endian 64-bit
+ ** twos-complement integer. */
+ pMem->u.i = *(i64*)&x;
+ pMem->flags = MEM_Int;
+ testcase( pMem->u.i<0 );
+ }else{
+ /* EVIDENCE-OF: R-57343-49114 Value is a big-endian IEEE 754-2008 64-bit
+ ** floating point number. */
+#if !defined(NDEBUG) && !defined(SQLITE_OMIT_FLOATING_POINT)
+ /* Verify that integers and floating point values use the same
+ ** byte order. Or, that if SQLITE_MIXED_ENDIAN_64BIT_FLOAT is
+ ** defined that 64-bit floating point values really are mixed
+ ** endian.
+ */
+ static const u64 t1 = ((u64)0x3ff00000)<<32;
+ static const double r1 = 1.0;
+ u64 t2 = t1;
+ swapMixedEndianFloat(t2);
+ assert( sizeof(r1)==sizeof(t2) && memcmp(&r1, &t2, sizeof(r1))==0 );
+#endif
+ assert( sizeof(x)==8 && sizeof(pMem->u.r)==8 );
+ swapMixedEndianFloat(x);
+ memcpy(&pMem->u.r, &x, sizeof(x));
+ pMem->flags = sqlite3IsNaN(pMem->u.r) ? MEM_Null : MEM_Real;
+ }
+ return 8;
+}
SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(
const unsigned char *buf, /* Buffer to deserialize from */
u32 serial_type, /* Serial type to deserialize */
Mem *pMem /* Memory cell to write value into */
){
- u64 x;
- u32 y;
switch( serial_type ){
case 10: /* Reserved for future use */
case 11: /* Reserved for future use */
- case 0: { /* NULL */
+ case 0: { /* Null */
+ /* EVIDENCE-OF: R-24078-09375 Value is a NULL. */
pMem->flags = MEM_Null;
break;
}
- case 1: { /* 1-byte signed integer */
+ case 1: {
+ /* EVIDENCE-OF: R-44885-25196 Value is an 8-bit twos-complement
+ ** integer. */
pMem->u.i = ONE_BYTE_INT(buf);
pMem->flags = MEM_Int;
testcase( pMem->u.i<0 );
return 1;
}
case 2: { /* 2-byte signed integer */
+ /* EVIDENCE-OF: R-49794-35026 Value is a big-endian 16-bit
+ ** twos-complement integer. */
pMem->u.i = TWO_BYTE_INT(buf);
pMem->flags = MEM_Int;
testcase( pMem->u.i<0 );
return 2;
}
case 3: { /* 3-byte signed integer */
+ /* EVIDENCE-OF: R-37839-54301 Value is a big-endian 24-bit
+ ** twos-complement integer. */
pMem->u.i = THREE_BYTE_INT(buf);
pMem->flags = MEM_Int;
testcase( pMem->u.i<0 );
return 3;
}
case 4: { /* 4-byte signed integer */
- y = FOUR_BYTE_UINT(buf);
- pMem->u.i = (i64)*(int*)&y;
+ /* EVIDENCE-OF: R-01849-26079 Value is a big-endian 32-bit
+ ** twos-complement integer. */
+ pMem->u.i = FOUR_BYTE_INT(buf);
pMem->flags = MEM_Int;
testcase( pMem->u.i<0 );
return 4;
}
case 5: { /* 6-byte signed integer */
+ /* EVIDENCE-OF: R-50385-09674 Value is a big-endian 48-bit
+ ** twos-complement integer. */
pMem->u.i = FOUR_BYTE_UINT(buf+2) + (((i64)1)<<32)*TWO_BYTE_INT(buf);
pMem->flags = MEM_Int;
testcase( pMem->u.i<0 );
@@ -65226,52 +67923,32 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(
}
case 6: /* 8-byte signed integer */
case 7: { /* IEEE floating point */
-#if !defined(NDEBUG) && !defined(SQLITE_OMIT_FLOATING_POINT)
- /* Verify that integers and floating point values use the same
- ** byte order. Or, that if SQLITE_MIXED_ENDIAN_64BIT_FLOAT is
- ** defined that 64-bit floating point values really are mixed
- ** endian.
- */
- static const u64 t1 = ((u64)0x3ff00000)<<32;
- static const double r1 = 1.0;
- u64 t2 = t1;
- swapMixedEndianFloat(t2);
- assert( sizeof(r1)==sizeof(t2) && memcmp(&r1, &t2, sizeof(r1))==0 );
-#endif
- x = FOUR_BYTE_UINT(buf);
- y = FOUR_BYTE_UINT(buf+4);
- x = (x<<32) | y;
- if( serial_type==6 ){
- pMem->u.i = *(i64*)&x;
- pMem->flags = MEM_Int;
- testcase( pMem->u.i<0 );
- }else{
- assert( sizeof(x)==8 && sizeof(pMem->r)==8 );
- swapMixedEndianFloat(x);
- memcpy(&pMem->r, &x, sizeof(x));
- pMem->flags = sqlite3IsNaN(pMem->r) ? MEM_Null : MEM_Real;
- }
- return 8;
+ /* These use local variables, so do them in a separate routine
+ ** to avoid having to move the frame pointer in the common case */
+ return serialGet(buf,serial_type,pMem);
}
case 8: /* Integer 0 */
case 9: { /* Integer 1 */
+ /* EVIDENCE-OF: R-12976-22893 Value is the integer 0. */
+ /* EVIDENCE-OF: R-18143-12121 Value is the integer 1. */
pMem->u.i = serial_type-8;
pMem->flags = MEM_Int;
return 0;
}
default: {
+ /* EVIDENCE-OF: R-14606-31564 Value is a BLOB that is (N-12)/2 bytes in
+ ** length.
+ ** EVIDENCE-OF: R-28401-00140 Value is a string in the text encoding and
+ ** (N-13)/2 bytes in length. */
static const u16 aFlag[] = { MEM_Blob|MEM_Ephem, MEM_Str|MEM_Ephem };
- u32 len = (serial_type-12)/2;
pMem->z = (char *)buf;
- pMem->n = len;
- pMem->xDel = 0;
+ pMem->n = (serial_type-12)/2;
pMem->flags = aFlag[serial_type&1];
- return len;
+ return pMem->n;
}
}
return 0;
}
-
/*
** This routine is used to allocate sufficient space for an UnpackedRecord
** structure large enough to be used with sqlite3VdbeRecordUnpack() if
@@ -65341,17 +68018,17 @@ SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(
idx = getVarint32(aKey, szHdr);
d = szHdr;
u = 0;
- while( idx<szHdr && u<p->nField && d<=nKey ){
+ while( idx<szHdr && d<=nKey ){
u32 serial_type;
idx += getVarint32(&aKey[idx], serial_type);
pMem->enc = pKeyInfo->enc;
pMem->db = pKeyInfo->db;
/* pMem->flags = 0; // sqlite3VdbeSerialGet() will set this for us */
- pMem->zMalloc = 0;
+ pMem->szMalloc = 0;
d += sqlite3VdbeSerialGet(&aKey[d], serial_type, pMem);
pMem++;
- u++;
+ if( (++u)>=p->nField ) break;
}
assert( u<=pKeyInfo->nField + 1 );
p->nField = u;
@@ -65365,10 +68042,14 @@ SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(
** sqlite3VdbeSerialGet() and sqlite3MemCompare() functions. It is used
** in assert() statements to ensure that the optimized code in
** sqlite3VdbeRecordCompare() returns results with these two primitives.
+**
+** Return true if the result of comparison is equivalent to desiredResult.
+** Return false if there is a disagreement.
*/
static int vdbeRecordCompareDebug(
int nKey1, const void *pKey1, /* Left key */
- const UnpackedRecord *pPKey2 /* Right key */
+ const UnpackedRecord *pPKey2, /* Right key */
+ int desiredResult /* Correct answer */
){
u32 d1; /* Offset into aKey[] of next data element */
u32 idx1; /* Offset into aKey[] of next header element */
@@ -65380,10 +68061,11 @@ static int vdbeRecordCompareDebug(
Mem mem1;
pKeyInfo = pPKey2->pKeyInfo;
+ if( pKeyInfo->db==0 ) return 1;
mem1.enc = pKeyInfo->enc;
mem1.db = pKeyInfo->db;
/* mem1.flags = 0; // Will be initialized by sqlite3VdbeSerialGet() */
- VVA_ONLY( mem1.zMalloc = 0; ) /* Only needed by assert() statements */
+ VVA_ONLY( mem1.szMalloc = 0; ) /* Only needed by assert() statements */
/* Compilers may complain that mem1.u.i is potentially uninitialized.
** We could initialize it, as shown here, to silence those complaints.
@@ -65426,11 +68108,11 @@ static int vdbeRecordCompareDebug(
*/
rc = sqlite3MemCompare(&mem1, &pPKey2->aMem[i], pKeyInfo->aColl[i]);
if( rc!=0 ){
- assert( mem1.zMalloc==0 ); /* See comment below */
+ assert( mem1.szMalloc==0 ); /* See comment below */
if( pKeyInfo->aSortOrder[i] ){
rc = -rc; /* Invert the result for DESC sort order. */
}
- return rc;
+ goto debugCompareEnd;
}
i++;
}while( idx1<szHdr1 && i<pPKey2->nField );
@@ -65439,13 +68121,57 @@ static int vdbeRecordCompareDebug(
** the following assert(). If the assert() fails, it indicates a
** memory leak and a need to call sqlite3VdbeMemRelease(&mem1).
*/
- assert( mem1.zMalloc==0 );
+ assert( mem1.szMalloc==0 );
/* rc==0 here means that one of the keys ran out of fields and
- ** all the fields up to that point were equal. Return the the default_rc
+ ** all the fields up to that point were equal. Return the default_rc
** value. */
- return pPKey2->default_rc;
+ rc = pPKey2->default_rc;
+
+debugCompareEnd:
+ if( desiredResult==0 && rc==0 ) return 1;
+ if( desiredResult<0 && rc<0 ) return 1;
+ if( desiredResult>0 && rc>0 ) return 1;
+ if( CORRUPT_DB ) return 1;
+ if( pKeyInfo->db->mallocFailed ) return 1;
+ return 0;
+}
+#endif
+
+#if SQLITE_DEBUG
+/*
+** Count the number of fields (a.k.a. columns) in the record given by
+** pKey,nKey. The verify that this count is less than or equal to the
+** limit given by pKeyInfo->nField + pKeyInfo->nXField.
+**
+** If this constraint is not satisfied, it means that the high-speed
+** vdbeRecordCompareInt() and vdbeRecordCompareString() routines will
+** not work correctly. If this assert() ever fires, it probably means
+** that the KeyInfo.nField or KeyInfo.nXField values were computed
+** incorrectly.
+*/
+static void vdbeAssertFieldCountWithinLimits(
+ int nKey, const void *pKey, /* The record to verify */
+ const KeyInfo *pKeyInfo /* Compare size with this KeyInfo */
+){
+ int nField = 0;
+ u32 szHdr;
+ u32 idx;
+ u32 notUsed;
+ const unsigned char *aKey = (const unsigned char*)pKey;
+
+ if( CORRUPT_DB ) return;
+ idx = getVarint32(aKey, szHdr);
+ assert( nKey>=0 );
+ assert( szHdr<=(u32)nKey );
+ while( idx<szHdr ){
+ idx += getVarint32(aKey+idx, notUsed);
+ nField++;
+ }
+ assert( nField <= pKeyInfo->nField+pKeyInfo->nXField );
}
+#else
+# define vdbeAssertFieldCountWithinLimits(A,B,C)
#endif
/*
@@ -65457,7 +68183,8 @@ static int vdbeRecordCompareDebug(
static int vdbeCompareMemString(
const Mem *pMem1,
const Mem *pMem2,
- const CollSeq *pColl
+ const CollSeq *pColl,
+ u8 *prcErr /* If an OOM occurs, set to SQLITE_NOMEM */
){
if( pMem1->enc==pColl->enc ){
/* The strings are already in the correct encoding. Call the
@@ -65469,8 +68196,8 @@ static int vdbeCompareMemString(
int n1, n2;
Mem c1;
Mem c2;
- memset(&c1, 0, sizeof(c1));
- memset(&c2, 0, sizeof(c2));
+ sqlite3VdbeMemInit(&c1, pMem1->db, MEM_Null);
+ sqlite3VdbeMemInit(&c2, pMem1->db, MEM_Null);
sqlite3VdbeMemShallowCopy(&c1, pMem1, MEM_Ephem);
sqlite3VdbeMemShallowCopy(&c2, pMem2, MEM_Ephem);
v1 = sqlite3ValueText((sqlite3_value*)&c1, pColl->enc);
@@ -65480,11 +68207,24 @@ static int vdbeCompareMemString(
rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2);
sqlite3VdbeMemRelease(&c1);
sqlite3VdbeMemRelease(&c2);
+ if( (v1==0 || v2==0) && prcErr ) *prcErr = SQLITE_NOMEM;
return rc;
}
}
/*
+** Compare two blobs. Return negative, zero, or positive if the first
+** is less than, equal to, or greater than the second, respectively.
+** If one blob is a prefix of the other, then the shorter is the lessor.
+*/
+static SQLITE_NOINLINE int sqlite3BlobCompare(const Mem *pB1, const Mem *pB2){
+ int c = memcmp(pB1->z, pB2->z, pB1->n>pB2->n ? pB2->n : pB1->n);
+ if( c ) return c;
+ return pB1->n - pB2->n;
+}
+
+
+/*
** Compare the values contained by the two memory cells, returning
** negative, zero or positive if pMem1 is less than, equal to, or greater
** than pMem2. Sorting order is NULL's first, followed by numbers (integers
@@ -65494,7 +68234,6 @@ static int vdbeCompareMemString(
** Two NULL values are considered equal by this function.
*/
SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
- int rc;
int f1, f2;
int combined_flags;
@@ -65522,14 +68261,14 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C
return 0;
}
if( (f1&MEM_Real)!=0 ){
- r1 = pMem1->r;
+ r1 = pMem1->u.r;
}else if( (f1&MEM_Int)!=0 ){
r1 = (double)pMem1->u.i;
}else{
return 1;
}
if( (f2&MEM_Real)!=0 ){
- r2 = pMem2->r;
+ r2 = pMem2->u.r;
}else if( (f2&MEM_Int)!=0 ){
r2 = (double)pMem2->u.i;
}else{
@@ -65562,18 +68301,14 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C
assert( !pColl || pColl->xCmp );
if( pColl ){
- return vdbeCompareMemString(pMem1, pMem2, pColl);
+ return vdbeCompareMemString(pMem1, pMem2, pColl, 0);
}
/* If a NULL pointer was passed as the collate function, fall through
** to the blob case and use memcmp(). */
}
/* Both values must be blobs. Compare using memcmp(). */
- rc = memcmp(pMem1->z, pMem2->z, (pMem1->n>pMem2->n)?pMem2->n:pMem1->n);
- if( rc==0 ){
- rc = pMem1->n - pMem2->n;
- }
- return rc;
+ return sqlite3BlobCompare(pMem1, pMem2);
}
@@ -65623,7 +68358,7 @@ static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){
** specified by {nKey1, pKey1} and pPKey2. It returns a negative, zero
** or positive integer if key1 is less than, equal to or
** greater than key2. The {nKey1, pKey1} key must be a blob
-** created by th OP_MakeRecord opcode of the VDBE. The pPKey2
+** created by the OP_MakeRecord opcode of the VDBE. The pPKey2
** key must be a parsed key such as obtained from
** sqlite3VdbeParseRecord.
**
@@ -65634,10 +68369,12 @@ static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){
** fields that appear in both keys are equal, then pPKey2->default_rc is
** returned.
**
-** If database corruption is discovered, set pPKey2->isCorrupt to non-zero
-** and return 0.
+** If database corruption is discovered, set pPKey2->errCode to
+** SQLITE_CORRUPT and return 0. If an OOM error is encountered,
+** pPKey2->errCode is set to SQLITE_NOMEM and, if it is not NULL, the
+** malloc-failed flag set on database handle (pPKey2->pKeyInfo->db).
*/
-SQLITE_PRIVATE int sqlite3VdbeRecordCompare(
+SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
int nKey1, const void *pKey1, /* Left key */
UnpackedRecord *pPKey2, /* Right key */
int bSkip /* If true, skip the first field */
@@ -65666,13 +68403,13 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare(
idx1 = getVarint32(aKey1, szHdr1);
d1 = szHdr1;
if( d1>(unsigned)nKey1 ){
- pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT;
+ pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
return 0; /* Corruption */
}
i = 0;
}
- VVA_ONLY( mem1.zMalloc = 0; ) /* Only needed by assert() statements */
+ VVA_ONLY( mem1.szMalloc = 0; ) /* Only needed by assert() statements */
assert( pPKey2->pKeyInfo->nField+pPKey2->pKeyInfo->nXField>=pPKey2->nField
|| CORRUPT_DB );
assert( pPKey2->pKeyInfo->aSortOrder!=0 );
@@ -65692,9 +68429,9 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare(
}else if( serial_type==7 ){
double rhs = (double)pRhs->u.i;
sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
- if( mem1.r<rhs ){
+ if( mem1.u.r<rhs ){
rc = -1;
- }else if( mem1.r>rhs ){
+ }else if( mem1.u.r>rhs ){
rc = +1;
}
}else{
@@ -65716,11 +68453,11 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare(
}else if( serial_type==0 ){
rc = -1;
}else{
- double rhs = pRhs->r;
+ double rhs = pRhs->u.r;
double lhs;
sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
if( serial_type==7 ){
- lhs = mem1.r;
+ lhs = mem1.u.r;
}else{
lhs = (double)mem1.u.i;
}
@@ -65745,14 +68482,16 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare(
testcase( (d1+mem1.n)==(unsigned)nKey1 );
testcase( (d1+mem1.n+1)==(unsigned)nKey1 );
if( (d1+mem1.n) > (unsigned)nKey1 ){
- pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT;
+ pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
return 0; /* Corruption */
}else if( pKeyInfo->aColl[i] ){
mem1.enc = pKeyInfo->enc;
mem1.db = pKeyInfo->db;
mem1.flags = MEM_Str;
mem1.z = (char*)&aKey1[d1];
- rc = vdbeCompareMemString(&mem1, pRhs, pKeyInfo->aColl[i]);
+ rc = vdbeCompareMemString(
+ &mem1, pRhs, pKeyInfo->aColl[i], &pPKey2->errCode
+ );
}else{
int nCmp = MIN(mem1.n, pRhs->n);
rc = memcmp(&aKey1[d1], pRhs->z, nCmp);
@@ -65772,7 +68511,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare(
testcase( (d1+nStr)==(unsigned)nKey1 );
testcase( (d1+nStr+1)==(unsigned)nKey1 );
if( (d1+nStr) > (unsigned)nKey1 ){
- pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT;
+ pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
return 0; /* Corruption */
}else{
int nCmp = MIN(nStr, pRhs->n);
@@ -65792,12 +68531,8 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare(
if( pKeyInfo->aSortOrder[i] ){
rc = -rc;
}
- assert( CORRUPT_DB
- || (rc<0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)<0)
- || (rc>0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)>0)
- || pKeyInfo->db->mallocFailed
- );
- assert( mem1.zMalloc==0 ); /* See comment below */
+ assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, rc) );
+ assert( mem1.szMalloc==0 ); /* See comment below */
return rc;
}
@@ -65810,17 +68545,24 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare(
/* No memory allocation is ever used on mem1. Prove this using
** the following assert(). If the assert() fails, it indicates a
** memory leak and a need to call sqlite3VdbeMemRelease(&mem1). */
- assert( mem1.zMalloc==0 );
+ assert( mem1.szMalloc==0 );
/* rc==0 here means that one or both of the keys ran out of fields and
- ** all the fields up to that point were equal. Return the the default_rc
+ ** all the fields up to that point were equal. Return the default_rc
** value. */
assert( CORRUPT_DB
- || pPKey2->default_rc==vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)
+ || vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, pPKey2->default_rc)
|| pKeyInfo->db->mallocFailed
);
return pPKey2->default_rc;
}
+SQLITE_PRIVATE int sqlite3VdbeRecordCompare(
+ int nKey1, const void *pKey1, /* Left key */
+ UnpackedRecord *pPKey2 /* Right key */
+){
+ return sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 0);
+}
+
/*
** This function is an optimized version of sqlite3VdbeRecordCompare()
@@ -65833,8 +68575,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare(
*/
static int vdbeRecordCompareInt(
int nKey1, const void *pKey1, /* Left key */
- UnpackedRecord *pPKey2, /* Right key */
- int bSkip /* Ignored */
+ UnpackedRecord *pPKey2 /* Right key */
){
const u8 *aKey = &((const u8*)pKey1)[*(const u8*)pKey1 & 0x3F];
int serial_type = ((const u8*)pKey1)[1];
@@ -65843,9 +68584,8 @@ static int vdbeRecordCompareInt(
u64 x;
i64 v = pPKey2->aMem[0].u.i;
i64 lhs;
- UNUSED_PARAMETER(bSkip);
- assert( bSkip==0 );
+ vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo);
assert( (*(u8*)pKey1)<=0x3F || CORRUPT_DB );
switch( serial_type ){
case 1: { /* 1-byte signed integer */
@@ -65895,10 +68635,10 @@ static int vdbeRecordCompareInt(
** (as gcc is clever enough to combine the two like cases). Other
** compilers might be similar. */
case 0: case 7:
- return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2, 0);
+ return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2);
default:
- return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2, 0);
+ return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2);
}
if( v>lhs ){
@@ -65908,18 +68648,14 @@ static int vdbeRecordCompareInt(
}else if( pPKey2->nField>1 ){
/* The first fields of the two keys are equal. Compare the trailing
** fields. */
- res = sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2, 1);
+ res = sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1);
}else{
/* The first fields of the two keys are equal and there are no trailing
** fields. Return pPKey2->default_rc in this case. */
res = pPKey2->default_rc;
}
- assert( (res==0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)==0)
- || (res<0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)<0)
- || (res>0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)>0)
- || CORRUPT_DB
- );
+ assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, res) );
return res;
}
@@ -65931,17 +68667,14 @@ static int vdbeRecordCompareInt(
*/
static int vdbeRecordCompareString(
int nKey1, const void *pKey1, /* Left key */
- UnpackedRecord *pPKey2, /* Right key */
- int bSkip
+ UnpackedRecord *pPKey2 /* Right key */
){
const u8 *aKey1 = (const u8*)pKey1;
int serial_type;
int res;
- UNUSED_PARAMETER(bSkip);
- assert( bSkip==0 );
+ vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo);
getVarint32(&aKey1[1], serial_type);
-
if( serial_type<12 ){
res = pPKey2->r1; /* (pKey1/nKey1) is a number or a null */
}else if( !(serial_type & 0x01) ){
@@ -65953,7 +68686,7 @@ static int vdbeRecordCompareString(
nStr = (serial_type-12) / 2;
if( (szHdr + nStr) > nKey1 ){
- pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT;
+ pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
return 0; /* Corruption */
}
nCmp = MIN( pPKey2->aMem[0].n, nStr );
@@ -65963,7 +68696,7 @@ static int vdbeRecordCompareString(
res = nStr - pPKey2->aMem[0].n;
if( res==0 ){
if( pPKey2->nField>1 ){
- res = sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2, 1);
+ res = sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1);
}else{
res = pPKey2->default_rc;
}
@@ -65979,9 +68712,7 @@ static int vdbeRecordCompareString(
}
}
- assert( (res==0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)==0)
- || (res<0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)<0)
- || (res>0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)>0)
+ assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, res)
|| CORRUPT_DB
|| pPKey2->pKeyInfo->db->mallocFailed
);
@@ -66047,8 +68778,6 @@ SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){
u32 lenRowid; /* Size of the rowid */
Mem m, v;
- UNUSED_PARAMETER(db);
-
/* Get the size of the index entry. Only indices entries of less
** than 2GiB are support - anything large must be database corruption.
** Any corruption is detected in sqlite3BtreeParseCellPtr(), though, so
@@ -66060,7 +68789,7 @@ SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){
assert( (nCellKey & SQLITE_MAX_U32)==(u64)nCellKey );
/* Read in the complete content of the index entry */
- memset(&m, 0, sizeof(m));
+ sqlite3VdbeMemInit(&m, db, 0);
rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, 1, &m);
if( rc ){
return rc;
@@ -66103,7 +68832,7 @@ SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){
/* Jump here if database corruption is detected after m has been
** allocated. Free the m object and return SQLITE_CORRUPT. */
idx_rowid_corruption:
- testcase( m.zMalloc!=0 );
+ testcase( m.szMalloc!=0 );
sqlite3VdbeMemRelease(&m);
return SQLITE_CORRUPT_BKPT;
}
@@ -66120,6 +68849,7 @@ idx_rowid_corruption:
** of the keys prior to the final rowid, not the entire key.
*/
SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(
+ sqlite3 *db, /* Database connection */
VdbeCursor *pC, /* The cursor to compare against */
UnpackedRecord *pUnpacked, /* Unpacked version of key */
int *res /* Write the comparison result here */
@@ -66138,12 +68868,12 @@ SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(
*res = 0;
return SQLITE_CORRUPT_BKPT;
}
- memset(&m, 0, sizeof(m));
+ sqlite3VdbeMemInit(&m, db, 0);
rc = sqlite3VdbeMemFromBtree(pC->pCursor, 0, (u32)nCellKey, 1, &m);
if( rc ){
return rc;
}
- *res = sqlite3VdbeRecordCompare(m.n, m.z, pUnpacked, 0);
+ *res = sqlite3VdbeRecordCompare(m.n, m.z, pUnpacked);
sqlite3VdbeMemRelease(&m);
return SQLITE_OK;
}
@@ -66270,7 +69000,7 @@ SQLITE_PRIVATE void sqlite3VtabImportErrmsg(Vdbe *p, sqlite3_vtab *pVtab){
** collating sequences are registered or if an authorizer function is
** added or changed.
*/
-SQLITE_API int sqlite3_expired(sqlite3_stmt *pStmt){
+SQLITE_API int SQLITE_STDCALL sqlite3_expired(sqlite3_stmt *pStmt){
Vdbe *p = (Vdbe*)pStmt;
return p==0 || p->expired;
}
@@ -66307,7 +69037,7 @@ static int vdbeSafetyNotNull(Vdbe *p){
** This routine sets the error code and string returned by
** sqlite3_errcode(), sqlite3_errmsg() and sqlite3_errmsg16().
*/
-SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt){
+SQLITE_API int SQLITE_STDCALL sqlite3_finalize(sqlite3_stmt *pStmt){
int rc;
if( pStmt==0 ){
/* IMPLEMENTATION-OF: R-57228-12904 Invoking sqlite3_finalize() on a NULL
@@ -66333,7 +69063,7 @@ SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt){
** This routine sets the error code and string returned by
** sqlite3_errcode(), sqlite3_errmsg() and sqlite3_errmsg16().
*/
-SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt){
+SQLITE_API int SQLITE_STDCALL sqlite3_reset(sqlite3_stmt *pStmt){
int rc;
if( pStmt==0 ){
rc = SQLITE_OK;
@@ -66352,7 +69082,7 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt){
/*
** Set all the parameters in the compiled SQL statement to NULL.
*/
-SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt *pStmt){
+SQLITE_API int SQLITE_STDCALL sqlite3_clear_bindings(sqlite3_stmt *pStmt){
int i;
int rc = SQLITE_OK;
Vdbe *p = (Vdbe*)pStmt;
@@ -66376,7 +69106,7 @@ SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt *pStmt){
** The following routines extract information from a Mem or sqlite3_value
** structure.
*/
-SQLITE_API const void *sqlite3_value_blob(sqlite3_value *pVal){
+SQLITE_API const void *SQLITE_STDCALL sqlite3_value_blob(sqlite3_value *pVal){
Mem *p = (Mem*)pVal;
if( p->flags & (MEM_Blob|MEM_Str) ){
sqlite3VdbeMemExpandBlob(p);
@@ -66386,36 +69116,40 @@ SQLITE_API const void *sqlite3_value_blob(sqlite3_value *pVal){
return sqlite3_value_text(pVal);
}
}
-SQLITE_API int sqlite3_value_bytes(sqlite3_value *pVal){
+SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes(sqlite3_value *pVal){
return sqlite3ValueBytes(pVal, SQLITE_UTF8);
}
-SQLITE_API int sqlite3_value_bytes16(sqlite3_value *pVal){
+SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes16(sqlite3_value *pVal){
return sqlite3ValueBytes(pVal, SQLITE_UTF16NATIVE);
}
-SQLITE_API double sqlite3_value_double(sqlite3_value *pVal){
+SQLITE_API double SQLITE_STDCALL sqlite3_value_double(sqlite3_value *pVal){
return sqlite3VdbeRealValue((Mem*)pVal);
}
-SQLITE_API int sqlite3_value_int(sqlite3_value *pVal){
+SQLITE_API int SQLITE_STDCALL sqlite3_value_int(sqlite3_value *pVal){
return (int)sqlite3VdbeIntValue((Mem*)pVal);
}
-SQLITE_API sqlite_int64 sqlite3_value_int64(sqlite3_value *pVal){
+SQLITE_API sqlite_int64 SQLITE_STDCALL sqlite3_value_int64(sqlite3_value *pVal){
return sqlite3VdbeIntValue((Mem*)pVal);
}
-SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value *pVal){
+SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_value_text(sqlite3_value *pVal){
return (const unsigned char *)sqlite3ValueText(pVal, SQLITE_UTF8);
}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API const void *sqlite3_value_text16(sqlite3_value* pVal){
+SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16(sqlite3_value* pVal){
return sqlite3ValueText(pVal, SQLITE_UTF16NATIVE);
}
-SQLITE_API const void *sqlite3_value_text16be(sqlite3_value *pVal){
+SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16be(sqlite3_value *pVal){
return sqlite3ValueText(pVal, SQLITE_UTF16BE);
}
-SQLITE_API const void *sqlite3_value_text16le(sqlite3_value *pVal){
+SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16le(sqlite3_value *pVal){
return sqlite3ValueText(pVal, SQLITE_UTF16LE);
}
#endif /* SQLITE_OMIT_UTF16 */
-SQLITE_API int sqlite3_value_type(sqlite3_value* pVal){
+/* EVIDENCE-OF: R-12793-43283 Every value in SQLite has one of five
+** fundamental datatypes: 64-bit signed integer 64-bit IEEE floating
+** point number string BLOB NULL
+*/
+SQLITE_API int SQLITE_STDCALL sqlite3_value_type(sqlite3_value* pVal){
static const u8 aType[] = {
SQLITE_BLOB, /* 0x00 */
SQLITE_NULL, /* 0x01 */
@@ -66457,9 +69191,12 @@ SQLITE_API int sqlite3_value_type(sqlite3_value* pVal){
** The following routines are used by user-defined functions to specify
** the function result.
**
-** The setStrOrError() funtion calls sqlite3VdbeMemSetStr() to store the
+** The setStrOrError() function calls sqlite3VdbeMemSetStr() to store the
** result as a string or blob but if the string or blob is too large, it
** then sets the error code to SQLITE_TOOBIG
+**
+** The invokeValueDestructor(P,X) routine invokes destructor function X()
+** on value P is not going to be used and need to be destroyed.
*/
static void setResultStrOrError(
sqlite3_context *pCtx, /* Function context */
@@ -66468,121 +69205,170 @@ static void setResultStrOrError(
u8 enc, /* Encoding of z. 0 for BLOBs */
void (*xDel)(void*) /* Destructor function */
){
- if( sqlite3VdbeMemSetStr(&pCtx->s, z, n, enc, xDel)==SQLITE_TOOBIG ){
+ if( sqlite3VdbeMemSetStr(pCtx->pOut, z, n, enc, xDel)==SQLITE_TOOBIG ){
sqlite3_result_error_toobig(pCtx);
}
}
-SQLITE_API void sqlite3_result_blob(
+static int invokeValueDestructor(
+ const void *p, /* Value to destroy */
+ void (*xDel)(void*), /* The destructor */
+ sqlite3_context *pCtx /* Set a SQLITE_TOOBIG error if no NULL */
+){
+ assert( xDel!=SQLITE_DYNAMIC );
+ if( xDel==0 ){
+ /* noop */
+ }else if( xDel==SQLITE_TRANSIENT ){
+ /* noop */
+ }else{
+ xDel((void*)p);
+ }
+ if( pCtx ) sqlite3_result_error_toobig(pCtx);
+ return SQLITE_TOOBIG;
+}
+SQLITE_API void SQLITE_STDCALL sqlite3_result_blob(
sqlite3_context *pCtx,
const void *z,
int n,
void (*xDel)(void *)
){
assert( n>=0 );
- assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
+ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
setResultStrOrError(pCtx, z, n, 0, xDel);
}
-SQLITE_API void sqlite3_result_double(sqlite3_context *pCtx, double rVal){
- assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
- sqlite3VdbeMemSetDouble(&pCtx->s, rVal);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_blob64(
+ sqlite3_context *pCtx,
+ const void *z,
+ sqlite3_uint64 n,
+ void (*xDel)(void *)
+){
+ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
+ assert( xDel!=SQLITE_DYNAMIC );
+ if( n>0x7fffffff ){
+ (void)invokeValueDestructor(z, xDel, pCtx);
+ }else{
+ setResultStrOrError(pCtx, z, (int)n, 0, xDel);
+ }
+}
+SQLITE_API void SQLITE_STDCALL sqlite3_result_double(sqlite3_context *pCtx, double rVal){
+ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
+ sqlite3VdbeMemSetDouble(pCtx->pOut, rVal);
}
-SQLITE_API void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){
- assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
+SQLITE_API void SQLITE_STDCALL sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){
+ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
pCtx->isError = SQLITE_ERROR;
pCtx->fErrorOrAux = 1;
- sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF8, SQLITE_TRANSIENT);
+ sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF8, SQLITE_TRANSIENT);
}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){
- assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
+SQLITE_API void SQLITE_STDCALL sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){
+ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
pCtx->isError = SQLITE_ERROR;
pCtx->fErrorOrAux = 1;
- sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT);
+ sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT);
}
#endif
-SQLITE_API void sqlite3_result_int(sqlite3_context *pCtx, int iVal){
- assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
- sqlite3VdbeMemSetInt64(&pCtx->s, (i64)iVal);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_int(sqlite3_context *pCtx, int iVal){
+ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
+ sqlite3VdbeMemSetInt64(pCtx->pOut, (i64)iVal);
}
-SQLITE_API void sqlite3_result_int64(sqlite3_context *pCtx, i64 iVal){
- assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
- sqlite3VdbeMemSetInt64(&pCtx->s, iVal);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_int64(sqlite3_context *pCtx, i64 iVal){
+ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
+ sqlite3VdbeMemSetInt64(pCtx->pOut, iVal);
}
-SQLITE_API void sqlite3_result_null(sqlite3_context *pCtx){
- assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
- sqlite3VdbeMemSetNull(&pCtx->s);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_null(sqlite3_context *pCtx){
+ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
+ sqlite3VdbeMemSetNull(pCtx->pOut);
}
-SQLITE_API void sqlite3_result_text(
+SQLITE_API void SQLITE_STDCALL sqlite3_result_text(
sqlite3_context *pCtx,
const char *z,
int n,
void (*xDel)(void *)
){
- assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
+ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
setResultStrOrError(pCtx, z, n, SQLITE_UTF8, xDel);
}
+SQLITE_API void SQLITE_STDCALL sqlite3_result_text64(
+ sqlite3_context *pCtx,
+ const char *z,
+ sqlite3_uint64 n,
+ void (*xDel)(void *),
+ unsigned char enc
+){
+ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
+ assert( xDel!=SQLITE_DYNAMIC );
+ if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE;
+ if( n>0x7fffffff ){
+ (void)invokeValueDestructor(z, xDel, pCtx);
+ }else{
+ setResultStrOrError(pCtx, z, (int)n, enc, xDel);
+ }
+}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API void sqlite3_result_text16(
+SQLITE_API void SQLITE_STDCALL sqlite3_result_text16(
sqlite3_context *pCtx,
const void *z,
int n,
void (*xDel)(void *)
){
- assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
+ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
setResultStrOrError(pCtx, z, n, SQLITE_UTF16NATIVE, xDel);
}
-SQLITE_API void sqlite3_result_text16be(
+SQLITE_API void SQLITE_STDCALL sqlite3_result_text16be(
sqlite3_context *pCtx,
const void *z,
int n,
void (*xDel)(void *)
){
- assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
+ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
setResultStrOrError(pCtx, z, n, SQLITE_UTF16BE, xDel);
}
-SQLITE_API void sqlite3_result_text16le(
+SQLITE_API void SQLITE_STDCALL sqlite3_result_text16le(
sqlite3_context *pCtx,
const void *z,
int n,
void (*xDel)(void *)
){
- assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
+ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
setResultStrOrError(pCtx, z, n, SQLITE_UTF16LE, xDel);
}
#endif /* SQLITE_OMIT_UTF16 */
-SQLITE_API void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){
- assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
- sqlite3VdbeMemCopy(&pCtx->s, pValue);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){
+ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
+ sqlite3VdbeMemCopy(pCtx->pOut, pValue);
}
-SQLITE_API void sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){
- assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
- sqlite3VdbeMemSetZeroBlob(&pCtx->s, n);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){
+ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
+ sqlite3VdbeMemSetZeroBlob(pCtx->pOut, n);
}
-SQLITE_API void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
+SQLITE_API void SQLITE_STDCALL sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
pCtx->isError = errCode;
pCtx->fErrorOrAux = 1;
- if( pCtx->s.flags & MEM_Null ){
- sqlite3VdbeMemSetStr(&pCtx->s, sqlite3ErrStr(errCode), -1,
+#ifdef SQLITE_DEBUG
+ if( pCtx->pVdbe ) pCtx->pVdbe->rcApp = errCode;
+#endif
+ if( pCtx->pOut->flags & MEM_Null ){
+ sqlite3VdbeMemSetStr(pCtx->pOut, sqlite3ErrStr(errCode), -1,
SQLITE_UTF8, SQLITE_STATIC);
}
}
/* Force an SQLITE_TOOBIG error. */
-SQLITE_API void sqlite3_result_error_toobig(sqlite3_context *pCtx){
- assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
+SQLITE_API void SQLITE_STDCALL sqlite3_result_error_toobig(sqlite3_context *pCtx){
+ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
pCtx->isError = SQLITE_TOOBIG;
pCtx->fErrorOrAux = 1;
- sqlite3VdbeMemSetStr(&pCtx->s, "string or blob too big", -1,
+ sqlite3VdbeMemSetStr(pCtx->pOut, "string or blob too big", -1,
SQLITE_UTF8, SQLITE_STATIC);
}
/* An SQLITE_NOMEM error. */
-SQLITE_API void sqlite3_result_error_nomem(sqlite3_context *pCtx){
- assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
- sqlite3VdbeMemSetNull(&pCtx->s);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_error_nomem(sqlite3_context *pCtx){
+ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
+ sqlite3VdbeMemSetNull(pCtx->pOut);
pCtx->isError = SQLITE_NOMEM;
pCtx->fErrorOrAux = 1;
- pCtx->s.db->mallocFailed = 1;
+ pCtx->pOut->db->mallocFailed = 1;
}
/*
@@ -66596,7 +69382,10 @@ static int doWalCallbacks(sqlite3 *db){
for(i=0; i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
if( pBt ){
- int nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt));
+ int nEntry;
+ sqlite3BtreeEnter(pBt);
+ nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt));
+ sqlite3BtreeLeave(pBt);
if( db->xWalCallback && nEntry>0 && rc==SQLITE_OK ){
rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zName, nEntry);
}
@@ -66638,7 +69427,7 @@ static int sqlite3Step(Vdbe *p){
** or SQLITE_BUSY error.
*/
#ifdef SQLITE_OMIT_AUTORESET
- if( p->rc==SQLITE_BUSY || p->rc==SQLITE_LOCKED ){
+ if( (rc = p->rc&0xff)==SQLITE_BUSY || rc==SQLITE_LOCKED ){
sqlite3_reset((sqlite3_stmt*)p);
}else{
return SQLITE_MISUSE_BKPT;
@@ -66684,6 +69473,9 @@ static int sqlite3Step(Vdbe *p){
if( p->bIsReader ) db->nVdbeRead++;
p->pc = 0;
}
+#ifdef SQLITE_DEBUG
+ p->rcApp = SQLITE_OK;
+#endif
#ifndef SQLITE_OMIT_EXPLAIN
if( p->explain ){
rc = sqlite3VdbeList(p);
@@ -66728,7 +69520,7 @@ end_of_step:
assert( rc==SQLITE_ROW || rc==SQLITE_DONE || rc==SQLITE_ERROR
|| rc==SQLITE_BUSY || rc==SQLITE_MISUSE
);
- assert( p->rc!=SQLITE_ROW && p->rc!=SQLITE_DONE );
+ assert( (p->rc!=SQLITE_ROW && p->rc!=SQLITE_DONE) || p->rc==p->rcApp );
if( p->isPrepareV2 && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
/* If this statement was prepared using sqlite3_prepare_v2(), and an
** error has occurred, then return the error code in p->rc to the
@@ -66744,7 +69536,7 @@ end_of_step:
** sqlite3Step() to do most of the work. If a schema error occurs,
** call sqlite3Reprepare() and try again.
*/
-SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){
+SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt *pStmt){
int rc = SQLITE_OK; /* Result from sqlite3Step() */
int rc2 = SQLITE_OK; /* Result from sqlite3Reprepare() */
Vdbe *v = (Vdbe*)pStmt; /* the prepared statement */
@@ -66758,10 +69550,12 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){
sqlite3_mutex_enter(db->mutex);
v->doingRerun = 0;
while( (rc = sqlite3Step(v))==SQLITE_SCHEMA
- && cnt++ < SQLITE_MAX_SCHEMA_RETRY
- && (rc2 = rc = sqlite3Reprepare(v))==SQLITE_OK ){
+ && cnt++ < SQLITE_MAX_SCHEMA_RETRY ){
+ int savedPc = v->pc;
+ rc2 = rc = sqlite3Reprepare(v);
+ if( rc!=SQLITE_OK) break;
sqlite3_reset(pStmt);
- v->doingRerun = 1;
+ if( savedPc>=0 ) v->doingRerun = 1;
assert( v->expired==0 );
}
if( rc2!=SQLITE_OK ){
@@ -66774,7 +69568,6 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){
** sqlite3_errmsg() and sqlite3_errcode().
*/
const char *zErr = (const char *)sqlite3_value_text(db->pErr);
- assert( zErr!=0 || db->mallocFailed );
sqlite3DbFree(db, v->zErrMsg);
if( !db->mallocFailed ){
v->zErrMsg = sqlite3DbStrDup(db, zErr);
@@ -66794,7 +69587,7 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){
** Extract the user data from a sqlite3_context structure and return a
** pointer to it.
*/
-SQLITE_API void *sqlite3_user_data(sqlite3_context *p){
+SQLITE_API void *SQLITE_STDCALL sqlite3_user_data(sqlite3_context *p){
assert( p && p->pFunc );
return p->pFunc->pUserData;
}
@@ -66809,22 +69602,32 @@ SQLITE_API void *sqlite3_user_data(sqlite3_context *p){
** sqlite3_create_function16() routines that originally registered the
** application defined function.
*/
-SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){
+SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context *p){
assert( p && p->pFunc );
- return p->s.db;
+ return p->pOut->db;
}
/*
-** Return the current time for a statement
+** Return the current time for a statement. If the current time
+** is requested more than once within the same run of a single prepared
+** statement, the exact same time is returned for each invocation regardless
+** of the amount of time that elapses between invocations. In other words,
+** the time returned is always the time of the first call.
*/
SQLITE_PRIVATE sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context *p){
- Vdbe *v = p->pVdbe;
int rc;
- if( v->iCurrentTime==0 ){
- rc = sqlite3OsCurrentTimeInt64(p->s.db->pVfs, &v->iCurrentTime);
- if( rc ) v->iCurrentTime = 0;
+#ifndef SQLITE_ENABLE_STAT3_OR_STAT4
+ sqlite3_int64 *piTime = &p->pVdbe->iCurrentTime;
+ assert( p->pVdbe!=0 );
+#else
+ sqlite3_int64 iTime = 0;
+ sqlite3_int64 *piTime = p->pVdbe!=0 ? &p->pVdbe->iCurrentTime : &iTime;
+#endif
+ if( *piTime==0 ){
+ rc = sqlite3OsCurrentTimeInt64(p->pOut->db->pVfs, piTime);
+ if( rc ) *piTime = 0;
}
- return v->iCurrentTime;
+ return *piTime;
}
/*
@@ -66850,41 +69653,55 @@ SQLITE_PRIVATE void sqlite3InvalidFunction(
}
/*
+** Create a new aggregate context for p and return a pointer to
+** its pMem->z element.
+*/
+static SQLITE_NOINLINE void *createAggContext(sqlite3_context *p, int nByte){
+ Mem *pMem = p->pMem;
+ assert( (pMem->flags & MEM_Agg)==0 );
+ if( nByte<=0 ){
+ sqlite3VdbeMemSetNull(pMem);
+ pMem->z = 0;
+ }else{
+ sqlite3VdbeMemClearAndResize(pMem, nByte);
+ pMem->flags = MEM_Agg;
+ pMem->u.pDef = p->pFunc;
+ if( pMem->z ){
+ memset(pMem->z, 0, nByte);
+ }
+ }
+ return (void*)pMem->z;
+}
+
+/*
** Allocate or return the aggregate context for a user function. A new
** context is allocated on the first call. Subsequent calls return the
** same context that was returned on prior calls.
*/
-SQLITE_API void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){
- Mem *pMem;
+SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context *p, int nByte){
assert( p && p->pFunc && p->pFunc->xStep );
- assert( sqlite3_mutex_held(p->s.db->mutex) );
- pMem = p->pMem;
+ assert( sqlite3_mutex_held(p->pOut->db->mutex) );
testcase( nByte<0 );
- if( (pMem->flags & MEM_Agg)==0 ){
- if( nByte<=0 ){
- sqlite3VdbeMemReleaseExternal(pMem);
- pMem->flags = MEM_Null;
- pMem->z = 0;
- }else{
- sqlite3VdbeMemGrow(pMem, nByte, 0);
- pMem->flags = MEM_Agg;
- pMem->u.pDef = p->pFunc;
- if( pMem->z ){
- memset(pMem->z, 0, nByte);
- }
- }
+ if( (p->pMem->flags & MEM_Agg)==0 ){
+ return createAggContext(p, nByte);
+ }else{
+ return (void*)p->pMem->z;
}
- return (void*)pMem->z;
}
/*
-** Return the auxilary data pointer, if any, for the iArg'th argument to
+** Return the auxiliary data pointer, if any, for the iArg'th argument to
** the user-function defined by pCtx.
*/
-SQLITE_API void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
+SQLITE_API void *SQLITE_STDCALL sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
AuxData *pAuxData;
- assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
+ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
+#if SQLITE_ENABLE_STAT3_OR_STAT4
+ if( pCtx->pVdbe==0 ) return 0;
+#else
+ assert( pCtx->pVdbe!=0 );
+#endif
for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){
if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break;
}
@@ -66893,11 +69710,11 @@ SQLITE_API void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
}
/*
-** Set the auxilary data pointer and delete function, for the iArg'th
+** Set the auxiliary data pointer and delete function, for the iArg'th
** argument to the user-function defined by pCtx. Any previous value is
** deleted by calling the delete function specified when it was set.
*/
-SQLITE_API void sqlite3_set_auxdata(
+SQLITE_API void SQLITE_STDCALL sqlite3_set_auxdata(
sqlite3_context *pCtx,
int iArg,
void *pAux,
@@ -66906,8 +69723,13 @@ SQLITE_API void sqlite3_set_auxdata(
AuxData *pAuxData;
Vdbe *pVdbe = pCtx->pVdbe;
- assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
+ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
if( iArg<0 ) goto failed;
+#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+ if( pVdbe==0 ) goto failed;
+#else
+ assert( pVdbe!=0 );
+#endif
for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){
if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break;
@@ -66939,7 +69761,7 @@ failed:
#ifndef SQLITE_OMIT_DEPRECATED
/*
-** Return the number of times the Step function of a aggregate has been
+** Return the number of times the Step function of an aggregate has been
** called.
**
** This function is deprecated. Do not use it for new code. It is
@@ -66947,7 +69769,7 @@ failed:
** implementations should keep their own counts within their aggregate
** context.
*/
-SQLITE_API int sqlite3_aggregate_count(sqlite3_context *p){
+SQLITE_API int SQLITE_STDCALL sqlite3_aggregate_count(sqlite3_context *p){
assert( p && p->pMem && p->pFunc && p->pFunc->xStep );
return p->pMem->n;
}
@@ -66956,7 +69778,7 @@ SQLITE_API int sqlite3_aggregate_count(sqlite3_context *p){
/*
** Return the number of columns in the result set for the statement pStmt.
*/
-SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt){
+SQLITE_API int SQLITE_STDCALL sqlite3_column_count(sqlite3_stmt *pStmt){
Vdbe *pVm = (Vdbe *)pStmt;
return pVm ? pVm->nResColumn : 0;
}
@@ -66965,7 +69787,7 @@ SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt){
** Return the number of values available from the current row of the
** currently executing statement pStmt.
*/
-SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt){
+SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt){
Vdbe *pVm = (Vdbe *)pStmt;
if( pVm==0 || pVm->pResultSet==0 ) return 0;
return pVm->nResColumn;
@@ -66988,11 +69810,22 @@ static const Mem *columnNullValue(void){
#if defined(SQLITE_DEBUG) && defined(__GNUC__)
__attribute__((aligned(8)))
#endif
- = {0, "", (double)0, {0}, 0, MEM_Null, 0,
+ = {
+ /* .u = */ {0},
+ /* .flags = */ MEM_Null,
+ /* .enc = */ 0,
+ /* .n = */ 0,
+ /* .z = */ 0,
+ /* .zMalloc = */ 0,
+ /* .szMalloc = */ 0,
+ /* .iPadding1 = */ 0,
+ /* .db = */ 0,
+ /* .xDel = */ 0,
#ifdef SQLITE_DEBUG
- 0, 0, /* pScopyFrom, pFiller */
+ /* .pScopyFrom = */ 0,
+ /* .pFiller = */ 0,
#endif
- 0, 0 };
+ };
return &nullMem;
}
@@ -67013,7 +69846,7 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
}else{
if( pVm && ALWAYS(pVm->db) ){
sqlite3_mutex_enter(pVm->db->mutex);
- sqlite3Error(pVm->db, SQLITE_RANGE, 0);
+ sqlite3Error(pVm->db, SQLITE_RANGE);
}
pOut = (Mem*)columnNullValue();
}
@@ -67056,7 +69889,7 @@ static void columnMallocFailure(sqlite3_stmt *pStmt)
** The following routines are used to access elements of the current row
** in the result set.
*/
-SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt *pStmt, int i){
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_blob(sqlite3_stmt *pStmt, int i){
const void *val;
val = sqlite3_value_blob( columnMem(pStmt,i) );
/* Even though there is no encoding conversion, value_blob() might
@@ -67066,37 +69899,37 @@ SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt *pStmt, int i){
columnMallocFailure(pStmt);
return val;
}
-SQLITE_API int sqlite3_column_bytes(sqlite3_stmt *pStmt, int i){
+SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes(sqlite3_stmt *pStmt, int i){
int val = sqlite3_value_bytes( columnMem(pStmt,i) );
columnMallocFailure(pStmt);
return val;
}
-SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt *pStmt, int i){
+SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes16(sqlite3_stmt *pStmt, int i){
int val = sqlite3_value_bytes16( columnMem(pStmt,i) );
columnMallocFailure(pStmt);
return val;
}
-SQLITE_API double sqlite3_column_double(sqlite3_stmt *pStmt, int i){
+SQLITE_API double SQLITE_STDCALL sqlite3_column_double(sqlite3_stmt *pStmt, int i){
double val = sqlite3_value_double( columnMem(pStmt,i) );
columnMallocFailure(pStmt);
return val;
}
-SQLITE_API int sqlite3_column_int(sqlite3_stmt *pStmt, int i){
+SQLITE_API int SQLITE_STDCALL sqlite3_column_int(sqlite3_stmt *pStmt, int i){
int val = sqlite3_value_int( columnMem(pStmt,i) );
columnMallocFailure(pStmt);
return val;
}
-SQLITE_API sqlite_int64 sqlite3_column_int64(sqlite3_stmt *pStmt, int i){
+SQLITE_API sqlite_int64 SQLITE_STDCALL sqlite3_column_int64(sqlite3_stmt *pStmt, int i){
sqlite_int64 val = sqlite3_value_int64( columnMem(pStmt,i) );
columnMallocFailure(pStmt);
return val;
}
-SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int i){
+SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_column_text(sqlite3_stmt *pStmt, int i){
const unsigned char *val = sqlite3_value_text( columnMem(pStmt,i) );
columnMallocFailure(pStmt);
return val;
}
-SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt *pStmt, int i){
+SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_column_value(sqlite3_stmt *pStmt, int i){
Mem *pOut = columnMem(pStmt, i);
if( pOut->flags&MEM_Static ){
pOut->flags &= ~MEM_Static;
@@ -67106,13 +69939,13 @@ SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt *pStmt, int i){
return (sqlite3_value *)pOut;
}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt *pStmt, int i){
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_text16(sqlite3_stmt *pStmt, int i){
const void *val = sqlite3_value_text16( columnMem(pStmt,i) );
columnMallocFailure(pStmt);
return val;
}
#endif /* SQLITE_OMIT_UTF16 */
-SQLITE_API int sqlite3_column_type(sqlite3_stmt *pStmt, int i){
+SQLITE_API int SQLITE_STDCALL sqlite3_column_type(sqlite3_stmt *pStmt, int i){
int iType = sqlite3_value_type( columnMem(pStmt,i) );
columnMallocFailure(pStmt);
return iType;
@@ -67140,11 +69973,19 @@ static const void *columnName(
const void *(*xFunc)(Mem*),
int useType
){
- const void *ret = 0;
- Vdbe *p = (Vdbe *)pStmt;
+ const void *ret;
+ Vdbe *p;
int n;
- sqlite3 *db = p->db;
-
+ sqlite3 *db;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pStmt==0 ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
+ ret = 0;
+ p = (Vdbe *)pStmt;
+ db = p->db;
assert( db!=0 );
n = sqlite3_column_count(pStmt);
if( N<n && N>=0 ){
@@ -67168,12 +70009,12 @@ static const void *columnName(
** Return the name of the Nth column of the result set returned by SQL
** statement pStmt.
*/
-SQLITE_API const char *sqlite3_column_name(sqlite3_stmt *pStmt, int N){
+SQLITE_API const char *SQLITE_STDCALL sqlite3_column_name(sqlite3_stmt *pStmt, int N){
return columnName(
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_NAME);
}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt *pStmt, int N){
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_name16(sqlite3_stmt *pStmt, int N){
return columnName(
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_NAME);
}
@@ -67193,12 +70034,12 @@ SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt *pStmt, int N){
** Return the column declaration type (if applicable) of the 'i'th column
** of the result set of SQL statement pStmt.
*/
-SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){
+SQLITE_API const char *SQLITE_STDCALL sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){
return columnName(
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_DECLTYPE);
}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){
return columnName(
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_DECLTYPE);
}
@@ -67209,14 +70050,14 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){
/*
** Return the name of the database from which a result column derives.
** NULL is returned if the result column is an expression or constant or
-** anything else which is not an unabiguous reference to a database column.
+** anything else which is not an unambiguous reference to a database column.
*/
-SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt *pStmt, int N){
+SQLITE_API const char *SQLITE_STDCALL sqlite3_column_database_name(sqlite3_stmt *pStmt, int N){
return columnName(
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_DATABASE);
}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N){
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N){
return columnName(
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_DATABASE);
}
@@ -67225,14 +70066,14 @@ SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N
/*
** Return the name of the table from which a result column derives.
** NULL is returned if the result column is an expression or constant or
-** anything else which is not an unabiguous reference to a database column.
+** anything else which is not an unambiguous reference to a database column.
*/
-SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt *pStmt, int N){
+SQLITE_API const char *SQLITE_STDCALL sqlite3_column_table_name(sqlite3_stmt *pStmt, int N){
return columnName(
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_TABLE);
}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){
return columnName(
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_TABLE);
}
@@ -67241,14 +70082,14 @@ SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){
/*
** Return the name of the table column from which a result column derives.
** NULL is returned if the result column is an expression or constant or
-** anything else which is not an unabiguous reference to a database column.
+** anything else which is not an unambiguous reference to a database column.
*/
-SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt *pStmt, int N){
+SQLITE_API const char *SQLITE_STDCALL sqlite3_column_origin_name(sqlite3_stmt *pStmt, int N){
return columnName(
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_COLUMN);
}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){
return columnName(
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_COLUMN);
}
@@ -67278,14 +70119,14 @@ static int vdbeUnbind(Vdbe *p, int i){
}
sqlite3_mutex_enter(p->db->mutex);
if( p->magic!=VDBE_MAGIC_RUN || p->pc>=0 ){
- sqlite3Error(p->db, SQLITE_MISUSE, 0);
+ sqlite3Error(p->db, SQLITE_MISUSE);
sqlite3_mutex_leave(p->db->mutex);
sqlite3_log(SQLITE_MISUSE,
"bind on a busy prepared statement: [%s]", p->zSql);
return SQLITE_MISUSE_BKPT;
}
if( i<1 || i>p->nVar ){
- sqlite3Error(p->db, SQLITE_RANGE, 0);
+ sqlite3Error(p->db, SQLITE_RANGE);
sqlite3_mutex_leave(p->db->mutex);
return SQLITE_RANGE;
}
@@ -67293,7 +70134,7 @@ static int vdbeUnbind(Vdbe *p, int i){
pVar = &p->aVar[i];
sqlite3VdbeMemRelease(pVar);
pVar->flags = MEM_Null;
- sqlite3Error(p->db, SQLITE_OK, 0);
+ sqlite3Error(p->db, SQLITE_OK);
/* If the bit corresponding to this variable in Vdbe.expmask is set, then
** binding a new value to this variable invalidates the current query plan.
@@ -67335,7 +70176,7 @@ static int bindText(
if( rc==SQLITE_OK && encoding!=0 ){
rc = sqlite3VdbeChangeEncoding(pVar, ENC(p->db));
}
- sqlite3Error(p->db, rc, 0);
+ sqlite3Error(p->db, rc);
rc = sqlite3ApiExit(p->db, rc);
}
sqlite3_mutex_leave(p->db->mutex);
@@ -67349,7 +70190,7 @@ static int bindText(
/*
** Bind a blob value to an SQL statement variable.
*/
-SQLITE_API int sqlite3_bind_blob(
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob(
sqlite3_stmt *pStmt,
int i,
const void *zData,
@@ -67358,7 +70199,21 @@ SQLITE_API int sqlite3_bind_blob(
){
return bindText(pStmt, i, zData, nData, xDel, 0);
}
-SQLITE_API int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob64(
+ sqlite3_stmt *pStmt,
+ int i,
+ const void *zData,
+ sqlite3_uint64 nData,
+ void (*xDel)(void*)
+){
+ assert( xDel!=SQLITE_DYNAMIC );
+ if( nData>0x7fffffff ){
+ return invokeValueDestructor(zData, xDel, 0);
+ }else{
+ return bindText(pStmt, i, zData, (int)nData, xDel, 0);
+ }
+}
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
int rc;
Vdbe *p = (Vdbe *)pStmt;
rc = vdbeUnbind(p, i);
@@ -67368,10 +70223,10 @@ SQLITE_API int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
}
return rc;
}
-SQLITE_API int sqlite3_bind_int(sqlite3_stmt *p, int i, int iValue){
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_int(sqlite3_stmt *p, int i, int iValue){
return sqlite3_bind_int64(p, i, (i64)iValue);
}
-SQLITE_API int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){
int rc;
Vdbe *p = (Vdbe *)pStmt;
rc = vdbeUnbind(p, i);
@@ -67381,7 +70236,7 @@ SQLITE_API int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValu
}
return rc;
}
-SQLITE_API int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_null(sqlite3_stmt *pStmt, int i){
int rc;
Vdbe *p = (Vdbe*)pStmt;
rc = vdbeUnbind(p, i);
@@ -67390,7 +70245,7 @@ SQLITE_API int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){
}
return rc;
}
-SQLITE_API int sqlite3_bind_text(
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_text(
sqlite3_stmt *pStmt,
int i,
const char *zData,
@@ -67399,8 +70254,24 @@ SQLITE_API int sqlite3_bind_text(
){
return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF8);
}
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_text64(
+ sqlite3_stmt *pStmt,
+ int i,
+ const char *zData,
+ sqlite3_uint64 nData,
+ void (*xDel)(void*),
+ unsigned char enc
+){
+ assert( xDel!=SQLITE_DYNAMIC );
+ if( nData>0x7fffffff ){
+ return invokeValueDestructor(zData, xDel, 0);
+ }else{
+ if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE;
+ return bindText(pStmt, i, zData, (int)nData, xDel, enc);
+ }
+}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API int sqlite3_bind_text16(
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_text16(
sqlite3_stmt *pStmt,
int i,
const void *zData,
@@ -67410,7 +70281,7 @@ SQLITE_API int sqlite3_bind_text16(
return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF16NATIVE);
}
#endif /* SQLITE_OMIT_UTF16 */
-SQLITE_API int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){
int rc;
switch( sqlite3_value_type((sqlite3_value*)pValue) ){
case SQLITE_INTEGER: {
@@ -67418,7 +70289,7 @@ SQLITE_API int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_valu
break;
}
case SQLITE_FLOAT: {
- rc = sqlite3_bind_double(pStmt, i, pValue->r);
+ rc = sqlite3_bind_double(pStmt, i, pValue->u.r);
break;
}
case SQLITE_BLOB: {
@@ -67441,7 +70312,7 @@ SQLITE_API int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_valu
}
return rc;
}
-SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){
int rc;
Vdbe *p = (Vdbe *)pStmt;
rc = vdbeUnbind(p, i);
@@ -67456,7 +70327,7 @@ SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){
** Return the number of wildcards that can be potentially bound to.
** This routine is added to support DBD::SQLite.
*/
-SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){
Vdbe *p = (Vdbe*)pStmt;
return p ? p->nVar : 0;
}
@@ -67467,7 +70338,7 @@ SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){
**
** The result is always UTF-8.
*/
-SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt *pStmt, int i){
+SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt *pStmt, int i){
Vdbe *p = (Vdbe*)pStmt;
if( p==0 || i<1 || i>p->nzVar ){
return 0;
@@ -67495,7 +70366,7 @@ SQLITE_PRIVATE int sqlite3VdbeParameterIndex(Vdbe *p, const char *zName, int nNa
}
return 0;
}
-SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt *pStmt, const char *zName){
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_index(sqlite3_stmt *pStmt, const char *zName){
return sqlite3VdbeParameterIndex((Vdbe*)pStmt, zName, sqlite3Strlen30(zName));
}
@@ -67521,7 +70392,7 @@ SQLITE_PRIVATE int sqlite3TransferBindings(sqlite3_stmt *pFromStmt, sqlite3_stmt
** Deprecated external interface. Internal/core SQLite code
** should call sqlite3TransferBindings.
**
-** Is is misuse to call this routine with statements from different
+** It is misuse to call this routine with statements from different
** database connections. But as this is a deprecated interface, we
** will not bother to check for that condition.
**
@@ -67529,7 +70400,7 @@ SQLITE_PRIVATE int sqlite3TransferBindings(sqlite3_stmt *pFromStmt, sqlite3_stmt
** an SQLITE_ERROR is returned. Nothing else can go wrong, so otherwise
** SQLITE_OK is returned.
*/
-SQLITE_API int sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){
+SQLITE_API int SQLITE_STDCALL sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){
Vdbe *pFrom = (Vdbe*)pFromStmt;
Vdbe *pTo = (Vdbe*)pToStmt;
if( pFrom->nVar!=pTo->nVar ){
@@ -67551,7 +70422,7 @@ SQLITE_API int sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *
** the first argument to the sqlite3_prepare() that was used to create
** the statement in the first place.
*/
-SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt *pStmt){
+SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_db_handle(sqlite3_stmt *pStmt){
return pStmt ? ((Vdbe*)pStmt)->db : 0;
}
@@ -67559,14 +70430,14 @@ SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt *pStmt){
** Return true if the prepared statement is guaranteed to not modify the
** database.
*/
-SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt){
+SQLITE_API int SQLITE_STDCALL sqlite3_stmt_readonly(sqlite3_stmt *pStmt){
return pStmt ? ((Vdbe*)pStmt)->readOnly : 1;
}
/*
** Return true if the prepared statement is in need of being reset.
*/
-SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt *pStmt){
+SQLITE_API int SQLITE_STDCALL sqlite3_stmt_busy(sqlite3_stmt *pStmt){
Vdbe *v = (Vdbe*)pStmt;
return v!=0 && v->pc>=0 && v->magic==VDBE_MAGIC_RUN;
}
@@ -67577,8 +70448,14 @@ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt *pStmt){
** prepared statement for the database connection. Return NULL if there
** are no more.
*/
-SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt){
+SQLITE_API sqlite3_stmt *SQLITE_STDCALL sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt){
sqlite3_stmt *pNext;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(pDb) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
sqlite3_mutex_enter(pDb->mutex);
if( pStmt==0 ){
pNext = (sqlite3_stmt*)pDb->pVdbe;
@@ -67592,13 +70469,89 @@ SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt){
/*
** Return the value of a status counter for a prepared statement
*/
-SQLITE_API int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){
+SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){
Vdbe *pVdbe = (Vdbe*)pStmt;
- u32 v = pVdbe->aCounter[op];
+ u32 v;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !pStmt ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
+ v = pVdbe->aCounter[op];
if( resetFlag ) pVdbe->aCounter[op] = 0;
return (int)v;
}
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+/*
+** Return status data for a single loop within query pStmt.
+*/
+SQLITE_API int SQLITE_STDCALL sqlite3_stmt_scanstatus(
+ sqlite3_stmt *pStmt, /* Prepared statement being queried */
+ int idx, /* Index of loop to report on */
+ int iScanStatusOp, /* Which metric to return */
+ void *pOut /* OUT: Write the answer here */
+){
+ Vdbe *p = (Vdbe*)pStmt;
+ ScanStatus *pScan;
+ if( idx<0 || idx>=p->nScan ) return 1;
+ pScan = &p->aScan[idx];
+ switch( iScanStatusOp ){
+ case SQLITE_SCANSTAT_NLOOP: {
+ *(sqlite3_int64*)pOut = p->anExec[pScan->addrLoop];
+ break;
+ }
+ case SQLITE_SCANSTAT_NVISIT: {
+ *(sqlite3_int64*)pOut = p->anExec[pScan->addrVisit];
+ break;
+ }
+ case SQLITE_SCANSTAT_EST: {
+ double r = 1.0;
+ LogEst x = pScan->nEst;
+ while( x<100 ){
+ x += 10;
+ r *= 0.5;
+ }
+ *(double*)pOut = r*sqlite3LogEstToInt(x);
+ break;
+ }
+ case SQLITE_SCANSTAT_NAME: {
+ *(const char**)pOut = pScan->zName;
+ break;
+ }
+ case SQLITE_SCANSTAT_EXPLAIN: {
+ if( pScan->addrExplain ){
+ *(const char**)pOut = p->aOp[ pScan->addrExplain ].p4.z;
+ }else{
+ *(const char**)pOut = 0;
+ }
+ break;
+ }
+ case SQLITE_SCANSTAT_SELECTID: {
+ if( pScan->addrExplain ){
+ *(int*)pOut = p->aOp[ pScan->addrExplain ].p1;
+ }else{
+ *(int*)pOut = -1;
+ }
+ break;
+ }
+ default: {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+** Zero all counters associated with the sqlite3_stmt_scanstatus() data.
+*/
+SQLITE_API void SQLITE_STDCALL sqlite3_stmt_scanstatus_reset(sqlite3_stmt *pStmt){
+ Vdbe *p = (Vdbe*)pStmt;
+ memset(p->anExec, 0, p->nOp * sizeof(i64));
+}
+#endif /* SQLITE_ENABLE_STMT_SCANSTATUS */
+
/************** End of vdbeapi.c *********************************************/
/************** Begin file vdbetrace.c ***************************************/
/*
@@ -67665,7 +70618,7 @@ static int findNextHostParameter(const char *zSql, int *pnToken){
** ALGORITHM: Scan the input string looking for host parameters in any of
** these forms: ?, ?N, $A, @A, :A. Take care to avoid text within
** string literals, quoted identifier names, and comments. For text forms,
-** the host parameter index is found by scanning the perpared
+** the host parameter index is found by scanning the prepared
** statement for the corresponding OP_Variable opcode. Once the host
** parameter index is known, locate the value in p->aVar[]. Then render
** the value as a literal in place of the host parameter name.
@@ -67685,9 +70638,8 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
char zBase[100]; /* Initial working space */
db = p->db;
- sqlite3StrAccumInit(&out, zBase, sizeof(zBase),
+ sqlite3StrAccumInit(&out, db, zBase, sizeof(zBase),
db->aLimit[SQLITE_LIMIT_LENGTH]);
- out.db = db;
if( db->nVdbeExec>1 ){
while( *zRawSql ){
const char *zStart = zRawSql;
@@ -67696,6 +70648,8 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
assert( (zRawSql - zStart) > 0 );
sqlite3StrAccumAppend(&out, zStart, (int)(zRawSql-zStart));
}
+ }else if( p->nVar==0 ){
+ sqlite3StrAccumAppend(&out, zRawSql, sqlite3Strlen30(zRawSql));
}else{
while( zRawSql[0] ){
n = findNextHostParameter(zRawSql, &nToken);
@@ -67712,10 +70666,12 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
idx = nextIndex;
}
}else{
- assert( zRawSql[0]==':' || zRawSql[0]=='$' || zRawSql[0]=='@' );
+ assert( zRawSql[0]==':' || zRawSql[0]=='$' ||
+ zRawSql[0]=='@' || zRawSql[0]=='#' );
testcase( zRawSql[0]==':' );
testcase( zRawSql[0]=='$' );
testcase( zRawSql[0]=='@' );
+ testcase( zRawSql[0]=='#' );
idx = sqlite3VdbeParameterIndex(p, zRawSql, nToken);
assert( idx>0 );
}
@@ -67728,7 +70684,7 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
}else if( pVar->flags & MEM_Int ){
sqlite3XPrintf(&out, 0, "%lld", pVar->u.i);
}else if( pVar->flags & MEM_Real ){
- sqlite3XPrintf(&out, 0, "%!.15g", pVar->r);
+ sqlite3XPrintf(&out, 0, "%!.15g", pVar->u.r);
}else if( pVar->flags & MEM_Str ){
int nOut; /* Number of bytes of the string text to include in output */
#ifndef SQLITE_OMIT_UTF16
@@ -67785,121 +70741,6 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
#endif /* #ifndef SQLITE_OMIT_TRACE */
-/*****************************************************************************
-** The following code implements the data-structure explaining logic
-** for the Vdbe.
-*/
-
-#if defined(SQLITE_ENABLE_TREE_EXPLAIN)
-
-/*
-** Allocate a new Explain object
-*/
-SQLITE_PRIVATE void sqlite3ExplainBegin(Vdbe *pVdbe){
- if( pVdbe ){
- Explain *p;
- sqlite3BeginBenignMalloc();
- p = (Explain *)sqlite3MallocZero( sizeof(Explain) );
- if( p ){
- p->pVdbe = pVdbe;
- sqlite3_free(pVdbe->pExplain);
- pVdbe->pExplain = p;
- sqlite3StrAccumInit(&p->str, p->zBase, sizeof(p->zBase),
- SQLITE_MAX_LENGTH);
- p->str.useMalloc = 2;
- }else{
- sqlite3EndBenignMalloc();
- }
- }
-}
-
-/*
-** Return true if the Explain ends with a new-line.
-*/
-static int endsWithNL(Explain *p){
- return p && p->str.zText && p->str.nChar
- && p->str.zText[p->str.nChar-1]=='\n';
-}
-
-/*
-** Append text to the indentation
-*/
-SQLITE_PRIVATE void sqlite3ExplainPrintf(Vdbe *pVdbe, const char *zFormat, ...){
- Explain *p;
- if( pVdbe && (p = pVdbe->pExplain)!=0 ){
- va_list ap;
- if( p->nIndent && endsWithNL(p) ){
- int n = p->nIndent;
- if( n>ArraySize(p->aIndent) ) n = ArraySize(p->aIndent);
- sqlite3AppendSpace(&p->str, p->aIndent[n-1]);
- }
- va_start(ap, zFormat);
- sqlite3VXPrintf(&p->str, SQLITE_PRINTF_INTERNAL, zFormat, ap);
- va_end(ap);
- }
-}
-
-/*
-** Append a '\n' if there is not already one.
-*/
-SQLITE_PRIVATE void sqlite3ExplainNL(Vdbe *pVdbe){
- Explain *p;
- if( pVdbe && (p = pVdbe->pExplain)!=0 && !endsWithNL(p) ){
- sqlite3StrAccumAppend(&p->str, "\n", 1);
- }
-}
-
-/*
-** Push a new indentation level. Subsequent lines will be indented
-** so that they begin at the current cursor position.
-*/
-SQLITE_PRIVATE void sqlite3ExplainPush(Vdbe *pVdbe){
- Explain *p;
- if( pVdbe && (p = pVdbe->pExplain)!=0 ){
- if( p->str.zText && p->nIndent<ArraySize(p->aIndent) ){
- const char *z = p->str.zText;
- int i = p->str.nChar-1;
- int x;
- while( i>=0 && z[i]!='\n' ){ i--; }
- x = (p->str.nChar - 1) - i;
- if( p->nIndent && x<p->aIndent[p->nIndent-1] ){
- x = p->aIndent[p->nIndent-1];
- }
- p->aIndent[p->nIndent] = x;
- }
- p->nIndent++;
- }
-}
-
-/*
-** Pop the indentation stack by one level.
-*/
-SQLITE_PRIVATE void sqlite3ExplainPop(Vdbe *p){
- if( p && p->pExplain ) p->pExplain->nIndent--;
-}
-
-/*
-** Free the indentation structure
-*/
-SQLITE_PRIVATE void sqlite3ExplainFinish(Vdbe *pVdbe){
- if( pVdbe && pVdbe->pExplain ){
- sqlite3_free(pVdbe->zExplain);
- sqlite3ExplainNL(pVdbe);
- pVdbe->zExplain = sqlite3StrAccumFinish(&pVdbe->pExplain->str);
- sqlite3_free(pVdbe->pExplain);
- pVdbe->pExplain = 0;
- sqlite3EndBenignMalloc();
- }
-}
-
-/*
-** Return the explanation of a virtual machine.
-*/
-SQLITE_PRIVATE const char *sqlite3VdbeExplanation(Vdbe *pVdbe){
- return (pVdbe && pVdbe->zExplain) ? pVdbe->zExplain : 0;
-}
-#endif /* defined(SQLITE_DEBUG) */
-
/************** End of vdbetrace.c *******************************************/
/************** Begin file vdbe.c ********************************************/
/*
@@ -68048,7 +70889,7 @@ SQLITE_API int sqlite3_found_count = 0;
** already. Return non-zero if a malloc() fails.
*/
#define Stringify(P, enc) \
- if(((P)->flags&(MEM_Str|MEM_Blob))==0 && sqlite3VdbeMemStringify(P,enc)) \
+ if(((P)->flags&(MEM_Str|MEM_Blob))==0 && sqlite3VdbeMemStringify(P,enc,0)) \
{ goto no_mem; }
/*
@@ -68111,11 +70952,12 @@ static VdbeCursor *allocateCursor(
sqlite3VdbeFreeCursor(p, p->apCsr[iCur]);
p->apCsr[iCur] = 0;
}
- if( SQLITE_OK==sqlite3VdbeMemGrow(pMem, nByte, 0) ){
+ if( SQLITE_OK==sqlite3VdbeMemClearAndResize(pMem, nByte) ){
p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->z;
memset(pCx, 0, sizeof(VdbeCursor));
pCx->iDb = iDb;
pCx->nField = nField;
+ pCx->aOffset = &pCx->aType[nField];
if( isBtreeCursor ){
pCx->pCursor = (BtCursor*)
&pMem->z[ROUND8(sizeof(VdbeCursor))+2*sizeof(u32)*nField];
@@ -68130,23 +70972,31 @@ static VdbeCursor *allocateCursor(
** do so without loss of information. In other words, if the string
** looks like a number, convert it into a number. If it does not
** look like a number, leave it alone.
+**
+** If the bTryForInt flag is true, then extra effort is made to give
+** an integer representation. Strings that look like floating point
+** values but which have no fractional component (example: '48.00')
+** will have a MEM_Int representation when bTryForInt is true.
+**
+** If bTryForInt is false, then if the input string contains a decimal
+** point or exponential notation, the result is only MEM_Real, even
+** if there is an exact integer representation of the quantity.
*/
-static void applyNumericAffinity(Mem *pRec){
+static void applyNumericAffinity(Mem *pRec, int bTryForInt){
double rValue;
i64 iValue;
u8 enc = pRec->enc;
- if( (pRec->flags&MEM_Str)==0 ) return;
+ assert( (pRec->flags & (MEM_Str|MEM_Int|MEM_Real))==MEM_Str );
if( sqlite3AtoF(pRec->z, &rValue, pRec->n, enc)==0 ) return;
if( 0==sqlite3Atoi64(pRec->z, &iValue, pRec->n, enc) ){
pRec->u.i = iValue;
pRec->flags |= MEM_Int;
}else{
- pRec->r = rValue;
+ pRec->u.r = rValue;
pRec->flags |= MEM_Real;
+ if( bTryForInt ) sqlite3VdbeIntegerAffinity(pRec);
}
}
-#define ApplyNumericAffinity(X) \
- if(((X)->flags&(MEM_Real|MEM_Int))==0){applyNumericAffinity(X);}
/*
** Processing is determine by the affinity parameter:
@@ -68171,22 +71021,25 @@ static void applyAffinity(
char affinity, /* The affinity to be applied */
u8 enc /* Use this text encoding */
){
- if( affinity==SQLITE_AFF_TEXT ){
+ if( affinity>=SQLITE_AFF_NUMERIC ){
+ assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL
+ || affinity==SQLITE_AFF_NUMERIC );
+ if( (pRec->flags & MEM_Int)==0 ){
+ if( (pRec->flags & MEM_Real)==0 ){
+ if( pRec->flags & MEM_Str ) applyNumericAffinity(pRec,1);
+ }else{
+ sqlite3VdbeIntegerAffinity(pRec);
+ }
+ }
+ }else if( affinity==SQLITE_AFF_TEXT ){
/* Only attempt the conversion to TEXT if there is an integer or real
** representation (blob and NULL do not get converted) but no string
** representation.
*/
if( 0==(pRec->flags&MEM_Str) && (pRec->flags&(MEM_Real|MEM_Int)) ){
- sqlite3VdbeMemStringify(pRec, enc);
+ sqlite3VdbeMemStringify(pRec, enc, 1);
}
pRec->flags &= ~(MEM_Real|MEM_Int);
- }else if( affinity!=SQLITE_AFF_NONE ){
- assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL
- || affinity==SQLITE_AFF_NUMERIC );
- ApplyNumericAffinity(pRec);
- if( pRec->flags & MEM_Real ){
- sqlite3VdbeIntegerAffinity(pRec);
- }
}
}
@@ -68196,11 +71049,11 @@ static void applyAffinity(
** is appropriate. But only do the conversion if it is possible without
** loss of information and return the revised type of the argument.
*/
-SQLITE_API int sqlite3_value_numeric_type(sqlite3_value *pVal){
+SQLITE_API int SQLITE_STDCALL sqlite3_value_numeric_type(sqlite3_value *pVal){
int eType = sqlite3_value_type(pVal);
if( eType==SQLITE_TEXT ){
Mem *pMem = (Mem*)pVal;
- applyNumericAffinity(pMem);
+ applyNumericAffinity(pMem, 0);
eType = sqlite3_value_type(pVal);
}
return eType;
@@ -68219,24 +71072,36 @@ SQLITE_PRIVATE void sqlite3ValueApplyAffinity(
}
/*
+** pMem currently only holds a string type (or maybe a BLOB that we can
+** interpret as a string if we want to). Compute its corresponding
+** numeric type, if has one. Set the pMem->u.r and pMem->u.i fields
+** accordingly.
+*/
+static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){
+ assert( (pMem->flags & (MEM_Int|MEM_Real))==0 );
+ assert( (pMem->flags & (MEM_Str|MEM_Blob))!=0 );
+ if( sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc)==0 ){
+ return 0;
+ }
+ if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==SQLITE_OK ){
+ return MEM_Int;
+ }
+ return MEM_Real;
+}
+
+/*
** Return the numeric type for pMem, either MEM_Int or MEM_Real or both or
** none.
**
** Unlike applyNumericAffinity(), this routine does not modify pMem->flags.
-** But it does set pMem->r and pMem->u.i appropriately.
+** But it does set pMem->u.r and pMem->u.i appropriately.
*/
static u16 numericType(Mem *pMem){
if( pMem->flags & (MEM_Int|MEM_Real) ){
return pMem->flags & (MEM_Int|MEM_Real);
}
if( pMem->flags & (MEM_Str|MEM_Blob) ){
- if( sqlite3AtoF(pMem->z, &pMem->r, pMem->n, pMem->enc)==0 ){
- return 0;
- }
- if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==SQLITE_OK ){
- return MEM_Int;
- }
- return MEM_Real;
+ return computeNumericType(pMem);
}
return 0;
}
@@ -68339,7 +71204,7 @@ static void memTracePrint(Mem *p){
printf(" i:%lld", p->u.i);
#ifndef SQLITE_OMIT_FLOATING_POINT
}else if( p->flags & MEM_Real ){
- printf(" r:%g", p->r);
+ printf(" r:%g", p->u.r);
#endif
}else if( p->flags & MEM_RowSet ){
printf(" (rowset)");
@@ -68482,6 +71347,21 @@ static int checkSavepointCount(sqlite3 *db){
}
#endif
+/*
+** Return the register of pOp->p2 after first preparing it to be
+** overwritten with an integer value.
+*/
+static Mem *out2Prerelease(Vdbe *p, VdbeOp *pOp){
+ Mem *pOut;
+ assert( pOp->p2>0 );
+ assert( pOp->p2<=(p->nMem-p->nCursor) );
+ pOut = &p->aMem[pOp->p2];
+ memAboutToChange(p, pOut);
+ if( VdbeMemDynamic(pOut) ) sqlite3VdbeMemSetNull(pOut);
+ pOut->flags = MEM_Int;
+ return pOut;
+}
+
/*
** Execute as much of a VDBE program as we can.
@@ -68490,9 +71370,11 @@ static int checkSavepointCount(sqlite3 *db){
SQLITE_PRIVATE int sqlite3VdbeExec(
Vdbe *p /* The VDBE */
){
- int pc=0; /* The program counter */
Op *aOp = p->aOp; /* Copy of p->aOp */
- Op *pOp; /* Current operation */
+ Op *pOp = aOp; /* Current operation */
+#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
+ Op *pOrigOp; /* Value of pOp at the top of the loop */
+#endif
int rc = SQLITE_OK; /* Value to return */
sqlite3 *db = p->db; /* The database */
u8 resetSchemaOnFault = 0; /* Reset schema after an error if positive */
@@ -68568,20 +71450,22 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
}
sqlite3EndBenignMalloc();
#endif
- for(pc=p->pc; rc==SQLITE_OK; pc++){
- assert( pc>=0 && pc<p->nOp );
+ for(pOp=&aOp[p->pc]; rc==SQLITE_OK; pOp++){
+ assert( pOp>=aOp && pOp<&aOp[p->nOp]);
if( db->mallocFailed ) goto no_mem;
#ifdef VDBE_PROFILE
start = sqlite3Hwtime();
#endif
nVmStep++;
- pOp = &aOp[pc];
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ if( p->anExec ) p->anExec[(int)(pOp-aOp)]++;
+#endif
/* Only allow tracing if SQLITE_DEBUG is defined.
*/
#ifdef SQLITE_DEBUG
if( db->flags & SQLITE_VdbeTrace ){
- sqlite3VdbePrintOp(stdout, pc, pOp);
+ sqlite3VdbePrintOp(stdout, (int)(pOp - aOp), pOp);
}
#endif
@@ -68598,23 +71482,9 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
}
#endif
- /* On any opcode with the "out2-prerelease" tag, free any
- ** external allocations out of mem[p2] and set mem[p2] to be
- ** an undefined integer. Opcodes will either fill in the integer
- ** value or convert mem[p2] to a different type.
- */
- assert( pOp->opflags==sqlite3OpcodeProperty[pOp->opcode] );
- if( pOp->opflags & OPFLG_OUT2_PRERELEASE ){
- assert( pOp->p2>0 );
- assert( pOp->p2<=(p->nMem-p->nCursor) );
- pOut = &aMem[pOp->p2];
- memAboutToChange(p, pOut);
- VdbeMemRelease(pOut);
- pOut->flags = MEM_Int;
- }
-
/* Sanity checking on other operands */
#ifdef SQLITE_DEBUG
+ assert( pOp->opflags==sqlite3OpcodeProperty[pOp->opcode] );
if( (pOp->opflags & OPFLG_IN1)!=0 ){
assert( pOp->p1>0 );
assert( pOp->p1<=(p->nMem-p->nCursor) );
@@ -68647,6 +71517,9 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
memAboutToChange(p, &aMem[pOp->p3]);
}
#endif
+#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
+ pOrigOp = pOp;
+#endif
switch( pOp->opcode ){
@@ -68670,7 +71543,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
**
** Other keywords in the comment that follows each case are used to
** construct the OPFLG_INITIALIZER value that initializes opcodeProperty[].
-** Keywords include: in1, in2, in3, out2_prerelease, out2, out3. See
+** Keywords include: in1, in2, in3, out2, out3. See
** the mkopcodeh.awk script for additional information.
**
** Documentation about VDBE opcodes is generated by scanning this file
@@ -68698,7 +71571,8 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
** to the current line should be indented for EXPLAIN output.
*/
case OP_Goto: { /* jump */
- pc = pOp->p2 - 1;
+jump_to_p2_and_check_for_interrupt:
+ pOp = &aOp[pOp->p2 - 1];
/* Opcodes that are used as the bottom of a loop (OP_Next, OP_Prev,
** OP_VNext, OP_RowSetNext, or OP_SorterNext) all jump here upon
@@ -68743,9 +71617,13 @@ case OP_Gosub: { /* jump */
assert( VdbeMemDynamic(pIn1)==0 );
memAboutToChange(p, pIn1);
pIn1->flags = MEM_Int;
- pIn1->u.i = pc;
+ pIn1->u.i = (int)(pOp-aOp);
REGISTER_TRACE(pOp->p1, pIn1);
- pc = pOp->p2 - 1;
+
+ /* Most jump operations do a goto to this spot in order to update
+ ** the pOp pointer. */
+jump_to_p2:
+ pOp = &aOp[pOp->p2 - 1];
break;
}
@@ -68757,7 +71635,7 @@ case OP_Gosub: { /* jump */
case OP_Return: { /* in1 */
pIn1 = &aMem[pOp->p1];
assert( pIn1->flags==MEM_Int );
- pc = (int)pIn1->u.i;
+ pOp = &aOp[pIn1->u.i];
pIn1->flags = MEM_Undefined;
break;
}
@@ -68781,7 +71659,7 @@ case OP_InitCoroutine: { /* jump */
assert( !VdbeMemDynamic(pOut) );
pOut->u.i = pOp->p3 - 1;
pOut->flags = MEM_Int;
- if( pOp->p2 ) pc = pOp->p2 - 1;
+ if( pOp->p2 ) goto jump_to_p2;
break;
}
@@ -68801,7 +71679,7 @@ case OP_EndCoroutine: { /* in1 */
pCaller = &aOp[pIn1->u.i];
assert( pCaller->opcode==OP_Yield );
assert( pCaller->p2>=0 && pCaller->p2<p->nOp );
- pc = pCaller->p2 - 1;
+ pOp = &aOp[pCaller->p2 - 1];
pIn1->flags = MEM_Undefined;
break;
}
@@ -68825,9 +71703,9 @@ case OP_Yield: { /* in1, jump */
assert( VdbeMemDynamic(pIn1)==0 );
pIn1->flags = MEM_Int;
pcDest = (int)pIn1->u.i;
- pIn1->u.i = pc;
+ pIn1->u.i = (int)(pOp - aOp);
REGISTER_TRACE(pOp->p1, pIn1);
- pc = pcDest;
+ pOp = &aOp[pcDest];
break;
}
@@ -68878,30 +71756,34 @@ case OP_HaltIfNull: { /* in3 */
case OP_Halt: {
const char *zType;
const char *zLogFmt;
+ VdbeFrame *pFrame;
+ int pcx;
+ pcx = (int)(pOp - aOp);
if( pOp->p1==SQLITE_OK && p->pFrame ){
/* Halt the sub-program. Return control to the parent frame. */
- VdbeFrame *pFrame = p->pFrame;
+ pFrame = p->pFrame;
p->pFrame = pFrame->pParent;
p->nFrame--;
sqlite3VdbeSetChanges(db, p->nChange);
- pc = sqlite3VdbeFrameRestore(pFrame);
+ pcx = sqlite3VdbeFrameRestore(pFrame);
lastRowid = db->lastRowid;
if( pOp->p2==OE_Ignore ){
- /* Instruction pc is the OP_Program that invoked the sub-program
+ /* Instruction pcx is the OP_Program that invoked the sub-program
** currently being halted. If the p2 instruction of this OP_Halt
** instruction is set to OE_Ignore, then the sub-program is throwing
** an IGNORE exception. In this case jump to the address specified
** as the p2 of the calling OP_Program. */
- pc = p->aOp[pc].p2-1;
+ pcx = p->aOp[pcx].p2-1;
}
aOp = p->aOp;
aMem = p->aMem;
+ pOp = &aOp[pcx];
break;
}
p->rc = pOp->p1;
p->errorAction = (u8)pOp->p2;
- p->pc = pc;
+ p->pc = pcx;
if( p->rc ){
if( pOp->p5 ){
static const char * const azType[] = { "NOT NULL", "UNIQUE", "CHECK",
@@ -68925,7 +71807,7 @@ case OP_Halt: {
}else{
sqlite3SetString(&p->zErrMsg, db, "%s constraint failed", zType);
}
- sqlite3_log(pOp->p1, zLogFmt, pc, p->zSql, p->zErrMsg);
+ sqlite3_log(pOp->p1, zLogFmt, pcx, p->zSql, p->zErrMsg);
}
rc = sqlite3VdbeHalt(p);
assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR );
@@ -68944,7 +71826,8 @@ case OP_Halt: {
**
** The 32-bit integer value P1 is written into register P2.
*/
-case OP_Integer: { /* out2-prerelease */
+case OP_Integer: { /* out2 */
+ pOut = out2Prerelease(p, pOp);
pOut->u.i = pOp->p1;
break;
}
@@ -68955,7 +71838,8 @@ case OP_Integer: { /* out2-prerelease */
** P4 is a pointer to a 64-bit integer value.
** Write that value into register P2.
*/
-case OP_Int64: { /* out2-prerelease */
+case OP_Int64: { /* out2 */
+ pOut = out2Prerelease(p, pOp);
assert( pOp->p4.pI64!=0 );
pOut->u.i = *pOp->p4.pI64;
break;
@@ -68968,10 +71852,11 @@ case OP_Int64: { /* out2-prerelease */
** P4 is a pointer to a 64-bit floating point value.
** Write that value into register P2.
*/
-case OP_Real: { /* same as TK_FLOAT, out2-prerelease */
+case OP_Real: { /* same as TK_FLOAT, out2 */
+ pOut = out2Prerelease(p, pOp);
pOut->flags = MEM_Real;
assert( !sqlite3IsNaN(*pOp->p4.pReal) );
- pOut->r = *pOp->p4.pReal;
+ pOut->u.r = *pOp->p4.pReal;
break;
}
#endif
@@ -68980,12 +71865,13 @@ case OP_Real: { /* same as TK_FLOAT, out2-prerelease */
** Synopsis: r[P2]='P4'
**
** P4 points to a nul terminated UTF-8 string. This opcode is transformed
-** into a String before it is executed for the first time. During
+** into a String opcode before it is executed for the first time. During
** this transformation, the length of string P4 is computed and stored
** as the P1 parameter.
*/
-case OP_String8: { /* same as TK_STRING, out2-prerelease */
+case OP_String8: { /* same as TK_STRING, out2 */
assert( pOp->p4.z!=0 );
+ pOut = out2Prerelease(p, pOp);
pOp->opcode = OP_String;
pOp->p1 = sqlite3Strlen30(pOp->p4.z);
@@ -68994,9 +71880,9 @@ case OP_String8: { /* same as TK_STRING, out2-prerelease */
rc = sqlite3VdbeMemSetStr(pOut, pOp->p4.z, -1, SQLITE_UTF8, SQLITE_STATIC);
if( rc==SQLITE_TOOBIG ) goto too_big;
if( SQLITE_OK!=sqlite3VdbeChangeEncoding(pOut, encoding) ) goto no_mem;
- assert( pOut->zMalloc==pOut->z );
+ assert( pOut->szMalloc>0 && pOut->zMalloc==pOut->z );
assert( VdbeMemDynamic(pOut)==0 );
- pOut->zMalloc = 0;
+ pOut->szMalloc = 0;
pOut->flags |= MEM_Static;
if( pOp->p4type==P4_DYNAMIC ){
sqlite3DbFree(db, pOp->p4.z);
@@ -69012,18 +71898,31 @@ case OP_String8: { /* same as TK_STRING, out2-prerelease */
/* Fall through to the next case, OP_String */
}
-/* Opcode: String P1 P2 * P4 *
+/* Opcode: String P1 P2 P3 P4 P5
** Synopsis: r[P2]='P4' (len=P1)
**
** The string value P4 of length P1 (bytes) is stored in register P2.
+**
+** If P5!=0 and the content of register P3 is greater than zero, then
+** the datatype of the register P2 is converted to BLOB. The content is
+** the same sequence of bytes, it is merely interpreted as a BLOB instead
+** of a string, as if it had been CAST.
*/
-case OP_String: { /* out2-prerelease */
+case OP_String: { /* out2 */
assert( pOp->p4.z!=0 );
+ pOut = out2Prerelease(p, pOp);
pOut->flags = MEM_Str|MEM_Static|MEM_Term;
pOut->z = pOp->p4.z;
pOut->n = pOp->p1;
pOut->enc = encoding;
UPDATE_MAX_BLOBSIZE(pOut);
+ if( pOp->p5 ){
+ assert( pOp->p3>0 );
+ assert( pOp->p3<=(p->nMem-p->nCursor) );
+ pIn3 = &aMem[pOp->p3];
+ assert( pIn3->flags & MEM_Int );
+ if( pIn3->u.i ) pOut->flags = MEM_Blob|MEM_Static|MEM_Term;
+ }
break;
}
@@ -69039,16 +71938,17 @@ case OP_String: { /* out2-prerelease */
** NULL values will not compare equal even if SQLITE_NULLEQ is set on
** OP_Ne or OP_Eq.
*/
-case OP_Null: { /* out2-prerelease */
+case OP_Null: { /* out2 */
int cnt;
u16 nullFlag;
+ pOut = out2Prerelease(p, pOp);
cnt = pOp->p3-pOp->p2;
assert( pOp->p3<=(p->nMem-p->nCursor) );
pOut->flags = nullFlag = pOp->p1 ? (MEM_Null|MEM_Cleared) : MEM_Null;
while( cnt>0 ){
pOut++;
memAboutToChange(p, pOut);
- VdbeMemRelease(pOut);
+ sqlite3VdbeMemSetNull(pOut);
pOut->flags = nullFlag;
cnt--;
}
@@ -69076,8 +71976,9 @@ case OP_SoftNull: {
** P4 points to a blob of data P1 bytes long. Store this
** blob in register P2.
*/
-case OP_Blob: { /* out2-prerelease */
+case OP_Blob: { /* out2 */
assert( pOp->p1 <= SQLITE_MAX_LENGTH );
+ pOut = out2Prerelease(p, pOp);
sqlite3VdbeMemSetStr(pOut, pOp->p4.z, pOp->p1, 0, 0);
pOut->enc = encoding;
UPDATE_MAX_BLOBSIZE(pOut);
@@ -69092,7 +71993,7 @@ case OP_Blob: { /* out2-prerelease */
** If the parameter is named, then its name appears in P4.
** The P4 value is used by sqlite3_bind_parameter_name().
*/
-case OP_Variable: { /* out2-prerelease */
+case OP_Variable: { /* out2 */
Mem *pVar; /* Value being transferred */
assert( pOp->p1>0 && pOp->p1<=p->nVar );
@@ -69101,6 +72002,7 @@ case OP_Variable: { /* out2-prerelease */
if( sqlite3VdbeMemTooBig(pVar) ){
goto too_big;
}
+ pOut = out2Prerelease(p, pOp);
sqlite3VdbeMemShallowCopy(pOut, pVar, MEM_Static);
UPDATE_MAX_BLOBSIZE(pOut);
break;
@@ -69116,7 +72018,6 @@ case OP_Variable: { /* out2-prerelease */
** for P3 to be less than 1.
*/
case OP_Move: {
- char *zMalloc; /* Holding variable for allocated memory */
int n; /* Number of registers left to copy */
int p1; /* Register to copy from */
int p2; /* Register to copy to */
@@ -69134,17 +72035,13 @@ case OP_Move: {
assert( pIn1<=&aMem[(p->nMem-p->nCursor)] );
assert( memIsValid(pIn1) );
memAboutToChange(p, pOut);
- VdbeMemRelease(pOut);
- zMalloc = pOut->zMalloc;
- memcpy(pOut, pIn1, sizeof(Mem));
+ sqlite3VdbeMemMove(pOut, pIn1);
#ifdef SQLITE_DEBUG
- if( pOut->pScopyFrom>=&aMem[p1] && pOut->pScopyFrom<&aMem[p1+pOp->p3] ){
- pOut->pScopyFrom += p1 - pOp->p2;
+ if( pOut->pScopyFrom>=&aMem[p1] && pOut->pScopyFrom<pOut ){
+ pOut->pScopyFrom += pOp->p2 - p1;
}
#endif
- pIn1->flags = MEM_Undefined;
- pIn1->xDel = 0;
- pIn1->zMalloc = zMalloc;
+ Deephemeralize(pOut);
REGISTER_TRACE(p2++, pOut);
pIn1++;
pOut++;
@@ -69283,7 +72180,7 @@ case OP_ResultRow: {
/* Return SQLITE_ROW
*/
- p->pc = pc + 1;
+ p->pc = (int)(pOp - aOp) + 1;
rc = SQLITE_ROW;
goto vdbe_return;
}
@@ -69449,7 +72346,7 @@ fp_math:
if( sqlite3IsNaN(rB) ){
goto arithmetic_result_is_null;
}
- pOut->r = rB;
+ pOut->u.r = rB;
MemSetTypeFlag(pOut, MEM_Real);
if( ((type1|type2)&MEM_Real)==0 && !bIntint ){
sqlite3VdbeIntegerAffinity(pOut);
@@ -69476,7 +72373,7 @@ arithmetic_result_is_null:
**
** The interface used by the implementation of the aforementioned functions
** to retrieve the collation sequence set by this opcode is not available
-** publicly, only to user functions defined in func.c.
+** publicly. Only built-in functions have access to this feature.
*/
case OP_CollSeq: {
assert( pOp->p4type==P4_COLLSEQ );
@@ -69514,8 +72411,8 @@ case OP_Function: {
apVal = p->apArg;
assert( apVal || n==0 );
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
- pOut = &aMem[pOp->p3];
- memAboutToChange(p, pOut);
+ ctx.pOut = &aMem[pOp->p3];
+ memAboutToChange(p, ctx.pOut);
assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem-p->nCursor)+1) );
assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
@@ -69529,67 +72426,31 @@ case OP_Function: {
assert( pOp->p4type==P4_FUNCDEF );
ctx.pFunc = pOp->p4.pFunc;
- ctx.iOp = pc;
+ ctx.iOp = (int)(pOp - aOp);
ctx.pVdbe = p;
-
- /* The output cell may already have a buffer allocated. Move
- ** the pointer to ctx.s so in case the user-function can use
- ** the already allocated buffer instead of allocating a new one.
- */
- memcpy(&ctx.s, pOut, sizeof(Mem));
- pOut->flags = MEM_Null;
- pOut->xDel = 0;
- pOut->zMalloc = 0;
- MemSetTypeFlag(&ctx.s, MEM_Null);
-
+ MemSetTypeFlag(ctx.pOut, MEM_Null);
ctx.fErrorOrAux = 0;
- if( ctx.pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){
- assert( pOp>aOp );
- assert( pOp[-1].p4type==P4_COLLSEQ );
- assert( pOp[-1].opcode==OP_CollSeq );
- ctx.pColl = pOp[-1].p4.pColl;
- }
db->lastRowid = lastRowid;
(*ctx.pFunc->xFunc)(&ctx, n, apVal); /* IMP: R-24505-23230 */
- lastRowid = db->lastRowid;
-
- if( db->mallocFailed ){
- /* Even though a malloc() has failed, the implementation of the
- ** user function may have called an sqlite3_result_XXX() function
- ** to return a value. The following call releases any resources
- ** associated with such a value.
- */
- sqlite3VdbeMemRelease(&ctx.s);
- goto no_mem;
- }
+ lastRowid = db->lastRowid; /* Remember rowid changes made by xFunc */
/* If the function returned an error, throw an exception */
if( ctx.fErrorOrAux ){
if( ctx.isError ){
- sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&ctx.s));
+ sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(ctx.pOut));
rc = ctx.isError;
}
- sqlite3VdbeDeleteAuxData(p, pc, pOp->p1);
+ sqlite3VdbeDeleteAuxData(p, (int)(pOp - aOp), pOp->p1);
}
/* Copy the result of the function into register P3 */
- sqlite3VdbeChangeEncoding(&ctx.s, encoding);
- assert( pOut->flags==MEM_Null );
- memcpy(pOut, &ctx.s, sizeof(Mem));
- if( sqlite3VdbeMemTooBig(pOut) ){
+ sqlite3VdbeChangeEncoding(ctx.pOut, encoding);
+ if( sqlite3VdbeMemTooBig(ctx.pOut) ){
goto too_big;
}
-#if 0
- /* The app-defined function has done something that as caused this
- ** statement to expire. (Perhaps the function called sqlite3_exec()
- ** with a CREATE TABLE statement.)
- */
- if( p->expired ) rc = SQLITE_ABORT;
-#endif
-
- REGISTER_TRACE(pOp->p3, pOut);
- UPDATE_MAX_BLOBSIZE(pOut);
+ REGISTER_TRACE(pOp->p3, ctx.pOut);
+ UPDATE_MAX_BLOBSIZE(ctx.pOut);
break;
}
@@ -69708,8 +72569,7 @@ case OP_MustBeInt: { /* jump, in1 */
rc = SQLITE_MISMATCH;
goto abort_due_to_error;
}else{
- pc = pOp->p2 - 1;
- break;
+ goto jump_to_p2;
}
}
}
@@ -69737,106 +72597,37 @@ case OP_RealAffinity: { /* in1 */
#endif
#ifndef SQLITE_OMIT_CAST
-/* Opcode: ToText P1 * * * *
+/* Opcode: Cast P1 P2 * * *
+** Synopsis: affinity(r[P1])
**
-** Force the value in register P1 to be text.
-** If the value is numeric, convert it to a string using the
-** equivalent of sprintf(). Blob values are unchanged and
-** are afterwards simply interpreted as text.
+** Force the value in register P1 to be the type defined by P2.
+**
+** <ul>
+** <li value="97"> TEXT
+** <li value="98"> BLOB
+** <li value="99"> NUMERIC
+** <li value="100"> INTEGER
+** <li value="101"> REAL
+** </ul>
**
** A NULL value is not changed by this routine. It remains NULL.
*/
-case OP_ToText: { /* same as TK_TO_TEXT, in1 */
+case OP_Cast: { /* in1 */
+ assert( pOp->p2>=SQLITE_AFF_NONE && pOp->p2<=SQLITE_AFF_REAL );
+ testcase( pOp->p2==SQLITE_AFF_TEXT );
+ testcase( pOp->p2==SQLITE_AFF_NONE );
+ testcase( pOp->p2==SQLITE_AFF_NUMERIC );
+ testcase( pOp->p2==SQLITE_AFF_INTEGER );
+ testcase( pOp->p2==SQLITE_AFF_REAL );
pIn1 = &aMem[pOp->p1];
memAboutToChange(p, pIn1);
- if( pIn1->flags & MEM_Null ) break;
- assert( MEM_Str==(MEM_Blob>>3) );
- pIn1->flags |= (pIn1->flags&MEM_Blob)>>3;
- applyAffinity(pIn1, SQLITE_AFF_TEXT, encoding);
rc = ExpandBlob(pIn1);
- assert( pIn1->flags & MEM_Str || db->mallocFailed );
- pIn1->flags &= ~(MEM_Int|MEM_Real|MEM_Blob|MEM_Zero);
+ sqlite3VdbeMemCast(pIn1, pOp->p2, encoding);
UPDATE_MAX_BLOBSIZE(pIn1);
break;
}
-
-/* Opcode: ToBlob P1 * * * *
-**
-** Force the value in register P1 to be a BLOB.
-** If the value is numeric, convert it to a string first.
-** Strings are simply reinterpreted as blobs with no change
-** to the underlying data.
-**
-** A NULL value is not changed by this routine. It remains NULL.
-*/
-case OP_ToBlob: { /* same as TK_TO_BLOB, in1 */
- pIn1 = &aMem[pOp->p1];
- if( pIn1->flags & MEM_Null ) break;
- if( (pIn1->flags & MEM_Blob)==0 ){
- applyAffinity(pIn1, SQLITE_AFF_TEXT, encoding);
- assert( pIn1->flags & MEM_Str || db->mallocFailed );
- MemSetTypeFlag(pIn1, MEM_Blob);
- }else{
- pIn1->flags &= ~(MEM_TypeMask&~MEM_Blob);
- }
- UPDATE_MAX_BLOBSIZE(pIn1);
- break;
-}
-
-/* Opcode: ToNumeric P1 * * * *
-**
-** Force the value in register P1 to be numeric (either an
-** integer or a floating-point number.)
-** If the value is text or blob, try to convert it to an using the
-** equivalent of atoi() or atof() and store 0 if no such conversion
-** is possible.
-**
-** A NULL value is not changed by this routine. It remains NULL.
-*/
-case OP_ToNumeric: { /* same as TK_TO_NUMERIC, in1 */
- pIn1 = &aMem[pOp->p1];
- sqlite3VdbeMemNumerify(pIn1);
- break;
-}
#endif /* SQLITE_OMIT_CAST */
-/* Opcode: ToInt P1 * * * *
-**
-** Force the value in register P1 to be an integer. If
-** The value is currently a real number, drop its fractional part.
-** If the value is text or blob, try to convert it to an integer using the
-** equivalent of atoi() and store 0 if no such conversion is possible.
-**
-** A NULL value is not changed by this routine. It remains NULL.
-*/
-case OP_ToInt: { /* same as TK_TO_INT, in1 */
- pIn1 = &aMem[pOp->p1];
- if( (pIn1->flags & MEM_Null)==0 ){
- sqlite3VdbeMemIntegerify(pIn1);
- }
- break;
-}
-
-#if !defined(SQLITE_OMIT_CAST) && !defined(SQLITE_OMIT_FLOATING_POINT)
-/* Opcode: ToReal P1 * * * *
-**
-** Force the value in register P1 to be a floating point number.
-** If The value is currently an integer, convert it.
-** If the value is text or blob, try to convert it to an integer using the
-** equivalent of atoi() and store 0.0 if no such conversion is possible.
-**
-** A NULL value is not changed by this routine. It remains NULL.
-*/
-case OP_ToReal: { /* same as TK_TO_REAL, in1 */
- pIn1 = &aMem[pOp->p1];
- memAboutToChange(p, pIn1);
- if( (pIn1->flags & MEM_Null)==0 ){
- sqlite3VdbeMemRealify(pIn1);
- }
- break;
-}
-#endif /* !defined(SQLITE_OMIT_CAST) && !defined(SQLITE_OMIT_FLOATING_POINT) */
-
/* Opcode: Lt P1 P2 P3 P4 P5
** Synopsis: if r[P1]<r[P3] goto P2
**
@@ -69964,7 +72755,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
}else{
VdbeBranchTaken(2,3);
if( pOp->p5 & SQLITE_JUMPIFNULL ){
- pc = pOp->p2-1;
+ goto jump_to_p2;
}
}
break;
@@ -69972,15 +72763,39 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
}else{
/* Neither operand is NULL. Do a comparison. */
affinity = pOp->p5 & SQLITE_AFF_MASK;
- if( affinity ){
- applyAffinity(pIn1, affinity, encoding);
- applyAffinity(pIn3, affinity, encoding);
- if( db->mallocFailed ) goto no_mem;
+ if( affinity>=SQLITE_AFF_NUMERIC ){
+ if( (pIn1->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
+ applyNumericAffinity(pIn1,0);
+ }
+ if( (pIn3->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
+ applyNumericAffinity(pIn3,0);
+ }
+ }else if( affinity==SQLITE_AFF_TEXT ){
+ if( (pIn1->flags & MEM_Str)==0 && (pIn1->flags & (MEM_Int|MEM_Real))!=0 ){
+ testcase( pIn1->flags & MEM_Int );
+ testcase( pIn1->flags & MEM_Real );
+ sqlite3VdbeMemStringify(pIn1, encoding, 1);
+ testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn) );
+ flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask);
+ }
+ if( (pIn3->flags & MEM_Str)==0 && (pIn3->flags & (MEM_Int|MEM_Real))!=0 ){
+ testcase( pIn3->flags & MEM_Int );
+ testcase( pIn3->flags & MEM_Real );
+ sqlite3VdbeMemStringify(pIn3, encoding, 1);
+ testcase( (flags3&MEM_Dyn) != (pIn3->flags&MEM_Dyn) );
+ flags3 = (pIn3->flags & ~MEM_TypeMask) | (flags3 & MEM_TypeMask);
+ }
}
-
assert( pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0 );
- ExpandBlob(pIn1);
- ExpandBlob(pIn3);
+ if( pIn1->flags & MEM_Zero ){
+ sqlite3VdbeMemExpandBlob(pIn1);
+ flags1 &= ~MEM_Zero;
+ }
+ if( pIn3->flags & MEM_Zero ){
+ sqlite3VdbeMemExpandBlob(pIn3);
+ flags3 &= ~MEM_Zero;
+ }
+ if( db->mallocFailed ) goto no_mem;
res = sqlite3MemCompare(pIn3, pIn1, pOp->p4.pColl);
}
switch( pOp->opcode ){
@@ -69992,6 +72807,12 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
default: res = res>=0; break;
}
+ /* Undo any changes made by applyAffinity() to the input registers. */
+ assert( (pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn) );
+ pIn1->flags = flags1;
+ assert( (pIn3->flags & MEM_Dyn) == (flags3 & MEM_Dyn) );
+ pIn3->flags = flags3;
+
if( pOp->p5 & SQLITE_STOREP2 ){
pOut = &aMem[pOp->p2];
memAboutToChange(p, pOut);
@@ -70001,12 +72822,9 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
}else{
VdbeBranchTaken(res!=0, (pOp->p5 & SQLITE_NULLEQ)?2:3);
if( res ){
- pc = pOp->p2-1;
+ goto jump_to_p2;
}
}
- /* Undo any changes made by applyAffinity() to the input registers. */
- pIn1->flags = (pIn1->flags&~MEM_TypeMask) | (flags1&MEM_TypeMask);
- pIn3->flags = (pIn3->flags&~MEM_TypeMask) | (flags3&MEM_TypeMask);
break;
}
@@ -70101,11 +72919,11 @@ case OP_Compare: {
*/
case OP_Jump: { /* jump */
if( iCompare<0 ){
- pc = pOp->p1 - 1; VdbeBranchTaken(0,3);
+ VdbeBranchTaken(0,3); pOp = &aOp[pOp->p1 - 1];
}else if( iCompare==0 ){
- pc = pOp->p2 - 1; VdbeBranchTaken(1,3);
+ VdbeBranchTaken(1,3); pOp = &aOp[pOp->p2 - 1];
}else{
- pc = pOp->p3 - 1; VdbeBranchTaken(2,3);
+ VdbeBranchTaken(2,3); pOp = &aOp[pOp->p3 - 1];
}
break;
}
@@ -70174,10 +72992,10 @@ case OP_Or: { /* same as TK_OR, in1, in2, out3 */
case OP_Not: { /* same as TK_NOT, in1, out2 */
pIn1 = &aMem[pOp->p1];
pOut = &aMem[pOp->p2];
- if( pIn1->flags & MEM_Null ){
- sqlite3VdbeMemSetNull(pOut);
- }else{
- sqlite3VdbeMemSetInt64(pOut, !sqlite3VdbeIntValue(pIn1));
+ sqlite3VdbeMemSetNull(pOut);
+ if( (pIn1->flags & MEM_Null)==0 ){
+ pOut->flags = MEM_Int;
+ pOut->u.i = !sqlite3VdbeIntValue(pIn1);
}
break;
}
@@ -70192,10 +73010,10 @@ case OP_Not: { /* same as TK_NOT, in1, out2 */
case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */
pIn1 = &aMem[pOp->p1];
pOut = &aMem[pOp->p2];
- if( pIn1->flags & MEM_Null ){
- sqlite3VdbeMemSetNull(pOut);
- }else{
- sqlite3VdbeMemSetInt64(pOut, ~sqlite3VdbeIntValue(pIn1));
+ sqlite3VdbeMemSetNull(pOut);
+ if( (pIn1->flags & MEM_Null)==0 ){
+ pOut->flags = MEM_Int;
+ pOut->u.i = ~sqlite3VdbeIntValue(pIn1);
}
break;
}
@@ -70215,7 +73033,7 @@ case OP_Once: { /* jump */
assert( pOp->p1<p->nOnceFlag );
VdbeBranchTaken(p->aOnceFlag[pOp->p1]!=0, 2);
if( p->aOnceFlag[pOp->p1] ){
- pc = pOp->p2-1;
+ goto jump_to_p2;
}else{
p->aOnceFlag[pOp->p1] = 1;
}
@@ -70250,7 +73068,7 @@ case OP_IfNot: { /* jump, in1 */
}
VdbeBranchTaken(c!=0, 2);
if( c ){
- pc = pOp->p2-1;
+ goto jump_to_p2;
}
break;
}
@@ -70264,7 +73082,7 @@ case OP_IsNull: { /* same as TK_ISNULL, jump, in1 */
pIn1 = &aMem[pOp->p1];
VdbeBranchTaken( (pIn1->flags & MEM_Null)!=0, 2);
if( (pIn1->flags & MEM_Null)!=0 ){
- pc = pOp->p2 - 1;
+ goto jump_to_p2;
}
break;
}
@@ -70278,7 +73096,7 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */
pIn1 = &aMem[pOp->p1];
VdbeBranchTaken( (pIn1->flags & MEM_Null)==0, 2);
if( (pIn1->flags & MEM_Null)==0 ){
- pc = pOp->p2 - 1;
+ goto jump_to_p2;
}
break;
}
@@ -70313,7 +73131,6 @@ case OP_Column: {
int p2; /* column number to retrieve */
VdbeCursor *pC; /* The VDBE cursor */
BtCursor *pCrsr; /* The BTree cursor */
- u32 *aType; /* aType[i] holds the numeric type of the i-th column */
u32 *aOffset; /* aOffset[i] is offset to start of data for i-th column */
int len; /* The length of the serialized data for the column */
int i; /* Loop counter */
@@ -70326,6 +73143,7 @@ case OP_Column: {
u32 szField; /* Number of bytes in the content of a field */
u32 avail; /* Number of bytes of available data */
u32 t; /* A type code from the record header */
+ u16 fx; /* pDest->flags value */
Mem *pReg; /* PseudoTable input register */
p2 = pOp->p2;
@@ -70336,8 +73154,7 @@ case OP_Column: {
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( p2<pC->nField );
- aType = pC->aType;
- aOffset = aType + pC->nField;
+ aOffset = pC->aOffset;
#ifndef SQLITE_OMIT_VIRTUALTABLE
assert( pC->pVtabCursor==0 ); /* OP_Column never called on virtual table */
#endif
@@ -70348,7 +73165,7 @@ case OP_Column: {
/* If the cursor cache is stale, bring it up-to-date */
rc = sqlite3VdbeCursorMoveto(pC);
if( rc ) goto abort_due_to_error;
- if( pC->cacheStatus!=p->cacheCtr || (pOp->p5&OPFLAG_CLEARCACHE)!=0 ){
+ if( pC->cacheStatus!=p->cacheCtr ){
if( pC->nullRow ){
if( pCrsr==0 ){
assert( pC->pseudoTableReg>0 );
@@ -70358,7 +73175,7 @@ case OP_Column: {
pC->payloadSize = pC->szRow = avail = pReg->n;
pC->aRow = (u8*)pReg->z;
}else{
- MemSetTypeFlag(pDest, MEM_Null);
+ sqlite3VdbeMemSetNull(pDest);
goto op_column_out;
}
}else{
@@ -70393,14 +73210,6 @@ case OP_Column: {
pC->iHdrOffset = getVarint32(pC->aRow, offset);
pC->nHdrParsed = 0;
aOffset[0] = offset;
- if( avail<offset ){
- /* pC->aRow does not have to hold the entire row, but it does at least
- ** need to cover the header of the record. If pC->aRow does not contain
- ** the complete header, then set it to zero, forcing the header to be
- ** dynamically allocated. */
- pC->aRow = 0;
- pC->szRow = 0;
- }
/* Make sure a corrupt database has not given us an oversize header.
** Do this now to avoid an oversize memory allocation.
@@ -70415,15 +73224,32 @@ case OP_Column: {
rc = SQLITE_CORRUPT_BKPT;
goto op_column_error;
}
+
+ if( avail<offset ){
+ /* pC->aRow does not have to hold the entire row, but it does at least
+ ** need to cover the header of the record. If pC->aRow does not contain
+ ** the complete header, then set it to zero, forcing the header to be
+ ** dynamically allocated. */
+ pC->aRow = 0;
+ pC->szRow = 0;
+ }
+
+ /* The following goto is an optimization. It can be omitted and
+ ** everything will still work. But OP_Column is measurably faster
+ ** by skipping the subsequent conditional, which is always true.
+ */
+ assert( pC->nHdrParsed<=p2 ); /* Conditional skipped */
+ goto op_column_read_header;
}
/* Make sure at least the first p2+1 entries of the header have been
- ** parsed and valid information is in aOffset[] and aType[].
+ ** parsed and valid information is in aOffset[] and pC->aType[].
*/
if( pC->nHdrParsed<=p2 ){
/* If there is more header available for parsing in the record, try
** to extract additional fields up through the p2+1-th field
*/
+ op_column_read_header:
if( pC->iHdrOffset<aOffset[0] ){
/* Make sure zData points to enough of the record to cover the header. */
if( pC->aRow==0 ){
@@ -70438,7 +73264,7 @@ case OP_Column: {
zData = pC->aRow;
}
- /* Fill in aType[i] and aOffset[i] values through the p2-th field. */
+ /* Fill in pC->aType[i] and aOffset[i] values through the p2-th field. */
i = pC->nHdrParsed;
offset = aOffset[i];
zHdr = zData + pC->iHdrOffset;
@@ -70451,7 +73277,7 @@ case OP_Column: {
}else{
zHdr += sqlite3GetVarint32(zHdr, &t);
}
- aType[i] = t;
+ pC->aType[i] = t;
szField = sqlite3VdbeSerialTypeLen(t);
offset += szField;
if( offset<szField ){ /* True if offset overflows */
@@ -70468,22 +73294,23 @@ case OP_Column: {
sMem.flags = MEM_Null;
}
- /* If we have read more header data than was contained in the header,
- ** or if the end of the last field appears to be past the end of the
- ** record, or if the end of the last field appears to be before the end
- ** of the record (when all fields present), then we must be dealing
- ** with a corrupt database.
+ /* The record is corrupt if any of the following are true:
+ ** (1) the bytes of the header extend past the declared header size
+ ** (zHdr>zEndHdr)
+ ** (2) the entire header was used but not all data was used
+ ** (zHdr==zEndHdr && offset!=pC->payloadSize)
+ ** (3) the end of the data extends beyond the end of the record.
+ ** (offset > pC->payloadSize)
*/
- if( (zHdr > zEndHdr)
+ if( (zHdr>=zEndHdr && (zHdr>zEndHdr || offset!=pC->payloadSize))
|| (offset > pC->payloadSize)
- || (zHdr==zEndHdr && offset!=pC->payloadSize)
){
rc = SQLITE_CORRUPT_BKPT;
goto op_column_error;
}
}
- /* If after trying to extra new entries from the header, nHdrParsed is
+ /* If after trying to extract new entries from the header, nHdrParsed is
** still not up to p2, that means that the record has fewer than p2
** columns. So the result will be either the default value or a NULL.
*/
@@ -70491,68 +73318,68 @@ case OP_Column: {
if( pOp->p4type==P4_MEM ){
sqlite3VdbeMemShallowCopy(pDest, pOp->p4.pMem, MEM_Static);
}else{
- MemSetTypeFlag(pDest, MEM_Null);
+ sqlite3VdbeMemSetNull(pDest);
}
goto op_column_out;
}
}
/* Extract the content for the p2+1-th column. Control can only
- ** reach this point if aOffset[p2], aOffset[p2+1], and aType[p2] are
+ ** reach this point if aOffset[p2], aOffset[p2+1], and pC->aType[p2] are
** all valid.
*/
assert( p2<pC->nHdrParsed );
assert( rc==SQLITE_OK );
assert( sqlite3VdbeCheckMemInvariants(pDest) );
+ if( VdbeMemDynamic(pDest) ) sqlite3VdbeMemSetNull(pDest);
+ t = pC->aType[p2];
if( pC->szRow>=aOffset[p2+1] ){
/* This is the common case where the desired content fits on the original
** page - where the content is not on an overflow page */
- VdbeMemRelease(pDest);
- sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], aType[p2], pDest);
+ sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], t, pDest);
}else{
/* This branch happens only when content is on overflow pages */
- t = aType[p2];
if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
&& ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0))
|| (len = sqlite3VdbeSerialTypeLen(t))==0
){
- /* Content is irrelevant for the typeof() function and for
- ** the length(X) function if X is a blob. So we might as well use
- ** bogus content rather than reading content from disk. NULL works
- ** for text and blob and whatever is in the payloadSize64 variable
- ** will work for everything else. Content is also irrelevant if
- ** the content length is 0. */
- zData = t<=13 ? (u8*)&payloadSize64 : 0;
- sMem.zMalloc = 0;
+ /* Content is irrelevant for
+ ** 1. the typeof() function,
+ ** 2. the length(X) function if X is a blob, and
+ ** 3. if the content length is zero.
+ ** So we might as well use bogus content rather than reading
+ ** content from disk. NULL will work for the value for strings
+ ** and blobs and whatever is in the payloadSize64 variable
+ ** will work for everything else. */
+ sqlite3VdbeSerialGet(t<=13 ? (u8*)&payloadSize64 : 0, t, pDest);
}else{
- memset(&sMem, 0, sizeof(sMem));
- sqlite3VdbeMemMove(&sMem, pDest);
rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, !pC->isTable,
- &sMem);
+ pDest);
if( rc!=SQLITE_OK ){
goto op_column_error;
}
- zData = (u8*)sMem.z;
- }
- sqlite3VdbeSerialGet(zData, t, pDest);
- /* If we dynamically allocated space to hold the data (in the
- ** sqlite3VdbeMemFromBtree() call above) then transfer control of that
- ** dynamically allocated space over to the pDest structure.
- ** This prevents a memory copy. */
- if( sMem.zMalloc ){
- assert( sMem.z==sMem.zMalloc );
- assert( VdbeMemDynamic(pDest)==0 );
- assert( (pDest->flags & (MEM_Blob|MEM_Str))==0 || pDest->z==sMem.z );
- pDest->flags &= ~(MEM_Ephem|MEM_Static);
- pDest->flags |= MEM_Term;
- pDest->z = sMem.z;
- pDest->zMalloc = sMem.zMalloc;
+ sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest);
+ pDest->flags &= ~MEM_Ephem;
}
}
pDest->enc = encoding;
op_column_out:
- Deephemeralize(pDest);
+ /* If the column value is an ephemeral string, go ahead and persist
+ ** that string in case the cursor moves before the column value is
+ ** used. The following code does the equivalent of Deephemeralize()
+ ** but does it faster. */
+ if( (pDest->flags & MEM_Ephem)!=0 && pDest->z ){
+ fx = pDest->flags & (MEM_Str|MEM_Blob);
+ assert( fx!=0 );
+ zData = (const u8*)pDest->z;
+ len = pDest->n;
+ if( sqlite3VdbeMemClearAndResize(pDest, len+2) ) goto no_mem;
+ memcpy(pDest->z, zData, len);
+ pDest->z[len] = 0;
+ pDest->z[len+1] = 0;
+ pDest->flags = fx|MEM_Term;
+ }
op_column_error:
UPDATE_MAX_BLOBSIZE(pDest);
REGISTER_TRACE(pOp->p3, pDest);
@@ -70607,7 +73434,7 @@ case OP_MakeRecord: {
u64 nData; /* Number of bytes of data space */
int nHdr; /* Number of bytes of header space */
i64 nByte; /* Data space required for this record */
- int nZero; /* Number of zero bytes at the end of the record */
+ i64 nZero; /* Number of zero bytes at the end of the record */
int nVarint; /* Number of bytes in a varint */
u32 serial_type; /* Type field */
Mem *pData0; /* First field to be combined into the record */
@@ -70627,7 +73454,7 @@ case OP_MakeRecord: {
** ------------------------------------------------------------------------
**
** Data(0) is taken from register P1. Data(1) comes from register P1+1
- ** and so froth.
+ ** and so forth.
**
** Each type field is a varint representing the serial type of the
** corresponding data element (see sqlite3VdbeSerialType()). The
@@ -70667,7 +73494,7 @@ case OP_MakeRecord: {
pRec = pLast;
do{
assert( memIsValid(pRec) );
- serial_type = sqlite3VdbeSerialType(pRec, file_format);
+ pRec->uTemp = serial_type = sqlite3VdbeSerialType(pRec, file_format);
len = sqlite3VdbeSerialTypeLen(serial_type);
if( pRec->flags & MEM_Zero ){
if( nData ){
@@ -70683,7 +73510,10 @@ case OP_MakeRecord: {
nHdr += serial_type<=127 ? 1 : sqlite3VarintLen(serial_type);
}while( (--pRec)>=pData0 );
- /* Add the initial header varint and total the size */
+ /* EVIDENCE-OF: R-22564-11647 The header begins with a single varint
+ ** which determines the total number of bytes in the header. The varint
+ ** value is the size of the header in bytes including the size varint
+ ** itself. */
testcase( nHdr==126 );
testcase( nHdr==127 );
if( nHdr<=126 ){
@@ -70696,16 +73526,16 @@ case OP_MakeRecord: {
if( nVarint<sqlite3VarintLen(nHdr) ) nHdr++;
}
nByte = nHdr+nData;
- if( nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){
+ if( nByte+nZero>db->aLimit[SQLITE_LIMIT_LENGTH] ){
goto too_big;
}
/* Make sure the output register has a buffer large enough to store
** the new record. The output register (pOp->p3) is not allowed to
** be one of the input registers (because the following call to
- ** sqlite3VdbeMemGrow() could clobber the value before it is used).
+ ** sqlite3VdbeMemClearAndResize() could clobber the value before it is used).
*/
- if( sqlite3VdbeMemGrow(pOut, (int)nByte, 0) ){
+ if( sqlite3VdbeMemClearAndResize(pOut, (int)nByte) ){
goto no_mem;
}
zNewRecord = (u8 *)pOut->z;
@@ -70716,8 +73546,12 @@ case OP_MakeRecord: {
assert( pData0<=pLast );
pRec = pData0;
do{
- serial_type = sqlite3VdbeSerialType(pRec, file_format);
+ serial_type = pRec->uTemp;
+ /* EVIDENCE-OF: R-06529-47362 Following the size varint are one or more
+ ** additional varints, one per column. */
i += putVarint32(&zNewRecord[i], serial_type); /* serial type */
+ /* EVIDENCE-OF: R-64536-51728 The values for each column in the record
+ ** immediately follow the header. */
j += sqlite3VdbeSerialPut(&zNewRecord[j], pRec, serial_type); /* content */
}while( (++pRec)<=pLast );
assert( i==nHdr );
@@ -70726,7 +73560,6 @@ case OP_MakeRecord: {
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
pOut->n = (int)nByte;
pOut->flags = MEM_Blob;
- pOut->xDel = 0;
if( nZero ){
pOut->u.nZero = nZero;
pOut->flags |= MEM_Zero;
@@ -70744,7 +73577,7 @@ case OP_MakeRecord: {
** opened by cursor P1 in register P2
*/
#ifndef SQLITE_OMIT_BTREECOUNT
-case OP_Count: { /* out2-prerelease */
+case OP_Count: { /* out2 */
i64 nEntry;
BtCursor *pCrsr;
@@ -70752,6 +73585,7 @@ case OP_Count: { /* out2-prerelease */
assert( pCrsr );
nEntry = 0; /* Not needed. Only used to silence a warning. */
rc = sqlite3BtreeCount(pCrsr, &nEntry);
+ pOut = out2Prerelease(p, pOp);
pOut->u.i = nEntry;
break;
}
@@ -70865,7 +73699,7 @@ case OP_Savepoint: {
}
db->autoCommit = 1;
if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){
- p->pc = pc;
+ p->pc = (int)(pOp - aOp);
db->autoCommit = 0;
p->rc = rc = SQLITE_BUSY;
goto vdbe_return;
@@ -70873,11 +73707,18 @@ case OP_Savepoint: {
db->isTransactionSavepoint = 0;
rc = p->rc;
}else{
+ int isSchemaChange;
iSavepoint = db->nSavepoint - iSavepoint - 1;
if( p1==SAVEPOINT_ROLLBACK ){
+ isSchemaChange = (db->flags & SQLITE_InternChanges)!=0;
for(ii=0; ii<db->nDb; ii++){
- sqlite3BtreeTripAllCursors(db->aDb[ii].pBt, SQLITE_ABORT);
+ rc = sqlite3BtreeTripAllCursors(db->aDb[ii].pBt,
+ SQLITE_ABORT_ROLLBACK,
+ isSchemaChange==0);
+ if( rc!=SQLITE_OK ) goto abort_due_to_error;
}
+ }else{
+ isSchemaChange = 0;
}
for(ii=0; ii<db->nDb; ii++){
rc = sqlite3BtreeSavepoint(db->aDb[ii].pBt, p1, iSavepoint);
@@ -70885,7 +73726,7 @@ case OP_Savepoint: {
goto abort_due_to_error;
}
}
- if( p1==SAVEPOINT_ROLLBACK && (db->flags&SQLITE_InternChanges)!=0 ){
+ if( isSchemaChange ){
sqlite3ExpirePreparedStatements(db);
sqlite3ResetAllSchemasOfConnection(db);
db->flags = (db->flags | SQLITE_InternChanges);
@@ -70917,7 +73758,7 @@ case OP_Savepoint: {
db->nDeferredImmCons = pSavepoint->nDeferredImmCons;
}
- if( !isTransaction ){
+ if( !isTransaction || p1==SAVEPOINT_ROLLBACK ){
rc = sqlite3VtabSavepoint(db, p1, iSavepoint);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
}
@@ -70977,7 +73818,7 @@ case OP_AutoCommit: {
}else{
db->autoCommit = (u8)desiredAutoCommit;
if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){
- p->pc = pc;
+ p->pc = (int)(pOp - aOp);
db->autoCommit = (u8)(1-desiredAutoCommit);
p->rc = rc = SQLITE_BUSY;
goto vdbe_return;
@@ -71054,7 +73895,7 @@ case OP_Transaction: {
if( pBt ){
rc = sqlite3BtreeBeginTrans(pBt, pOp->p2);
if( rc==SQLITE_BUSY ){
- p->pc = pc;
+ p->pc = (int)(pOp - aOp);
p->rc = rc = SQLITE_BUSY;
goto vdbe_return;
}
@@ -71084,7 +73925,12 @@ case OP_Transaction: {
p->nStmtDefImmCons = db->nDeferredImmCons;
}
- /* Gather the schema version number for checking */
+ /* Gather the schema version number for checking:
+ ** IMPLEMENTATION-OF: R-32195-19465 The schema version is used by SQLite
+ ** each time a query is executed to ensure that the internal cache of the
+ ** schema used when compiling the SQL query matches the schema of the
+ ** database against which the compiled query is actually executed.
+ */
sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta);
iGen = db->aDb[pOp->p1].pSchema->iGeneration;
}else{
@@ -71128,7 +73974,7 @@ case OP_Transaction: {
** must be started or there must be an open cursor) before
** executing this instruction.
*/
-case OP_ReadCookie: { /* out2-prerelease */
+case OP_ReadCookie: { /* out2 */
int iMeta;
int iDb;
int iCookie;
@@ -71142,6 +73988,7 @@ case OP_ReadCookie: { /* out2-prerelease */
assert( DbMaskTest(p->btreeMask, iDb) );
sqlite3BtreeGetMeta(db->aDb[iDb].pBt, iCookie, (u32 *)&iMeta);
+ pOut = out2Prerelease(p, pOp);
pOut->u.i = iMeta;
break;
}
@@ -71252,37 +74099,35 @@ case OP_SetCookie: { /* in3 */
** See also OpenRead.
*/
case OP_ReopenIdx: {
+ int nField;
+ KeyInfo *pKeyInfo;
+ int p2;
+ int iDb;
+ int wrFlag;
+ Btree *pX;
VdbeCursor *pCur;
+ Db *pDb;
- assert( pOp->p5==0 );
+ assert( pOp->p5==0 || pOp->p5==OPFLAG_SEEKEQ );
assert( pOp->p4type==P4_KEYINFO );
pCur = p->apCsr[pOp->p1];
if( pCur && pCur->pgnoRoot==(u32)pOp->p2 ){
assert( pCur->iDb==pOp->p3 ); /* Guaranteed by the code generator */
- break;
+ goto open_cursor_set_hints;
}
/* If the cursor is not currently open or is open on a different
** index, then fall through into OP_OpenRead to force a reopen */
-}
case OP_OpenRead:
-case OP_OpenWrite: {
- int nField;
- KeyInfo *pKeyInfo;
- int p2;
- int iDb;
- int wrFlag;
- Btree *pX;
- VdbeCursor *pCur;
- Db *pDb;
+case OP_OpenWrite:
- assert( (pOp->p5&(OPFLAG_P2ISREG|OPFLAG_BULKCSR))==pOp->p5 );
- assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 );
+ assert( (pOp->p5&(OPFLAG_P2ISREG|OPFLAG_BULKCSR|OPFLAG_SEEKEQ))==pOp->p5 );
+ assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 || pOp->p5==OPFLAG_SEEKEQ );
assert( p->bIsReader );
assert( pOp->opcode==OP_OpenRead || pOp->opcode==OP_ReopenIdx
|| p->readOnly==0 );
if( p->expired ){
- rc = SQLITE_ABORT;
+ rc = SQLITE_ABORT_ROLLBACK;
break;
}
@@ -71339,18 +74184,17 @@ case OP_OpenWrite: {
pCur->pgnoRoot = p2;
rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->pCursor);
pCur->pKeyInfo = pKeyInfo;
- assert( OPFLAG_BULKCSR==BTREE_BULKLOAD );
- sqlite3BtreeCursorHints(pCur->pCursor, (pOp->p5 & OPFLAG_BULKCSR));
-
- /* Since it performs no memory allocation or IO, the only value that
- ** sqlite3BtreeCursor() may return is SQLITE_OK. */
- assert( rc==SQLITE_OK );
-
/* Set the VdbeCursor.isTable variable. Previous versions of
** SQLite used to check if the root-page flags were sane at this point
** and report database corruption if they were not, but this check has
** since moved into the btree layer. */
pCur->isTable = pOp->p4type!=P4_KEYINFO;
+
+open_cursor_set_hints:
+ assert( OPFLAG_BULKCSR==BTREE_BULKLOAD );
+ assert( OPFLAG_SEEKEQ==BTREE_SEEK_EQ );
+ sqlite3BtreeCursorHints(pCur->pCursor,
+ (pOp->p5 & (OPFLAG_BULKCSR|OPFLAG_SEEKEQ)));
break;
}
@@ -71429,11 +74273,15 @@ case OP_OpenEphemeral: {
break;
}
-/* Opcode: SorterOpen P1 P2 * P4 *
+/* Opcode: SorterOpen P1 P2 P3 P4 *
**
** This opcode works like OP_OpenEphemeral except that it opens
** a transient index that is specifically designed to sort large
** tables using an external merge-sort algorithm.
+**
+** If argument P3 is non-zero, then it indicates that the sorter may
+** assume that a stable sort considering the first P3 fields of each
+** key is sufficient to produce the required results.
*/
case OP_SorterOpen: {
VdbeCursor *pCx;
@@ -71445,7 +74293,25 @@ case OP_SorterOpen: {
pCx->pKeyInfo = pOp->p4.pKeyInfo;
assert( pCx->pKeyInfo->db==db );
assert( pCx->pKeyInfo->enc==ENC(db) );
- rc = sqlite3VdbeSorterInit(db, pCx);
+ rc = sqlite3VdbeSorterInit(db, pOp->p3, pCx);
+ break;
+}
+
+/* Opcode: SequenceTest P1 P2 * * *
+** Synopsis: if( cursor[P1].ctr++ ) pc = P2
+**
+** P1 is a sorter cursor. If the sequence counter is currently zero, jump
+** to P2. Regardless of whether or not the jump is taken, increment the
+** the sequence value.
+*/
+case OP_SequenceTest: {
+ VdbeCursor *pC;
+ assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+ pC = p->apCsr[pOp->p1];
+ assert( pC->pSorter );
+ if( (pC->seqCount++)==0 ){
+ goto jump_to_p2;
+ }
break;
}
@@ -71589,14 +74455,31 @@ case OP_SeekGT: { /* jump, in3 */
#ifdef SQLITE_DEBUG
pC->seekOp = pOp->opcode;
#endif
+
+ /* For a cursor with the BTREE_SEEK_EQ hint, only the OP_SeekGE and
+ ** OP_SeekLE opcodes are allowed, and these must be immediately followed
+ ** by an OP_IdxGT or OP_IdxLT opcode, respectively, with the same key.
+ */
+#ifdef SQLITE_DEBUG
+ if( sqlite3BtreeCursorHasHint(pC->pCursor, BTREE_SEEK_EQ) ){
+ assert( pOp->opcode==OP_SeekGE || pOp->opcode==OP_SeekLE );
+ assert( pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT );
+ assert( pOp[1].p1==pOp[0].p1 );
+ assert( pOp[1].p2==pOp[0].p2 );
+ assert( pOp[1].p3==pOp[0].p3 );
+ assert( pOp[1].p4.i==pOp[0].p4.i );
+ }
+#endif
+
if( pC->isTable ){
/* The input value in P3 might be of any type: integer, real, string,
** blob, or NULL. But it needs to be an integer before we can do
- ** the seek, so covert it. */
+ ** the seek, so convert it. */
pIn3 = &aMem[pOp->p3];
- ApplyNumericAffinity(pIn3);
+ if( (pIn3->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
+ applyNumericAffinity(pIn3, 0);
+ }
iKey = sqlite3VdbeIntValue(pIn3);
- pC->rowidIsValid = 0;
/* If the P3 value could not be converted into an integer without
** loss of information, then special processing is required... */
@@ -71604,7 +74487,7 @@ case OP_SeekGT: { /* jump, in3 */
if( (pIn3->flags & MEM_Real)==0 ){
/* If the P3 value cannot be converted into any kind of a number,
** then the seek is not possible, so jump to P2 */
- pc = pOp->p2 - 1; VdbeBranchTaken(1,2);
+ VdbeBranchTaken(1,2); goto jump_to_p2;
break;
}
@@ -71615,7 +74498,7 @@ case OP_SeekGT: { /* jump, in3 */
** (x > 4.9) -> (x >= 5)
** (x <= 4.9) -> (x < 5)
*/
- if( pIn3->r<(double)iKey ){
+ if( pIn3->u.r<(double)iKey ){
assert( OP_SeekGE==(OP_SeekGT-1) );
assert( OP_SeekLT==(OP_SeekLE-1) );
assert( (OP_SeekLE & 0x0001)==(OP_SeekGT & 0x0001) );
@@ -71624,7 +74507,7 @@ case OP_SeekGT: { /* jump, in3 */
/* If the approximation iKey is smaller than the actual real search
** term, substitute <= for < and > for >=. */
- else if( pIn3->r>(double)iKey ){
+ else if( pIn3->u.r>(double)iKey ){
assert( OP_SeekLE==(OP_SeekLT+1) );
assert( OP_SeekGT==(OP_SeekGE+1) );
assert( (OP_SeekLT & 0x0001)==(OP_SeekGE & 0x0001) );
@@ -71632,13 +74515,10 @@ case OP_SeekGT: { /* jump, in3 */
}
}
rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)iKey, 0, &res);
+ pC->movetoTarget = iKey; /* Used by OP_Delete */
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
- if( res==0 ){
- pC->rowidIsValid = 1;
- pC->lastRowid = iKey;
- }
}else{
nField = pOp->p4.i;
assert( pOp->p4type==P4_INT32 );
@@ -71668,7 +74548,6 @@ case OP_SeekGT: { /* jump, in3 */
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
- pC->rowidIsValid = 0;
}
pC->deferredMoveto = 0;
pC->cacheStatus = CACHE_STALE;
@@ -71680,7 +74559,6 @@ case OP_SeekGT: { /* jump, in3 */
res = 0;
rc = sqlite3BtreeNext(pC->pCursor, &res);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
- pC->rowidIsValid = 0;
}else{
res = 0;
}
@@ -71690,7 +74568,6 @@ case OP_SeekGT: { /* jump, in3 */
res = 0;
rc = sqlite3BtreePrevious(pC->pCursor, &res);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
- pC->rowidIsValid = 0;
}else{
/* res might be negative because the table is empty. Check to
** see if this is the case.
@@ -71701,7 +74578,7 @@ case OP_SeekGT: { /* jump, in3 */
assert( pOp->p2>0 );
VdbeBranchTaken(res!=0,2);
if( res ){
- pc = pOp->p2 - 1;
+ goto jump_to_p2;
}
break;
}
@@ -71727,7 +74604,6 @@ case OP_Seek: { /* in2 */
pC->nullRow = 0;
pIn2 = &aMem[pOp->p2];
pC->movetoTarget = sqlite3VdbeIntValue(pIn2);
- pC->rowidIsValid = 0;
pC->deferredMoveto = 1;
break;
}
@@ -71796,6 +74672,7 @@ case OP_NoConflict: /* jump, in3 */
case OP_NotFound: /* jump, in3 */
case OP_Found: { /* jump, in3 */
int alreadyExists;
+ int takeJump;
int ii;
VdbeCursor *pC;
int res;
@@ -71818,7 +74695,7 @@ case OP_Found: { /* jump, in3 */
pIn3 = &aMem[pOp->p3];
assert( pC->pCursor!=0 );
assert( pC->isTable==0 );
- pFree = 0; /* Not needed. Only used to suppress a compiler warning. */
+ pFree = 0;
if( pOp->p4.i>0 ){
r.pKeyInfo = pC->pKeyInfo;
r.nField = (u16)pOp->p4.i;
@@ -71834,28 +74711,27 @@ case OP_Found: { /* jump, in3 */
}else{
pIdxKey = sqlite3VdbeAllocUnpackedRecord(
pC->pKeyInfo, aTempRec, sizeof(aTempRec), &pFree
- );
+ );
if( pIdxKey==0 ) goto no_mem;
assert( pIn3->flags & MEM_Blob );
- assert( (pIn3->flags & MEM_Zero)==0 ); /* zeroblobs already expanded */
+ ExpandBlob(pIn3);
sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z, pIdxKey);
}
pIdxKey->default_rc = 0;
+ takeJump = 0;
if( pOp->opcode==OP_NoConflict ){
/* For the OP_NoConflict opcode, take the jump if any of the
** input fields are NULL, since any key with a NULL will not
** conflict */
- for(ii=0; ii<r.nField; ii++){
- if( r.aMem[ii].flags & MEM_Null ){
- pc = pOp->p2 - 1; VdbeBranchTaken(1,2);
+ for(ii=0; ii<pIdxKey->nField; ii++){
+ if( pIdxKey->aMem[ii].flags & MEM_Null ){
+ takeJump = 1;
break;
}
}
}
rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, pIdxKey, 0, 0, &res);
- if( pOp->p4.i==0 ){
- sqlite3DbFree(db, pFree);
- }
+ sqlite3DbFree(db, pFree);
if( rc!=SQLITE_OK ){
break;
}
@@ -71866,10 +74742,10 @@ case OP_Found: { /* jump, in3 */
pC->cacheStatus = CACHE_STALE;
if( pOp->opcode==OP_Found ){
VdbeBranchTaken(alreadyExists!=0,2);
- if( alreadyExists ) pc = pOp->p2 - 1;
+ if( alreadyExists ) goto jump_to_p2;
}else{
- VdbeBranchTaken(alreadyExists==0,2);
- if( !alreadyExists ) pc = pOp->p2 - 1;
+ VdbeBranchTaken(takeJump||alreadyExists==0,2);
+ if( takeJump || !alreadyExists ) goto jump_to_p2;
}
break;
}
@@ -71913,17 +74789,13 @@ case OP_NotExists: { /* jump, in3 */
res = 0;
iKey = pIn3->u.i;
rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res);
- pC->lastRowid = pIn3->u.i;
- pC->rowidIsValid = res==0 ?1:0;
+ pC->movetoTarget = iKey; /* Used by OP_Delete */
pC->nullRow = 0;
pC->cacheStatus = CACHE_STALE;
pC->deferredMoveto = 0;
VdbeBranchTaken(res!=0,2);
- if( res!=0 ){
- pc = pOp->p2 - 1;
- assert( pC->rowidIsValid==0 );
- }
pC->seekResult = res;
+ if( res!=0 ) goto jump_to_p2;
break;
}
@@ -71935,9 +74807,10 @@ case OP_NotExists: { /* jump, in3 */
** The sequence number on the cursor is incremented after this
** instruction.
*/
-case OP_Sequence: { /* out2-prerelease */
+case OP_Sequence: { /* out2 */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( p->apCsr[pOp->p1]!=0 );
+ pOut = out2Prerelease(p, pOp);
pOut->u.i = p->apCsr[pOp->p1]->seqCount++;
break;
}
@@ -71958,7 +74831,7 @@ case OP_Sequence: { /* out2-prerelease */
** generated record number. This P3 mechanism is used to help implement the
** AUTOINCREMENT feature.
*/
-case OP_NewRowid: { /* out2-prerelease */
+case OP_NewRowid: { /* out2 */
i64 v; /* The new rowid */
VdbeCursor *pC; /* Cursor of table to get the new rowid */
int res; /* Result of an sqlite3BtreeLast() */
@@ -71968,6 +74841,7 @@ case OP_NewRowid: { /* out2-prerelease */
v = 0;
res = 0;
+ pOut = out2Prerelease(p, pOp);
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
@@ -72055,32 +74929,20 @@ case OP_NewRowid: { /* out2-prerelease */
** it finds one that is not previously used. */
assert( pOp->p3==0 ); /* We cannot be in random rowid mode if this is
** an AUTOINCREMENT table. */
- /* on the first attempt, simply do one more than previous */
- v = lastRowid;
- v &= (MAX_ROWID>>1); /* ensure doesn't go negative */
- v++; /* ensure non-zero */
cnt = 0;
- while( ((rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)v,
+ do{
+ sqlite3_randomness(sizeof(v), &v);
+ v &= (MAX_ROWID>>1); v++; /* Ensure that v is greater than zero */
+ }while( ((rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)v,
0, &res))==SQLITE_OK)
&& (res==0)
- && (++cnt<100)){
- /* collision - try another random rowid */
- sqlite3_randomness(sizeof(v), &v);
- if( cnt<5 ){
- /* try "small" random rowids for the initial attempts */
- v &= 0xffffff;
- }else{
- v &= (MAX_ROWID>>1); /* ensure doesn't go negative */
- }
- v++; /* ensure non-zero */
- }
+ && (++cnt<100));
if( rc==SQLITE_OK && res==0 ){
rc = SQLITE_FULL; /* IMP: R-38219-53002 */
goto abort_due_to_error;
}
assert( v>0 ); /* EV: R-40812-03570 */
}
- pC->rowidIsValid = 0;
pC->deferredMoveto = 0;
pC->cacheStatus = CACHE_STALE;
}
@@ -72185,7 +75047,6 @@ case OP_InsertInt: {
pData->z, pData->n, nZero,
(pOp->p5 & OPFLAG_APPEND)!=0, seekResult
);
- pC->rowidIsValid = 0;
pC->deferredMoveto = 0;
pC->cacheStatus = CACHE_STALE;
@@ -72222,33 +75083,32 @@ case OP_InsertInt: {
** using OP_NotFound prior to invoking this opcode.
*/
case OP_Delete: {
- i64 iKey;
VdbeCursor *pC;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( pC->pCursor!=0 ); /* Only valid for real tables, no pseudotables */
- iKey = pC->lastRowid; /* Only used for the update hook */
-
- /* The OP_Delete opcode always follows an OP_NotExists or OP_Last or
- ** OP_Column on the same table without any intervening operations that
- ** might move or invalidate the cursor. Hence cursor pC is always pointing
- ** to the row to be deleted and the sqlite3VdbeCursorMoveto() operation
- ** below is always a no-op and cannot fail. We will run it anyhow, though,
- ** to guard against future changes to the code generator.
- **/
assert( pC->deferredMoveto==0 );
- rc = sqlite3VdbeCursorMoveto(pC);
- if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error;
+#ifdef SQLITE_DEBUG
+ /* The seek operation that positioned the cursor prior to OP_Delete will
+ ** have also set the pC->movetoTarget field to the rowid of the row that
+ ** is being deleted */
+ if( pOp->p4.z && pC->isTable ){
+ i64 iKey = 0;
+ sqlite3BtreeKeySize(pC->pCursor, &iKey);
+ assert( pC->movetoTarget==iKey );
+ }
+#endif
+
rc = sqlite3BtreeDelete(pC->pCursor);
pC->cacheStatus = CACHE_STALE;
/* Invoke the update-hook if required. */
if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z && pC->isTable ){
db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE,
- db->aDb[pC->iDb].zName, pOp->p4.z, iKey);
+ db->aDb[pC->iDb].zName, pOp->p4.z, pC->movetoTarget);
assert( pC->iDb>=0 );
}
if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++;
@@ -72292,18 +75152,24 @@ case OP_SorterCompare: {
assert( pOp->p4type==P4_INT32 );
pIn3 = &aMem[pOp->p3];
nKeyCol = pOp->p4.i;
+ res = 0;
rc = sqlite3VdbeSorterCompare(pC, pIn3, nKeyCol, &res);
VdbeBranchTaken(res!=0,2);
- if( res ){
- pc = pOp->p2-1;
- }
+ if( res ) goto jump_to_p2;
break;
};
-/* Opcode: SorterData P1 P2 * * *
+/* Opcode: SorterData P1 P2 P3 * *
** Synopsis: r[P2]=data
**
** Write into register P2 the current sorter data for sorter cursor P1.
+** Then clear the column header cache on cursor P3.
+**
+** This opcode is normally use to move a record out of the sorter and into
+** a register that is the source for a pseudo-table cursor created using
+** OpenPseudo. That pseudo-table cursor is the one that is identified by
+** parameter P3. Clearing the P3 column cache as part of this opcode saves
+** us from having to issue a separate NullRow instruction to clear that cache.
*/
case OP_SorterData: {
VdbeCursor *pC;
@@ -72313,6 +75179,8 @@ case OP_SorterData: {
assert( isSorter(pC) );
rc = sqlite3VdbeSorterRowkey(pC, pOut);
assert( rc!=SQLITE_OK || (pOut->flags & MEM_Blob) );
+ assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+ p->apCsr[pOp->p3]->cacheStatus = CACHE_STALE;
break;
}
@@ -72359,16 +75227,20 @@ case OP_RowData: {
assert( pC->pseudoTableReg==0 );
assert( pC->pCursor!=0 );
pCrsr = pC->pCursor;
- assert( sqlite3BtreeCursorIsValid(pCrsr) );
/* The OP_RowKey and OP_RowData opcodes always follow OP_NotExists or
** OP_Rewind/Op_Next with no intervening instructions that might invalidate
- ** the cursor. Hence the following sqlite3VdbeCursorMoveto() call is always
- ** a no-op and can never fail. But we leave it in place as a safety.
+ ** the cursor. If this where not the case, on of the following assert()s
+ ** would fail. Should this ever change (because of changes in the code
+ ** generator) then the fix would be to insert a call to
+ ** sqlite3VdbeCursorMoveto().
*/
assert( pC->deferredMoveto==0 );
+ assert( sqlite3BtreeCursorIsValid(pCrsr) );
+#if 0 /* Not required due to the previous to assert() statements */
rc = sqlite3VdbeCursorMoveto(pC);
- if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error;
+ if( rc!=SQLITE_OK ) goto abort_due_to_error;
+#endif
if( pC->isTable==0 ){
assert( !pC->isTable );
@@ -72385,7 +75257,8 @@ case OP_RowData: {
goto too_big;
}
}
- if( sqlite3VdbeMemGrow(pOut, n, 0) ){
+ testcase( n==0 );
+ if( sqlite3VdbeMemClearAndResize(pOut, MAX(n,32)) ){
goto no_mem;
}
pOut->n = n;
@@ -72411,12 +75284,13 @@ case OP_RowData: {
** be a separate OP_VRowid opcode for use with virtual tables, but this
** one opcode now works for both table types.
*/
-case OP_Rowid: { /* out2-prerelease */
+case OP_Rowid: { /* out2 */
VdbeCursor *pC;
i64 v;
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
+ pOut = out2Prerelease(p, pOp);
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
@@ -72436,14 +75310,14 @@ case OP_Rowid: { /* out2-prerelease */
#endif /* SQLITE_OMIT_VIRTUALTABLE */
}else{
assert( pC->pCursor!=0 );
- rc = sqlite3VdbeCursorMoveto(pC);
+ rc = sqlite3VdbeCursorRestore(pC);
if( rc ) goto abort_due_to_error;
- if( pC->rowidIsValid ){
- v = pC->lastRowid;
- }else{
- rc = sqlite3BtreeKeySize(pC->pCursor, &v);
- assert( rc==SQLITE_OK ); /* Always so because of CursorMoveto() above */
+ if( pC->nullRow ){
+ pOut->flags = MEM_Null;
+ break;
}
+ rc = sqlite3BtreeKeySize(pC->pCursor, &v);
+ assert( rc==SQLITE_OK ); /* Always so because of CursorRestore() above */
}
pOut->u.i = v;
break;
@@ -72462,7 +75336,6 @@ case OP_NullRow: {
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
pC->nullRow = 1;
- pC->rowidIsValid = 0;
pC->cacheStatus = CACHE_STALE;
if( pC->pCursor ){
sqlite3BtreeClearCursor(pC->pCursor);
@@ -72470,7 +75343,7 @@ case OP_NullRow: {
break;
}
-/* Opcode: Last P1 P2 * * *
+/* Opcode: Last P1 P2 P3 * *
**
** The next use of the Rowid or Column or Prev instruction for P1
** will refer to the last entry in the database table or index.
@@ -72496,14 +75369,14 @@ case OP_Last: { /* jump */
rc = sqlite3BtreeLast(pCrsr, &res);
pC->nullRow = (u8)res;
pC->deferredMoveto = 0;
- pC->rowidIsValid = 0;
pC->cacheStatus = CACHE_STALE;
+ pC->seekResult = pOp->p3;
#ifdef SQLITE_DEBUG
pC->seekOp = OP_Last;
#endif
if( pOp->p2>0 ){
VdbeBranchTaken(res!=0,2);
- if( res ) pc = pOp->p2 - 1;
+ if( res ) goto jump_to_p2;
}
break;
}
@@ -72534,9 +75407,9 @@ case OP_Sort: { /* jump */
**
** The next use of the Rowid or Column or Next instruction for P1
** will refer to the first entry in the database table or index.
-** If the table or index is empty and P2>0, then jump immediately to P2.
-** If P2 is 0 or if the table or index is not empty, fall through
-** to the following instruction.
+** If the table or index is empty, jump immediately to P2.
+** If the table or index is not empty, fall through to the following
+** instruction.
**
** This opcode leaves the cursor configured to move in forward order,
** from the beginning toward the end. In other words, the cursor is
@@ -72556,21 +75429,18 @@ case OP_Rewind: { /* jump */
pC->seekOp = OP_Rewind;
#endif
if( isSorter(pC) ){
- rc = sqlite3VdbeSorterRewind(db, pC, &res);
+ rc = sqlite3VdbeSorterRewind(pC, &res);
}else{
pCrsr = pC->pCursor;
assert( pCrsr );
rc = sqlite3BtreeFirst(pCrsr, &res);
pC->deferredMoveto = 0;
pC->cacheStatus = CACHE_STALE;
- pC->rowidIsValid = 0;
}
pC->nullRow = (u8)res;
assert( pOp->p2>0 && pOp->p2<p->nOp );
VdbeBranchTaken(res!=0,2);
- if( res ){
- pc = pOp->p2 - 1;
- }
+ if( res ) goto jump_to_p2;
break;
}
@@ -72681,15 +75551,14 @@ next_tail:
VdbeBranchTaken(res==0,2);
if( res==0 ){
pC->nullRow = 0;
- pc = pOp->p2 - 1;
p->aCounter[pOp->p5]++;
#ifdef SQLITE_TEST
sqlite3_search_count++;
#endif
+ goto jump_to_p2_and_check_for_interrupt;
}else{
pC->nullRow = 1;
}
- pC->rowidIsValid = 0;
goto check_for_interrupt;
}
@@ -72734,7 +75603,7 @@ case OP_IdxInsert: { /* in2 */
rc = ExpandBlob(pIn2);
if( rc==SQLITE_OK ){
if( isSorter(pC) ){
- rc = sqlite3VdbeSorterWrite(db, pC, pIn2);
+ rc = sqlite3VdbeSorterWrite(pC, pIn2);
}else{
nKey = pIn2->n;
zKey = pIn2->z;
@@ -72794,21 +75663,28 @@ case OP_IdxDelete: {
**
** See also: Rowid, MakeRecord.
*/
-case OP_IdxRowid: { /* out2-prerelease */
+case OP_IdxRowid: { /* out2 */
BtCursor *pCrsr;
VdbeCursor *pC;
i64 rowid;
+ pOut = out2Prerelease(p, pOp);
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
pCrsr = pC->pCursor;
assert( pCrsr!=0 );
pOut->flags = MEM_Null;
- rc = sqlite3VdbeCursorMoveto(pC);
- if( NEVER(rc) ) goto abort_due_to_error;
- assert( pC->deferredMoveto==0 );
assert( pC->isTable==0 );
+ assert( pC->deferredMoveto==0 );
+
+ /* sqlite3VbeCursorRestore() can only fail if the record has been deleted
+ ** out from under the cursor. That will never happend for an IdxRowid
+ ** opcode, hence the NEVER() arround the check of the return value.
+ */
+ rc = sqlite3VdbeCursorRestore(pC);
+ if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error;
+
if( !pC->nullRow ){
rowid = 0; /* Not needed. Only used to silence a warning. */
rc = sqlite3VdbeIdxRowid(db, pCrsr, &rowid);
@@ -72895,7 +75771,7 @@ case OP_IdxGE: { /* jump */
{ int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
#endif
res = 0; /* Not needed. Only used to silence a warning. */
- rc = sqlite3VdbeIdxKeyCompare(pC, &r, &res);
+ rc = sqlite3VdbeIdxKeyCompare(db, pC, &r, &res);
assert( (OP_IdxLE&1)==(OP_IdxLT&1) && (OP_IdxGE&1)==(OP_IdxGT&1) );
if( (pOp->opcode&1)==(OP_IdxLT&1) ){
assert( pOp->opcode==OP_IdxLE || pOp->opcode==OP_IdxLT );
@@ -72905,9 +75781,7 @@ case OP_IdxGE: { /* jump */
res++;
}
VdbeBranchTaken(res>0,2);
- if( res>0 ){
- pc = pOp->p2 - 1 ;
- }
+ if( res>0 ) goto jump_to_p2;
break;
}
@@ -72931,32 +75805,18 @@ case OP_IdxGE: { /* jump */
**
** See also: Clear
*/
-case OP_Destroy: { /* out2-prerelease */
+case OP_Destroy: { /* out2 */
int iMoved;
- int iCnt;
- Vdbe *pVdbe;
int iDb;
assert( p->readOnly==0 );
-#ifndef SQLITE_OMIT_VIRTUALTABLE
- iCnt = 0;
- for(pVdbe=db->pVdbe; pVdbe; pVdbe = pVdbe->pNext){
- if( pVdbe->magic==VDBE_MAGIC_RUN && pVdbe->bIsReader
- && pVdbe->inVtabMethod<2 && pVdbe->pc>=0
- ){
- iCnt++;
- }
- }
-#else
- iCnt = db->nVdbeRead;
-#endif
+ pOut = out2Prerelease(p, pOp);
pOut->flags = MEM_Null;
- if( iCnt>1 ){
+ if( db->nVdbeRead > db->nVDestroy+1 ){
rc = SQLITE_LOCKED;
p->errorAction = OE_Abort;
}else{
iDb = pOp->p3;
- assert( iCnt==1 );
assert( DbMaskTest(p->btreeMask, iDb) );
iMoved = 0; /* Not needed. Only to silence a warning. */
rc = sqlite3BtreeDropTable(db->aDb[iDb].pBt, pOp->p1, &iMoved);
@@ -73059,12 +75919,13 @@ case OP_ResetSorter: {
**
** See documentation on OP_CreateTable for additional information.
*/
-case OP_CreateIndex: /* out2-prerelease */
-case OP_CreateTable: { /* out2-prerelease */
+case OP_CreateIndex: /* out2 */
+case OP_CreateTable: { /* out2 */
int pgno;
int flags;
Db *pDb;
+ pOut = out2Prerelease(p, pOp);
pgno = 0;
assert( pOp->p1>=0 && pOp->p1<db->nDb );
assert( DbMaskTest(p->btreeMask, pOp->p1) );
@@ -73290,12 +76151,12 @@ case OP_RowSetRead: { /* jump, in1, out3 */
){
/* The boolean index is empty */
sqlite3VdbeMemSetNull(pIn1);
- pc = pOp->p2 - 1;
VdbeBranchTaken(1,2);
+ goto jump_to_p2_and_check_for_interrupt;
}else{
/* A value was pulled from the index */
- sqlite3VdbeMemSetInt64(&aMem[pOp->p3], val);
VdbeBranchTaken(0,2);
+ sqlite3VdbeMemSetInt64(&aMem[pOp->p3], val);
}
goto check_for_interrupt;
}
@@ -73346,10 +76207,7 @@ case OP_RowSetTest: { /* jump, in1, in3 */
if( iSet ){
exists = sqlite3RowSetTest(pIn1->u.pRowSet, iSet, pIn3->u.i);
VdbeBranchTaken(exists!=0,2);
- if( exists ){
- pc = pOp->p2 - 1;
- break;
- }
+ if( exists ) goto jump_to_p2;
}
if( iSet>=0 ){
sqlite3RowSetInsert(pIn1->u.pRowSet, pIn3->u.i);
@@ -73438,7 +76296,7 @@ case OP_Program: { /* jump */
pFrame->v = p;
pFrame->nChildMem = nMem;
pFrame->nChildCsr = pProgram->nCsr;
- pFrame->pc = pc;
+ pFrame->pc = (int)(pOp - aOp);
pFrame->aMem = p->aMem;
pFrame->nMem = p->nMem;
pFrame->apCsr = p->apCsr;
@@ -73448,6 +76306,9 @@ case OP_Program: { /* jump */
pFrame->token = pProgram->token;
pFrame->aOnceFlag = p->aOnceFlag;
pFrame->nOnceFlag = p->nOnceFlag;
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ pFrame->anExec = p->anExec;
+#endif
pEnd = &VdbeFrameMem(pFrame)[pFrame->nChildMem];
for(pMem=VdbeFrameMem(pFrame); pMem!=pEnd; pMem++){
@@ -73458,13 +76319,14 @@ case OP_Program: { /* jump */
pFrame = pRt->u.pFrame;
assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem );
assert( pProgram->nCsr==pFrame->nChildCsr );
- assert( pc==pFrame->pc );
+ assert( (int)(pOp - aOp)==pFrame->pc );
}
p->nFrame++;
pFrame->pParent = p->pFrame;
pFrame->lastRowid = lastRowid;
pFrame->nChange = p->nChange;
+ pFrame->nDbChange = p->db->nChange;
p->nChange = 0;
p->pFrame = pFrame;
p->aMem = aMem = &VdbeFrameMem(pFrame)[-1];
@@ -73475,7 +76337,10 @@ case OP_Program: { /* jump */
p->nOp = pProgram->nOp;
p->aOnceFlag = (u8 *)&p->apCsr[p->nCursor];
p->nOnceFlag = pProgram->nOnce;
- pc = -1;
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ p->anExec = 0;
+#endif
+ pOp = &aOp[-1];
memset(p->aOnceFlag, 0, p->nOnceFlag);
break;
@@ -73493,9 +76358,10 @@ case OP_Program: { /* jump */
** the value of the P1 argument to the value of the P1 argument to the
** calling OP_Program instruction.
*/
-case OP_Param: { /* out2-prerelease */
+case OP_Param: { /* out2 */
VdbeFrame *pFrame;
Mem *pIn;
+ pOut = out2Prerelease(p, pOp);
pFrame = p->pFrame;
pIn = &pFrame->aMem[pOp->p1 + pFrame->aOp[pFrame->pc].p1];
sqlite3VdbeMemShallowCopy(pOut, pIn, MEM_Ephem);
@@ -73539,10 +76405,10 @@ case OP_FkCounter: {
case OP_FkIfZero: { /* jump */
if( pOp->p1 ){
VdbeBranchTaken(db->nDeferredCons==0 && db->nDeferredImmCons==0, 2);
- if( db->nDeferredCons==0 && db->nDeferredImmCons==0 ) pc = pOp->p2-1;
+ if( db->nDeferredCons==0 && db->nDeferredImmCons==0 ) goto jump_to_p2;
}else{
VdbeBranchTaken(p->nFkConstraint==0 && db->nDeferredImmCons==0, 2);
- if( p->nFkConstraint==0 && db->nDeferredImmCons==0 ) pc = pOp->p2-1;
+ if( p->nFkConstraint==0 && db->nDeferredImmCons==0 ) goto jump_to_p2;
}
break;
}
@@ -73582,18 +76448,18 @@ case OP_MemMax: { /* in2 */
/* Opcode: IfPos P1 P2 * * *
** Synopsis: if r[P1]>0 goto P2
**
-** If the value of register P1 is 1 or greater, jump to P2.
+** Register P1 must contain an integer.
+** If the value of register P1 is 1 or greater, jump to P2 and
+** add the literal value P3 to register P1.
**
-** It is illegal to use this instruction on a register that does
-** not contain an integer. An assertion fault will result if you try.
+** If the initial value of register P1 is less than 1, then the
+** value is unchanged and control passes through to the next instruction.
*/
case OP_IfPos: { /* jump, in1 */
pIn1 = &aMem[pOp->p1];
assert( pIn1->flags&MEM_Int );
VdbeBranchTaken( pIn1->u.i>0, 2);
- if( pIn1->u.i>0 ){
- pc = pOp->p2 - 1;
- }
+ if( pIn1->u.i>0 ) goto jump_to_p2;
break;
}
@@ -73608,26 +76474,56 @@ case OP_IfNeg: { /* jump, in1 */
assert( pIn1->flags&MEM_Int );
pIn1->u.i += pOp->p3;
VdbeBranchTaken(pIn1->u.i<0, 2);
- if( pIn1->u.i<0 ){
- pc = pOp->p2 - 1;
+ if( pIn1->u.i<0 ) goto jump_to_p2;
+ break;
+}
+
+/* Opcode: IfNotZero P1 P2 P3 * *
+** Synopsis: if r[P1]!=0 then r[P1]+=P3, goto P2
+**
+** Register P1 must contain an integer. If the content of register P1 is
+** initially nonzero, then add P3 to P1 and jump to P2. If register P1 is
+** initially zero, leave it unchanged and fall through.
+*/
+case OP_IfNotZero: { /* jump, in1 */
+ pIn1 = &aMem[pOp->p1];
+ assert( pIn1->flags&MEM_Int );
+ VdbeBranchTaken(pIn1->u.i<0, 2);
+ if( pIn1->u.i ){
+ pIn1->u.i += pOp->p3;
+ goto jump_to_p2;
}
break;
}
-/* Opcode: IfZero P1 P2 P3 * *
-** Synopsis: r[P1]+=P3, if r[P1]==0 goto P2
+/* Opcode: DecrJumpZero P1 P2 * * *
+** Synopsis: if (--r[P1])==0 goto P2
**
-** The register P1 must contain an integer. Add literal P3 to the
-** value in register P1. If the result is exactly 0, jump to P2.
+** Register P1 must hold an integer. Decrement the value in register P1
+** then jump to P2 if the new value is exactly zero.
*/
-case OP_IfZero: { /* jump, in1 */
+case OP_DecrJumpZero: { /* jump, in1 */
pIn1 = &aMem[pOp->p1];
assert( pIn1->flags&MEM_Int );
- pIn1->u.i += pOp->p3;
+ pIn1->u.i--;
VdbeBranchTaken(pIn1->u.i==0, 2);
- if( pIn1->u.i==0 ){
- pc = pOp->p2 - 1;
- }
+ if( pIn1->u.i==0 ) goto jump_to_p2;
+ break;
+}
+
+
+/* Opcode: JumpZeroIncr P1 P2 * * *
+** Synopsis: if (r[P1]++)==0 ) goto P2
+**
+** The register P1 must contain an integer. If register P1 is initially
+** zero, then jump to P2. Increment register P1 regardless of whether or
+** not the jump is taken.
+*/
+case OP_JumpZeroIncr: { /* jump, in1 */
+ pIn1 = &aMem[pOp->p1];
+ assert( pIn1->flags&MEM_Int );
+ VdbeBranchTaken(pIn1->u.i==0, 2);
+ if( (pIn1->u.i++)==0 ) goto jump_to_p2;
break;
}
@@ -73647,6 +76543,7 @@ case OP_AggStep: {
int i;
Mem *pMem;
Mem *pRec;
+ Mem t;
sqlite3_context ctx;
sqlite3_value **apVal;
@@ -73664,23 +76561,15 @@ case OP_AggStep: {
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
ctx.pMem = pMem = &aMem[pOp->p3];
pMem->n++;
- ctx.s.flags = MEM_Null;
- ctx.s.z = 0;
- ctx.s.zMalloc = 0;
- ctx.s.xDel = 0;
- ctx.s.db = db;
+ sqlite3VdbeMemInit(&t, db, MEM_Null);
+ ctx.pOut = &t;
ctx.isError = 0;
- ctx.pColl = 0;
+ ctx.pVdbe = p;
+ ctx.iOp = (int)(pOp - aOp);
ctx.skipFlag = 0;
- if( ctx.pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){
- assert( pOp>p->aOp );
- assert( pOp[-1].p4type==P4_COLLSEQ );
- assert( pOp[-1].opcode==OP_CollSeq );
- ctx.pColl = pOp[-1].p4.pColl;
- }
(ctx.pFunc->xStep)(&ctx, n, apVal); /* IMP: R-24505-23230 */
if( ctx.isError ){
- sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&ctx.s));
+ sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&t));
rc = ctx.isError;
}
if( ctx.skipFlag ){
@@ -73688,9 +76577,7 @@ case OP_AggStep: {
i = pOp[-1].p1;
if( i ) sqlite3VdbeMemSetInt64(&aMem[i], 1);
}
-
- sqlite3VdbeMemRelease(&ctx.s);
-
+ sqlite3VdbeMemRelease(&t);
break;
}
@@ -73728,8 +76615,8 @@ case OP_AggFinal: {
/* Opcode: Checkpoint P1 P2 P3 * *
**
** Checkpoint database P1. This is a no-op if P1 is not currently in
-** WAL mode. Parameter P2 is one of SQLITE_CHECKPOINT_PASSIVE, FULL
-** or RESTART. Write 1 or 0 into mem[P3] if the checkpoint returns
+** WAL mode. Parameter P2 is one of SQLITE_CHECKPOINT_PASSIVE, FULL,
+** RESTART, or TRUNCATE. Write 1 or 0 into mem[P3] if the checkpoint returns
** SQLITE_BUSY or not, respectively. Write the number of pages in the
** WAL after the checkpoint into mem[P3+1] and the number of pages
** in the WAL that have been checkpointed after the checkpoint
@@ -73747,6 +76634,7 @@ case OP_Checkpoint: {
assert( pOp->p2==SQLITE_CHECKPOINT_PASSIVE
|| pOp->p2==SQLITE_CHECKPOINT_FULL
|| pOp->p2==SQLITE_CHECKPOINT_RESTART
+ || pOp->p2==SQLITE_CHECKPOINT_TRUNCATE
);
rc = sqlite3Checkpoint(db, pOp->p1, pOp->p2, &aRes[1], &aRes[2]);
if( rc==SQLITE_BUSY ){
@@ -73772,7 +76660,7 @@ case OP_Checkpoint: {
**
** Write a string containing the final journal-mode to register P2.
*/
-case OP_JournalMode: { /* out2-prerelease */
+case OP_JournalMode: { /* out2 */
Btree *pBt; /* Btree to change journal mode of */
Pager *pPager; /* Pager associated with pBt */
int eNew; /* New journal mode */
@@ -73781,6 +76669,7 @@ case OP_JournalMode: { /* out2-prerelease */
const char *zFilename; /* Name of database file for pPager */
#endif
+ pOut = out2Prerelease(p, pOp);
eNew = pOp->p3;
assert( eNew==PAGER_JOURNALMODE_DELETE
|| eNew==PAGER_JOURNALMODE_TRUNCATE
@@ -73856,7 +76745,6 @@ case OP_JournalMode: { /* out2-prerelease */
}
eNew = sqlite3PagerSetJournalMode(pPager, eNew);
- pOut = &aMem[pOp->p2];
pOut->flags = MEM_Str|MEM_Static|MEM_Term;
pOut->z = (char *)sqlite3JournalModename(eNew);
pOut->n = sqlite3Strlen30(pOut->z);
@@ -73897,8 +76785,8 @@ case OP_IncrVacuum: { /* jump */
rc = sqlite3BtreeIncrVacuum(pBt);
VdbeBranchTaken(rc==SQLITE_DONE,2);
if( rc==SQLITE_DONE ){
- pc = pOp->p2 - 1;
rc = SQLITE_OK;
+ goto jump_to_p2;
}
break;
}
@@ -73976,13 +76864,29 @@ case OP_VBegin: {
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
-/* Opcode: VCreate P1 * * P4 *
+/* Opcode: VCreate P1 P2 * * *
**
-** P4 is the name of a virtual table in database P1. Call the xCreate method
-** for that table.
+** P2 is a register that holds the name of a virtual table in database
+** P1. Call the xCreate method for that table.
*/
case OP_VCreate: {
- rc = sqlite3VtabCallCreate(db, pOp->p1, pOp->p4.z, &p->zErrMsg);
+ Mem sMem; /* For storing the record being decoded */
+ const char *zTab; /* Name of the virtual table */
+
+ memset(&sMem, 0, sizeof(sMem));
+ sMem.db = db;
+ /* Because P2 is always a static string, it is impossible for the
+ ** sqlite3VdbeMemCopy() to fail */
+ assert( (aMem[pOp->p2].flags & MEM_Str)!=0 );
+ assert( (aMem[pOp->p2].flags & MEM_Static)!=0 );
+ rc = sqlite3VdbeMemCopy(&sMem, &aMem[pOp->p2]);
+ assert( rc==SQLITE_OK );
+ zTab = (const char*)sqlite3_value_text(&sMem);
+ assert( zTab || db->mallocFailed );
+ if( zTab ){
+ rc = sqlite3VtabCallCreate(db, pOp->p1, zTab, &p->zErrMsg);
+ }
+ sqlite3VdbeMemRelease(&sMem);
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -73994,9 +76898,9 @@ case OP_VCreate: {
** of that table.
*/
case OP_VDestroy: {
- p->inVtabMethod = 2;
+ db->nVDestroy++;
rc = sqlite3VtabCallDestroy(db, pOp->p1, pOp->p4.z);
- p->inVtabMethod = 0;
+ db->nVDestroy--;
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -74012,14 +76916,17 @@ case OP_VOpen: {
VdbeCursor *pCur;
sqlite3_vtab_cursor *pVtabCursor;
sqlite3_vtab *pVtab;
- sqlite3_module *pModule;
+ const sqlite3_module *pModule;
assert( p->bIsReader );
pCur = 0;
pVtabCursor = 0;
pVtab = pOp->p4.pVtab->pVtab;
- pModule = (sqlite3_module *)pVtab->pModule;
- assert(pVtab && pModule);
+ if( pVtab==0 || NEVER(pVtab->pModule==0) ){
+ rc = SQLITE_LOCKED;
+ break;
+ }
+ pModule = pVtab->pModule;
rc = pModule->xOpen(pVtab, &pVtabCursor);
sqlite3VtabImportErrmsg(p, pVtab);
if( SQLITE_OK==rc ){
@@ -74030,9 +76937,11 @@ case OP_VOpen: {
pCur = allocateCursor(p, pOp->p1, 0, -1, 0);
if( pCur ){
pCur->pVtabCursor = pVtabCursor;
+ pVtab->nRef++;
}else{
- db->mallocFailed = 1;
+ assert( db->mallocFailed );
pModule->xClose(pVtabCursor);
+ goto no_mem;
}
}
break;
@@ -74088,27 +76997,19 @@ case OP_VFilter: { /* jump */
iQuery = (int)pQuery->u.i;
/* Invoke the xFilter method */
- {
- res = 0;
- apArg = p->apArg;
- for(i = 0; i<nArg; i++){
- apArg[i] = &pArgc[i+1];
- }
-
- p->inVtabMethod = 1;
- rc = pModule->xFilter(pVtabCursor, iQuery, pOp->p4.z, nArg, apArg);
- p->inVtabMethod = 0;
- sqlite3VtabImportErrmsg(p, pVtab);
- if( rc==SQLITE_OK ){
- res = pModule->xEof(pVtabCursor);
- }
- VdbeBranchTaken(res!=0,2);
- if( res ){
- pc = pOp->p2 - 1;
- }
+ res = 0;
+ apArg = p->apArg;
+ for(i = 0; i<nArg; i++){
+ apArg[i] = &pArgc[i+1];
+ }
+ rc = pModule->xFilter(pVtabCursor, iQuery, pOp->p4.z, nArg, apArg);
+ sqlite3VtabImportErrmsg(p, pVtab);
+ if( rc==SQLITE_OK ){
+ res = pModule->xEof(pVtabCursor);
}
pCur->nullRow = 0;
-
+ VdbeBranchTaken(res!=0,2);
+ if( res ) goto jump_to_p2;
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -74140,27 +77041,14 @@ case OP_VColumn: {
pModule = pVtab->pModule;
assert( pModule->xColumn );
memset(&sContext, 0, sizeof(sContext));
-
- /* The output cell may already have a buffer allocated. Move
- ** the current contents to sContext.s so in case the user-function
- ** can use the already allocated buffer instead of allocating a
- ** new one.
- */
- sqlite3VdbeMemMove(&sContext.s, pDest);
- MemSetTypeFlag(&sContext.s, MEM_Null);
-
+ sContext.pOut = pDest;
+ MemSetTypeFlag(pDest, MEM_Null);
rc = pModule->xColumn(pCur->pVtabCursor, &sContext, pOp->p2);
sqlite3VtabImportErrmsg(p, pVtab);
if( sContext.isError ){
rc = sContext.isError;
}
-
- /* Copy the result of the function to the P3 register. We
- ** do this regardless of whether or not an error occurred to ensure any
- ** dynamic allocation in sContext.s (a Mem struct) is released.
- */
- sqlite3VdbeChangeEncoding(&sContext.s, encoding);
- sqlite3VdbeMemMove(pDest, &sContext.s);
+ sqlite3VdbeChangeEncoding(pDest, encoding);
REGISTER_TRACE(pOp->p3, pDest);
UPDATE_MAX_BLOBSIZE(pDest);
@@ -74200,9 +77088,7 @@ case OP_VNext: { /* jump */
** data is available) and the error code returned when xColumn or
** some other method is next invoked on the save virtual table cursor.
*/
- p->inVtabMethod = 1;
rc = pModule->xNext(pCur->pVtabCursor);
- p->inVtabMethod = 0;
sqlite3VtabImportErrmsg(p, pVtab);
if( rc==SQLITE_OK ){
res = pModule->xEof(pCur->pVtabCursor);
@@ -74210,7 +77096,7 @@ case OP_VNext: { /* jump */
VdbeBranchTaken(!res,2);
if( !res ){
/* If there is data, jump to P2 */
- pc = pOp->p2 - 1;
+ goto jump_to_p2_and_check_for_interrupt;
}
goto check_for_interrupt;
}
@@ -74277,7 +77163,7 @@ case OP_VRename: {
*/
case OP_VUpdate: {
sqlite3_vtab *pVtab;
- sqlite3_module *pModule;
+ const sqlite3_module *pModule;
int nArg;
int i;
sqlite_int64 rowid;
@@ -74289,7 +77175,11 @@ case OP_VUpdate: {
);
assert( p->readOnly==0 );
pVtab = pOp->p4.pVtab->pVtab;
- pModule = (sqlite3_module *)pVtab->pModule;
+ if( pVtab==0 || NEVER(pVtab->pModule==0) ){
+ rc = SQLITE_LOCKED;
+ break;
+ }
+ pModule = pVtab->pModule;
nArg = pOp->p2;
assert( pOp->p4type==P4_VTAB );
if( ALWAYS(pModule->xUpdate) ){
@@ -74329,7 +77219,8 @@ case OP_VUpdate: {
**
** Write the current number of pages in database P1 to memory cell P2.
*/
-case OP_Pagecount: { /* out2-prerelease */
+case OP_Pagecount: { /* out2 */
+ pOut = out2Prerelease(p, pOp);
pOut->u.i = sqlite3BtreeLastPage(db->aDb[pOp->p1].pBt);
break;
}
@@ -74345,10 +77236,11 @@ case OP_Pagecount: { /* out2-prerelease */
**
** Store the maximum page count after the change in register P2.
*/
-case OP_MaxPgcnt: { /* out2-prerelease */
+case OP_MaxPgcnt: { /* out2 */
unsigned int newMax;
Btree *pBt;
+ pOut = out2Prerelease(p, pOp);
pBt = db->aDb[pOp->p1].pBt;
newMax = 0;
if( pOp->p3 ){
@@ -74377,9 +77269,6 @@ case OP_Init: { /* jump */
char *zTrace;
char *z;
- if( pOp->p2 ){
- pc = pOp->p2 - 1;
- }
#ifndef SQLITE_OMIT_TRACE
if( db->xTrace
&& !p->doingRerun
@@ -74407,6 +77296,7 @@ case OP_Init: { /* jump */
}
#endif /* SQLITE_DEBUG */
#endif /* SQLITE_OMIT_TRACE */
+ if( pOp->p2 ) goto jump_to_p2;
break;
}
@@ -74438,8 +77328,8 @@ default: { /* This is really OP_Noop and OP_Explain */
#ifdef VDBE_PROFILE
{
u64 endTime = sqlite3Hwtime();
- if( endTime>start ) pOp->cycles += endTime - start;
- pOp->cnt++;
+ if( endTime>start ) pOrigOp->cycles += endTime - start;
+ pOrigOp->cnt++;
}
#endif
@@ -74449,16 +77339,16 @@ default: { /* This is really OP_Noop and OP_Explain */
** the evaluator loop. So we can leave it out when NDEBUG is defined.
*/
#ifndef NDEBUG
- assert( pc>=-1 && pc<p->nOp );
+ assert( pOp>=&aOp[-1] && pOp<&aOp[p->nOp-1] );
#ifdef SQLITE_DEBUG
if( db->flags & SQLITE_VdbeTrace ){
if( rc!=0 ) printf("rc=%d\n",rc);
- if( pOp->opflags & (OPFLG_OUT2_PRERELEASE|OPFLG_OUT2) ){
- registerTrace(pOp->p2, &aMem[pOp->p2]);
+ if( pOrigOp->opflags & (OPFLG_OUT2) ){
+ registerTrace(pOrigOp->p2, &aMem[pOrigOp->p2]);
}
- if( pOp->opflags & OPFLG_OUT3 ){
- registerTrace(pOp->p3, &aMem[pOp->p3]);
+ if( pOrigOp->opflags & OPFLG_OUT3 ){
+ registerTrace(pOrigOp->p3, &aMem[pOrigOp->p3]);
}
}
#endif /* SQLITE_DEBUG */
@@ -74473,7 +77363,7 @@ vdbe_error_halt:
p->rc = rc;
testcase( sqlite3GlobalConfig.xLog!=0 );
sqlite3_log(rc, "statement aborts at %d: [%s] %s",
- pc, p->zSql, p->zErrMsg);
+ (int)(pOp - aOp), p->zSql, p->zErrMsg);
sqlite3VdbeHalt(p);
if( rc==SQLITE_IOERR_NOMEM ) db->mallocFailed = 1;
rc = SQLITE_ERROR;
@@ -74636,7 +77526,7 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
/*
** Open a blob handle.
*/
-SQLITE_API int sqlite3_blob_open(
+SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
sqlite3* db, /* The database connection */
const char *zDb, /* The attached database containing the blob */
const char *zTable, /* The table containing the blob */
@@ -74685,8 +77575,18 @@ SQLITE_API int sqlite3_blob_open(
Parse *pParse = 0;
Incrblob *pBlob = 0;
- flags = !!flags; /* flags = (flags ? 1 : 0); */
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( ppBlob==0 ){
+ return SQLITE_MISUSE_BKPT;
+ }
+#endif
*ppBlob = 0;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) || zTable==0 ){
+ return SQLITE_MISUSE_BKPT;
+ }
+#endif
+ flags = !!flags; /* flags = (flags ? 1 : 0); */
sqlite3_mutex_enter(db->mutex);
@@ -74850,7 +77750,7 @@ blob_open_out:
if( pBlob && pBlob->pStmt ) sqlite3VdbeFinalize((Vdbe *)pBlob->pStmt);
sqlite3DbFree(db, pBlob);
}
- sqlite3Error(db, rc, (zErr ? "%s" : 0), zErr);
+ sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr);
sqlite3DbFree(db, zErr);
sqlite3ParserReset(pParse);
sqlite3StackFree(db, pParse);
@@ -74863,7 +77763,7 @@ blob_open_out:
** Close a blob handle that was previously created using
** sqlite3_blob_open().
*/
-SQLITE_API int sqlite3_blob_close(sqlite3_blob *pBlob){
+SQLITE_API int SQLITE_STDCALL sqlite3_blob_close(sqlite3_blob *pBlob){
Incrblob *p = (Incrblob *)pBlob;
int rc;
sqlite3 *db;
@@ -74900,10 +77800,9 @@ static int blobReadWrite(
sqlite3_mutex_enter(db->mutex);
v = (Vdbe*)p->pStmt;
- if( n<0 || iOffset<0 || (iOffset+n)>p->nByte ){
+ if( n<0 || iOffset<0 || ((sqlite3_int64)iOffset+n)>p->nByte ){
/* Request is out of range. Return a transient error. */
rc = SQLITE_ERROR;
- sqlite3Error(db, SQLITE_ERROR, 0);
}else if( v==0 ){
/* If there is no statement handle, then the blob-handle has
** already been invalidated. Return SQLITE_ABORT in this case.
@@ -74921,10 +77820,10 @@ static int blobReadWrite(
sqlite3VdbeFinalize(v);
p->pStmt = 0;
}else{
- db->errCode = rc;
v->rc = rc;
}
}
+ sqlite3Error(db, rc);
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
return rc;
@@ -74933,14 +77832,14 @@ static int blobReadWrite(
/*
** Read data from a blob handle.
*/
-SQLITE_API int sqlite3_blob_read(sqlite3_blob *pBlob, void *z, int n, int iOffset){
+SQLITE_API int SQLITE_STDCALL sqlite3_blob_read(sqlite3_blob *pBlob, void *z, int n, int iOffset){
return blobReadWrite(pBlob, z, n, iOffset, sqlite3BtreeData);
}
/*
** Write data to a blob handle.
*/
-SQLITE_API int sqlite3_blob_write(sqlite3_blob *pBlob, const void *z, int n, int iOffset){
+SQLITE_API int SQLITE_STDCALL sqlite3_blob_write(sqlite3_blob *pBlob, const void *z, int n, int iOffset){
return blobReadWrite(pBlob, (void *)z, n, iOffset, sqlite3BtreePutData);
}
@@ -74950,7 +77849,7 @@ SQLITE_API int sqlite3_blob_write(sqlite3_blob *pBlob, const void *z, int n, int
** The Incrblob.nByte field is fixed for the lifetime of the Incrblob
** so no mutex is required for access.
*/
-SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *pBlob){
+SQLITE_API int SQLITE_STDCALL sqlite3_blob_bytes(sqlite3_blob *pBlob){
Incrblob *p = (Incrblob *)pBlob;
return (p && p->pStmt) ? p->nByte : 0;
}
@@ -74965,7 +77864,7 @@ SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *pBlob){
** subsequent calls to sqlite3_blob_xxx() functions (except blob_close())
** immediately return SQLITE_ABORT.
*/
-SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
+SQLITE_API int SQLITE_STDCALL sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
int rc;
Incrblob *p = (Incrblob *)pBlob;
sqlite3 *db;
@@ -74983,7 +77882,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
char *zErr;
rc = blobSeekToRow(p, iRow, &zErr);
if( rc!=SQLITE_OK ){
- sqlite3Error(db, rc, (zErr ? "%s" : 0), zErr);
+ sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr);
sqlite3DbFree(db, zErr);
}
assert( rc!=SQLITE_SCHEMA );
@@ -75000,7 +77899,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
/************** End of vdbeblob.c ********************************************/
/************** Begin file vdbesort.c ****************************************/
/*
-** 2011 July 9
+** 2011-07-09
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
@@ -75011,42 +77910,203 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
**
*************************************************************************
** This file contains code for the VdbeSorter object, used in concert with
-** a VdbeCursor to sort large numbers of keys (as may be required, for
-** example, by CREATE INDEX statements on tables too large to fit in main
-** memory).
+** a VdbeCursor to sort large numbers of keys for CREATE INDEX statements
+** or by SELECT statements with ORDER BY clauses that cannot be satisfied
+** using indexes and without LIMIT clauses.
+**
+** The VdbeSorter object implements a multi-threaded external merge sort
+** algorithm that is efficient even if the number of elements being sorted
+** exceeds the available memory.
+**
+** Here is the (internal, non-API) interface between this module and the
+** rest of the SQLite system:
+**
+** sqlite3VdbeSorterInit() Create a new VdbeSorter object.
+**
+** sqlite3VdbeSorterWrite() Add a single new row to the VdbeSorter
+** object. The row is a binary blob in the
+** OP_MakeRecord format that contains both
+** the ORDER BY key columns and result columns
+** in the case of a SELECT w/ ORDER BY, or
+** the complete record for an index entry
+** in the case of a CREATE INDEX.
+**
+** sqlite3VdbeSorterRewind() Sort all content previously added.
+** Position the read cursor on the
+** first sorted element.
+**
+** sqlite3VdbeSorterNext() Advance the read cursor to the next sorted
+** element.
+**
+** sqlite3VdbeSorterRowkey() Return the complete binary blob for the
+** row currently under the read cursor.
+**
+** sqlite3VdbeSorterCompare() Compare the binary blob for the row
+** currently under the read cursor against
+** another binary blob X and report if
+** X is strictly less than the read cursor.
+** Used to enforce uniqueness in a
+** CREATE UNIQUE INDEX statement.
+**
+** sqlite3VdbeSorterClose() Close the VdbeSorter object and reclaim
+** all resources.
+**
+** sqlite3VdbeSorterReset() Refurbish the VdbeSorter for reuse. This
+** is like Close() followed by Init() only
+** much faster.
+**
+** The interfaces above must be called in a particular order. Write() can
+** only occur in between Init()/Reset() and Rewind(). Next(), Rowkey(), and
+** Compare() can only occur in between Rewind() and Close()/Reset(). i.e.
+**
+** Init()
+** for each record: Write()
+** Rewind()
+** Rowkey()/Compare()
+** Next()
+** Close()
+**
+** Algorithm:
+**
+** Records passed to the sorter via calls to Write() are initially held
+** unsorted in main memory. Assuming the amount of memory used never exceeds
+** a threshold, when Rewind() is called the set of records is sorted using
+** an in-memory merge sort. In this case, no temporary files are required
+** and subsequent calls to Rowkey(), Next() and Compare() read records
+** directly from main memory.
+**
+** If the amount of space used to store records in main memory exceeds the
+** threshold, then the set of records currently in memory are sorted and
+** written to a temporary file in "Packed Memory Array" (PMA) format.
+** A PMA created at this point is known as a "level-0 PMA". Higher levels
+** of PMAs may be created by merging existing PMAs together - for example
+** merging two or more level-0 PMAs together creates a level-1 PMA.
+**
+** The threshold for the amount of main memory to use before flushing
+** records to a PMA is roughly the same as the limit configured for the
+** page-cache of the main database. Specifically, the threshold is set to
+** the value returned by "PRAGMA main.page_size" multipled by
+** that returned by "PRAGMA main.cache_size", in bytes.
+**
+** If the sorter is running in single-threaded mode, then all PMAs generated
+** are appended to a single temporary file. Or, if the sorter is running in
+** multi-threaded mode then up to (N+1) temporary files may be opened, where
+** N is the configured number of worker threads. In this case, instead of
+** sorting the records and writing the PMA to a temporary file itself, the
+** calling thread usually launches a worker thread to do so. Except, if
+** there are already N worker threads running, the main thread does the work
+** itself.
+**
+** The sorter is running in multi-threaded mode if (a) the library was built
+** with pre-processor symbol SQLITE_MAX_WORKER_THREADS set to a value greater
+** than zero, and (b) worker threads have been enabled at runtime by calling
+** "PRAGMA threads=N" with some value of N greater than 0.
+**
+** When Rewind() is called, any data remaining in memory is flushed to a
+** final PMA. So at this point the data is stored in some number of sorted
+** PMAs within temporary files on disk.
+**
+** If there are fewer than SORTER_MAX_MERGE_COUNT PMAs in total and the
+** sorter is running in single-threaded mode, then these PMAs are merged
+** incrementally as keys are retreived from the sorter by the VDBE. The
+** MergeEngine object, described in further detail below, performs this
+** merge.
+**
+** Or, if running in multi-threaded mode, then a background thread is
+** launched to merge the existing PMAs. Once the background thread has
+** merged T bytes of data into a single sorted PMA, the main thread
+** begins reading keys from that PMA while the background thread proceeds
+** with merging the next T bytes of data. And so on.
+**
+** Parameter T is set to half the value of the memory threshold used
+** by Write() above to determine when to create a new PMA.
+**
+** If there are more than SORTER_MAX_MERGE_COUNT PMAs in total when
+** Rewind() is called, then a hierarchy of incremental-merges is used.
+** First, T bytes of data from the first SORTER_MAX_MERGE_COUNT PMAs on
+** disk are merged together. Then T bytes of data from the second set, and
+** so on, such that no operation ever merges more than SORTER_MAX_MERGE_COUNT
+** PMAs at a time. This done is to improve locality.
+**
+** If running in multi-threaded mode and there are more than
+** SORTER_MAX_MERGE_COUNT PMAs on disk when Rewind() is called, then more
+** than one background thread may be created. Specifically, there may be
+** one background thread for each temporary file on disk, and one background
+** thread to merge the output of each of the others to a single PMA for
+** the main thread to read from.
*/
+/*
+** If SQLITE_DEBUG_SORTER_THREADS is defined, this module outputs various
+** messages to stderr that may be helpful in understanding the performance
+** characteristics of the sorter in multi-threaded mode.
+*/
+#if 0
+# define SQLITE_DEBUG_SORTER_THREADS 1
+#endif
+
+/*
+** Hard-coded maximum amount of data to accumulate in memory before flushing
+** to a level 0 PMA. The purpose of this limit is to prevent various integer
+** overflows. 512MiB.
+*/
+#define SQLITE_MAX_PMASZ (1<<29)
+/*
+** Private objects used by the sorter
+*/
+typedef struct MergeEngine MergeEngine; /* Merge PMAs together */
+typedef struct PmaReader PmaReader; /* Incrementally read one PMA */
+typedef struct PmaWriter PmaWriter; /* Incrementally write one PMA */
+typedef struct SorterRecord SorterRecord; /* A record being sorted */
+typedef struct SortSubtask SortSubtask; /* A sub-task in the sort process */
+typedef struct SorterFile SorterFile; /* Temporary file object wrapper */
+typedef struct SorterList SorterList; /* In-memory list of records */
+typedef struct IncrMerger IncrMerger; /* Read & merge multiple PMAs */
-typedef struct VdbeSorterIter VdbeSorterIter;
-typedef struct SorterRecord SorterRecord;
-typedef struct FileWriter FileWriter;
+/*
+** A container for a temp file handle and the current amount of data
+** stored in the file.
+*/
+struct SorterFile {
+ sqlite3_file *pFd; /* File handle */
+ i64 iEof; /* Bytes of data stored in pFd */
+};
/*
-** NOTES ON DATA STRUCTURE USED FOR N-WAY MERGES:
+** An in-memory list of objects to be sorted.
**
-** As keys are added to the sorter, they are written to disk in a series
-** of sorted packed-memory-arrays (PMAs). The size of each PMA is roughly
-** the same as the cache-size allowed for temporary databases. In order
-** to allow the caller to extract keys from the sorter in sorted order,
-** all PMAs currently stored on disk must be merged together. This comment
-** describes the data structure used to do so. The structure supports
-** merging any number of arrays in a single pass with no redundant comparison
-** operations.
+** If aMemory==0 then each object is allocated separately and the objects
+** are connected using SorterRecord.u.pNext. If aMemory!=0 then all objects
+** are stored in the aMemory[] bulk memory, one right after the other, and
+** are connected using SorterRecord.u.iNext.
+*/
+struct SorterList {
+ SorterRecord *pList; /* Linked list of records */
+ u8 *aMemory; /* If non-NULL, bulk memory to hold pList */
+ int szPMA; /* Size of pList as PMA in bytes */
+};
+
+/*
+** The MergeEngine object is used to combine two or more smaller PMAs into
+** one big PMA using a merge operation. Separate PMAs all need to be
+** combined into one big PMA in order to be able to step through the sorted
+** records in order.
**
-** The aIter[] array contains an iterator for each of the PMAs being merged.
-** An aIter[] iterator either points to a valid key or else is at EOF. For
-** the purposes of the paragraphs below, we assume that the array is actually
-** N elements in size, where N is the smallest power of 2 greater to or equal
-** to the number of iterators being merged. The extra aIter[] elements are
-** treated as if they are empty (always at EOF).
+** The aReadr[] array contains a PmaReader object for each of the PMAs being
+** merged. An aReadr[] object either points to a valid key or else is at EOF.
+** ("EOF" means "End Of File". When aReadr[] is at EOF there is no more data.)
+** For the purposes of the paragraphs below, we assume that the array is
+** actually N elements in size, where N is the smallest power of 2 greater
+** to or equal to the number of PMAs being merged. The extra aReadr[] elements
+** are treated as if they are empty (always at EOF).
**
** The aTree[] array is also N elements in size. The value of N is stored in
-** the VdbeSorter.nTree variable.
+** the MergeEngine.nTree variable.
**
** The final (N/2) elements of aTree[] contain the results of comparing
-** pairs of iterator keys together. Element i contains the result of
-** comparing aIter[2*i-N] and aIter[2*i-N+1]. Whichever key is smaller, the
+** pairs of PMA keys together. Element i contains the result of
+** comparing aReadr[2*i-N] and aReadr[2*i-N+1]. Whichever key is smaller, the
** aTree element is set to the index of it.
**
** For the purposes of this comparison, EOF is considered greater than any
@@ -75054,34 +78114,34 @@ typedef struct FileWriter FileWriter;
** values), it doesn't matter which index is stored.
**
** The (N/4) elements of aTree[] that precede the final (N/2) described
-** above contains the index of the smallest of each block of 4 iterators.
-** And so on. So that aTree[1] contains the index of the iterator that
+** above contains the index of the smallest of each block of 4 PmaReaders
+** And so on. So that aTree[1] contains the index of the PmaReader that
** currently points to the smallest key value. aTree[0] is unused.
**
** Example:
**
-** aIter[0] -> Banana
-** aIter[1] -> Feijoa
-** aIter[2] -> Elderberry
-** aIter[3] -> Currant
-** aIter[4] -> Grapefruit
-** aIter[5] -> Apple
-** aIter[6] -> Durian
-** aIter[7] -> EOF
+** aReadr[0] -> Banana
+** aReadr[1] -> Feijoa
+** aReadr[2] -> Elderberry
+** aReadr[3] -> Currant
+** aReadr[4] -> Grapefruit
+** aReadr[5] -> Apple
+** aReadr[6] -> Durian
+** aReadr[7] -> EOF
**
** aTree[] = { X, 5 0, 5 0, 3, 5, 6 }
**
** The current element is "Apple" (the value of the key indicated by
-** iterator 5). When the Next() operation is invoked, iterator 5 will
+** PmaReader 5). When the Next() operation is invoked, PmaReader 5 will
** be advanced to the next key in its segment. Say the next key is
** "Eggplant":
**
-** aIter[5] -> Eggplant
+** aReadr[5] -> Eggplant
**
-** The contents of aTree[] are updated first by comparing the new iterator
-** 5 key to the current key of iterator 4 (still "Grapefruit"). The iterator
+** The contents of aTree[] are updated first by comparing the new PmaReader
+** 5 key to the current key of PmaReader 4 (still "Grapefruit"). The PmaReader
** 5 value is still smaller, so aTree[6] is set to 5. And so on up the tree.
-** The value of iterator 6 - "Durian" - is now smaller than that of iterator
+** The value of PmaReader 6 - "Durian" - is now smaller than that of PmaReader
** 5, so aTree[3] is set to 6. Key 0 is smaller than key 6 (Banana<Durian),
** so the value written into element 1 of the array is 0. As follows:
**
@@ -75091,97 +78151,250 @@ typedef struct FileWriter FileWriter;
** key comparison operations are required, where N is the number of segments
** being merged (rounded up to the next power of 2).
*/
+struct MergeEngine {
+ int nTree; /* Used size of aTree/aReadr (power of 2) */
+ SortSubtask *pTask; /* Used by this thread only */
+ int *aTree; /* Current state of incremental merge */
+ PmaReader *aReadr; /* Array of PmaReaders to merge data from */
+};
+
+/*
+** This object represents a single thread of control in a sort operation.
+** Exactly VdbeSorter.nTask instances of this object are allocated
+** as part of each VdbeSorter object. Instances are never allocated any
+** other way. VdbeSorter.nTask is set to the number of worker threads allowed
+** (see SQLITE_CONFIG_WORKER_THREADS) plus one (the main thread). Thus for
+** single-threaded operation, there is exactly one instance of this object
+** and for multi-threaded operation there are two or more instances.
+**
+** Essentially, this structure contains all those fields of the VdbeSorter
+** structure for which each thread requires a separate instance. For example,
+** each thread requries its own UnpackedRecord object to unpack records in
+** as part of comparison operations.
+**
+** Before a background thread is launched, variable bDone is set to 0. Then,
+** right before it exits, the thread itself sets bDone to 1. This is used for
+** two purposes:
+**
+** 1. When flushing the contents of memory to a level-0 PMA on disk, to
+** attempt to select a SortSubtask for which there is not already an
+** active background thread (since doing so causes the main thread
+** to block until it finishes).
+**
+** 2. If SQLITE_DEBUG_SORTER_THREADS is defined, to determine if a call
+** to sqlite3ThreadJoin() is likely to block. Cases that are likely to
+** block provoke debugging output.
+**
+** In both cases, the effects of the main thread seeing (bDone==0) even
+** after the thread has finished are not dire. So we don't worry about
+** memory barriers and such here.
+*/
+typedef int (*SorterCompare)(SortSubtask*,int*,const void*,int,const void*,int);
+struct SortSubtask {
+ SQLiteThread *pThread; /* Background thread, if any */
+ int bDone; /* Set if thread is finished but not joined */
+ VdbeSorter *pSorter; /* Sorter that owns this sub-task */
+ UnpackedRecord *pUnpacked; /* Space to unpack a record */
+ SorterList list; /* List for thread to write to a PMA */
+ int nPMA; /* Number of PMAs currently in file */
+ SorterCompare xCompare; /* Compare function to use */
+ SorterFile file; /* Temp file for level-0 PMAs */
+ SorterFile file2; /* Space for other PMAs */
+};
+
+
+/*
+** Main sorter structure. A single instance of this is allocated for each
+** sorter cursor created by the VDBE.
+**
+** mxKeysize:
+** As records are added to the sorter by calls to sqlite3VdbeSorterWrite(),
+** this variable is updated so as to be set to the size on disk of the
+** largest record in the sorter.
+*/
struct VdbeSorter {
- i64 iWriteOff; /* Current write offset within file pTemp1 */
- i64 iReadOff; /* Current read offset within file pTemp1 */
- int nInMemory; /* Current size of pRecord list as PMA */
- int nTree; /* Used size of aTree/aIter (power of 2) */
- int nPMA; /* Number of PMAs stored in pTemp1 */
int mnPmaSize; /* Minimum PMA size, in bytes */
int mxPmaSize; /* Maximum PMA size, in bytes. 0==no limit */
- VdbeSorterIter *aIter; /* Array of iterators to merge */
- int *aTree; /* Current state of incremental merge */
- sqlite3_file *pTemp1; /* PMA file 1 */
- SorterRecord *pRecord; /* Head of in-memory record list */
- UnpackedRecord *pUnpacked; /* Used to unpack keys */
+ int mxKeysize; /* Largest serialized key seen so far */
+ int pgsz; /* Main database page size */
+ PmaReader *pReader; /* Readr data from here after Rewind() */
+ MergeEngine *pMerger; /* Or here, if bUseThreads==0 */
+ sqlite3 *db; /* Database connection */
+ KeyInfo *pKeyInfo; /* How to compare records */
+ UnpackedRecord *pUnpacked; /* Used by VdbeSorterCompare() */
+ SorterList list; /* List of in-memory records */
+ int iMemory; /* Offset of free space in list.aMemory */
+ int nMemory; /* Size of list.aMemory allocation in bytes */
+ u8 bUsePMA; /* True if one or more PMAs created */
+ u8 bUseThreads; /* True to use background threads */
+ u8 iPrev; /* Previous thread used to flush PMA */
+ u8 nTask; /* Size of aTask[] array */
+ u8 typeMask;
+ SortSubtask aTask[1]; /* One or more subtasks */
+};
+
+#define SORTER_TYPE_INTEGER 0x01
+#define SORTER_TYPE_TEXT 0x02
+
+/*
+** An instance of the following object is used to read records out of a
+** PMA, in sorted order. The next key to be read is cached in nKey/aKey.
+** aKey might point into aMap or into aBuffer. If neither of those locations
+** contain a contiguous representation of the key, then aAlloc is allocated
+** and the key is copied into aAlloc and aKey is made to poitn to aAlloc.
+**
+** pFd==0 at EOF.
+*/
+struct PmaReader {
+ i64 iReadOff; /* Current read offset */
+ i64 iEof; /* 1 byte past EOF for this PmaReader */
+ int nAlloc; /* Bytes of space at aAlloc */
+ int nKey; /* Number of bytes in key */
+ sqlite3_file *pFd; /* File handle we are reading from */
+ u8 *aAlloc; /* Space for aKey if aBuffer and pMap wont work */
+ u8 *aKey; /* Pointer to current key */
+ u8 *aBuffer; /* Current read buffer */
+ int nBuffer; /* Size of read buffer in bytes */
+ u8 *aMap; /* Pointer to mapping of entire file */
+ IncrMerger *pIncr; /* Incremental merger */
};
/*
-** The following type is an iterator for a PMA. It caches the current key in
-** variables nKey/aKey. If the iterator is at EOF, pFile==0.
-*/
-struct VdbeSorterIter {
- i64 iReadOff; /* Current read offset */
- i64 iEof; /* 1 byte past EOF for this iterator */
- int nAlloc; /* Bytes of space at aAlloc */
- int nKey; /* Number of bytes in key */
- sqlite3_file *pFile; /* File iterator is reading from */
- u8 *aAlloc; /* Allocated space */
- u8 *aKey; /* Pointer to current key */
- u8 *aBuffer; /* Current read buffer */
- int nBuffer; /* Size of read buffer in bytes */
+** Normally, a PmaReader object iterates through an existing PMA stored
+** within a temp file. However, if the PmaReader.pIncr variable points to
+** an object of the following type, it may be used to iterate/merge through
+** multiple PMAs simultaneously.
+**
+** There are two types of IncrMerger object - single (bUseThread==0) and
+** multi-threaded (bUseThread==1).
+**
+** A multi-threaded IncrMerger object uses two temporary files - aFile[0]
+** and aFile[1]. Neither file is allowed to grow to more than mxSz bytes in
+** size. When the IncrMerger is initialized, it reads enough data from
+** pMerger to populate aFile[0]. It then sets variables within the
+** corresponding PmaReader object to read from that file and kicks off
+** a background thread to populate aFile[1] with the next mxSz bytes of
+** sorted record data from pMerger.
+**
+** When the PmaReader reaches the end of aFile[0], it blocks until the
+** background thread has finished populating aFile[1]. It then exchanges
+** the contents of the aFile[0] and aFile[1] variables within this structure,
+** sets the PmaReader fields to read from the new aFile[0] and kicks off
+** another background thread to populate the new aFile[1]. And so on, until
+** the contents of pMerger are exhausted.
+**
+** A single-threaded IncrMerger does not open any temporary files of its
+** own. Instead, it has exclusive access to mxSz bytes of space beginning
+** at offset iStartOff of file pTask->file2. And instead of using a
+** background thread to prepare data for the PmaReader, with a single
+** threaded IncrMerger the allocate part of pTask->file2 is "refilled" with
+** keys from pMerger by the calling thread whenever the PmaReader runs out
+** of data.
+*/
+struct IncrMerger {
+ SortSubtask *pTask; /* Task that owns this merger */
+ MergeEngine *pMerger; /* Merge engine thread reads data from */
+ i64 iStartOff; /* Offset to start writing file at */
+ int mxSz; /* Maximum bytes of data to store */
+ int bEof; /* Set to true when merge is finished */
+ int bUseThread; /* True to use a bg thread for this object */
+ SorterFile aFile[2]; /* aFile[0] for reading, [1] for writing */
};
/*
-** An instance of this structure is used to organize the stream of records
-** being written to files by the merge-sort code into aligned, page-sized
-** blocks. Doing all I/O in aligned page-sized blocks helps I/O to go
-** faster on many operating systems.
+** An instance of this object is used for writing a PMA.
+**
+** The PMA is written one record at a time. Each record is of an arbitrary
+** size. But I/O is more efficient if it occurs in page-sized blocks where
+** each block is aligned on a page boundary. This object caches writes to
+** the PMA so that aligned, page-size blocks are written.
*/
-struct FileWriter {
+struct PmaWriter {
int eFWErr; /* Non-zero if in an error state */
u8 *aBuffer; /* Pointer to write buffer */
int nBuffer; /* Size of write buffer in bytes */
int iBufStart; /* First byte of buffer to write */
int iBufEnd; /* Last byte of buffer to write */
i64 iWriteOff; /* Offset of start of buffer in file */
- sqlite3_file *pFile; /* File to write to */
+ sqlite3_file *pFd; /* File handle to write to */
};
/*
-** A structure to store a single record. All in-memory records are connected
-** together into a linked list headed at VdbeSorter.pRecord using the
-** SorterRecord.pNext pointer.
+** This object is the header on a single record while that record is being
+** held in memory and prior to being written out as part of a PMA.
+**
+** How the linked list is connected depends on how memory is being managed
+** by this module. If using a separate allocation for each in-memory record
+** (VdbeSorter.list.aMemory==0), then the list is always connected using the
+** SorterRecord.u.pNext pointers.
+**
+** Or, if using the single large allocation method (VdbeSorter.list.aMemory!=0),
+** then while records are being accumulated the list is linked using the
+** SorterRecord.u.iNext offset. This is because the aMemory[] array may
+** be sqlite3Realloc()ed while records are being accumulated. Once the VM
+** has finished passing records to the sorter, or when the in-memory buffer
+** is full, the list is sorted. As part of the sorting process, it is
+** converted to use the SorterRecord.u.pNext pointers. See function
+** vdbeSorterSort() for details.
*/
struct SorterRecord {
- void *pVal;
- int nVal;
- SorterRecord *pNext;
+ int nVal; /* Size of the record in bytes */
+ union {
+ SorterRecord *pNext; /* Pointer to next record in list */
+ int iNext; /* Offset within aMemory of next record */
+ } u;
+ /* The data for the record immediately follows this header */
};
-/* Minimum allowable value for the VdbeSorter.nWorking variable */
-#define SORTER_MIN_WORKING 10
+/* Return a pointer to the buffer containing the record data for SorterRecord
+** object p. Should be used as if:
+**
+** void *SRVAL(SorterRecord *p) { return (void*)&p[1]; }
+*/
+#define SRVAL(p) ((void*)((SorterRecord*)(p) + 1))
+
-/* Maximum number of segments to merge in a single pass. */
+/* Maximum number of PMAs that a single MergeEngine can merge */
#define SORTER_MAX_MERGE_COUNT 16
+static int vdbeIncrSwap(IncrMerger*);
+static void vdbeIncrFree(IncrMerger *);
+
/*
-** Free all memory belonging to the VdbeSorterIter object passed as the second
+** Free all memory belonging to the PmaReader object passed as the
** argument. All structure fields are set to zero before returning.
*/
-static void vdbeSorterIterZero(sqlite3 *db, VdbeSorterIter *pIter){
- sqlite3DbFree(db, pIter->aAlloc);
- sqlite3DbFree(db, pIter->aBuffer);
- memset(pIter, 0, sizeof(VdbeSorterIter));
+static void vdbePmaReaderClear(PmaReader *pReadr){
+ sqlite3_free(pReadr->aAlloc);
+ sqlite3_free(pReadr->aBuffer);
+ if( pReadr->aMap ) sqlite3OsUnfetch(pReadr->pFd, 0, pReadr->aMap);
+ vdbeIncrFree(pReadr->pIncr);
+ memset(pReadr, 0, sizeof(PmaReader));
}
/*
-** Read nByte bytes of data from the stream of data iterated by object p.
+** Read the next nByte bytes of data from the PMA p.
** If successful, set *ppOut to point to a buffer containing the data
** and return SQLITE_OK. Otherwise, if an error occurs, return an SQLite
** error code.
**
-** The buffer indicated by *ppOut may only be considered valid until the
+** The buffer returned in *ppOut is only valid until the
** next call to this function.
*/
-static int vdbeSorterIterRead(
- sqlite3 *db, /* Database handle (for malloc) */
- VdbeSorterIter *p, /* Iterator */
+static int vdbePmaReadBlob(
+ PmaReader *p, /* PmaReader from which to take the blob */
int nByte, /* Bytes of data to read */
u8 **ppOut /* OUT: Pointer to buffer containing data */
){
int iBuf; /* Offset within buffer to read from */
int nAvail; /* Bytes of data available in buffer */
+
+ if( p->aMap ){
+ *ppOut = &p->aMap[p->iReadOff];
+ p->iReadOff += nByte;
+ return SQLITE_OK;
+ }
+
assert( p->aBuffer );
/* If there is no more data to be read from the buffer, read the next
@@ -75200,8 +78413,8 @@ static int vdbeSorterIterRead(
}
assert( nRead>0 );
- /* Read data from the file. Return early if an error occurs. */
- rc = sqlite3OsRead(p->pFile, p->aBuffer, nRead, p->iReadOff);
+ /* Readr data from the file. Return early if an error occurs. */
+ rc = sqlite3OsRead(p->pFd, p->aBuffer, nRead, p->iReadOff);
assert( rc!=SQLITE_IOERR_SHORT_READ );
if( rc!=SQLITE_OK ) return rc;
}
@@ -75221,11 +78434,13 @@ static int vdbeSorterIterRead(
/* Extend the p->aAlloc[] allocation if required. */
if( p->nAlloc<nByte ){
- int nNew = p->nAlloc*2;
+ u8 *aNew;
+ int nNew = MAX(128, p->nAlloc*2);
while( nByte>nNew ) nNew = nNew*2;
- p->aAlloc = sqlite3DbReallocOrFree(db, p->aAlloc, nNew);
- if( !p->aAlloc ) return SQLITE_NOMEM;
+ aNew = sqlite3Realloc(p->aAlloc, nNew);
+ if( !aNew ) return SQLITE_NOMEM;
p->nAlloc = nNew;
+ p->aAlloc = aNew;
}
/* Copy as much data as is available in the buffer into the start of
@@ -75237,13 +78452,13 @@ static int vdbeSorterIterRead(
/* The following loop copies up to p->nBuffer bytes per iteration into
** the p->aAlloc[] buffer. */
while( nRem>0 ){
- int rc; /* vdbeSorterIterRead() return code */
+ int rc; /* vdbePmaReadBlob() return code */
int nCopy; /* Number of bytes to copy */
u8 *aNext; /* Pointer to buffer to copy data from */
nCopy = nRem;
if( nRem>p->nBuffer ) nCopy = p->nBuffer;
- rc = vdbeSorterIterRead(db, p, nCopy, &aNext);
+ rc = vdbePmaReadBlob(p, nCopy, &aNext);
if( rc!=SQLITE_OK ) return rc;
assert( aNext!=p->aAlloc );
memcpy(&p->aAlloc[nByte - nRem], aNext, nCopy);
@@ -75260,234 +78475,444 @@ static int vdbeSorterIterRead(
** Read a varint from the stream of data accessed by p. Set *pnOut to
** the value read.
*/
-static int vdbeSorterIterVarint(sqlite3 *db, VdbeSorterIter *p, u64 *pnOut){
+static int vdbePmaReadVarint(PmaReader *p, u64 *pnOut){
int iBuf;
- iBuf = p->iReadOff % p->nBuffer;
- if( iBuf && (p->nBuffer-iBuf)>=9 ){
- p->iReadOff += sqlite3GetVarint(&p->aBuffer[iBuf], pnOut);
+ if( p->aMap ){
+ p->iReadOff += sqlite3GetVarint(&p->aMap[p->iReadOff], pnOut);
}else{
- u8 aVarint[16], *a;
- int i = 0, rc;
- do{
- rc = vdbeSorterIterRead(db, p, 1, &a);
- if( rc ) return rc;
- aVarint[(i++)&0xf] = a[0];
- }while( (a[0]&0x80)!=0 );
- sqlite3GetVarint(aVarint, pnOut);
+ iBuf = p->iReadOff % p->nBuffer;
+ if( iBuf && (p->nBuffer-iBuf)>=9 ){
+ p->iReadOff += sqlite3GetVarint(&p->aBuffer[iBuf], pnOut);
+ }else{
+ u8 aVarint[16], *a;
+ int i = 0, rc;
+ do{
+ rc = vdbePmaReadBlob(p, 1, &a);
+ if( rc ) return rc;
+ aVarint[(i++)&0xf] = a[0];
+ }while( (a[0]&0x80)!=0 );
+ sqlite3GetVarint(aVarint, pnOut);
+ }
}
return SQLITE_OK;
}
+/*
+** Attempt to memory map file pFile. If successful, set *pp to point to the
+** new mapping and return SQLITE_OK. If the mapping is not attempted
+** (because the file is too large or the VFS layer is configured not to use
+** mmap), return SQLITE_OK and set *pp to NULL.
+**
+** Or, if an error occurs, return an SQLite error code. The final value of
+** *pp is undefined in this case.
+*/
+static int vdbeSorterMapFile(SortSubtask *pTask, SorterFile *pFile, u8 **pp){
+ int rc = SQLITE_OK;
+ if( pFile->iEof<=(i64)(pTask->pSorter->db->nMaxSorterMmap) ){
+ sqlite3_file *pFd = pFile->pFd;
+ if( pFd->pMethods->iVersion>=3 ){
+ rc = sqlite3OsFetch(pFd, 0, (int)pFile->iEof, (void**)pp);
+ testcase( rc!=SQLITE_OK );
+ }
+ }
+ return rc;
+}
/*
-** Advance iterator pIter to the next key in its PMA. Return SQLITE_OK if
-** no error occurs, or an SQLite error code if one does.
+** Attach PmaReader pReadr to file pFile (if it is not already attached to
+** that file) and seek it to offset iOff within the file. Return SQLITE_OK
+** if successful, or an SQLite error code if an error occurs.
*/
-static int vdbeSorterIterNext(
- sqlite3 *db, /* Database handle (for sqlite3DbMalloc() ) */
- VdbeSorterIter *pIter /* Iterator to advance */
+static int vdbePmaReaderSeek(
+ SortSubtask *pTask, /* Task context */
+ PmaReader *pReadr, /* Reader whose cursor is to be moved */
+ SorterFile *pFile, /* Sorter file to read from */
+ i64 iOff /* Offset in pFile */
){
- int rc; /* Return Code */
+ int rc = SQLITE_OK;
+
+ assert( pReadr->pIncr==0 || pReadr->pIncr->bEof==0 );
+
+ if( sqlite3FaultSim(201) ) return SQLITE_IOERR_READ;
+ if( pReadr->aMap ){
+ sqlite3OsUnfetch(pReadr->pFd, 0, pReadr->aMap);
+ pReadr->aMap = 0;
+ }
+ pReadr->iReadOff = iOff;
+ pReadr->iEof = pFile->iEof;
+ pReadr->pFd = pFile->pFd;
+
+ rc = vdbeSorterMapFile(pTask, pFile, &pReadr->aMap);
+ if( rc==SQLITE_OK && pReadr->aMap==0 ){
+ int pgsz = pTask->pSorter->pgsz;
+ int iBuf = pReadr->iReadOff % pgsz;
+ if( pReadr->aBuffer==0 ){
+ pReadr->aBuffer = (u8*)sqlite3Malloc(pgsz);
+ if( pReadr->aBuffer==0 ) rc = SQLITE_NOMEM;
+ pReadr->nBuffer = pgsz;
+ }
+ if( rc==SQLITE_OK && iBuf ){
+ int nRead = pgsz - iBuf;
+ if( (pReadr->iReadOff + nRead) > pReadr->iEof ){
+ nRead = (int)(pReadr->iEof - pReadr->iReadOff);
+ }
+ rc = sqlite3OsRead(
+ pReadr->pFd, &pReadr->aBuffer[iBuf], nRead, pReadr->iReadOff
+ );
+ testcase( rc!=SQLITE_OK );
+ }
+ }
+
+ return rc;
+}
+
+/*
+** Advance PmaReader pReadr to the next key in its PMA. Return SQLITE_OK if
+** no error occurs, or an SQLite error code if one does.
+*/
+static int vdbePmaReaderNext(PmaReader *pReadr){
+ int rc = SQLITE_OK; /* Return Code */
u64 nRec = 0; /* Size of record in bytes */
- if( pIter->iReadOff>=pIter->iEof ){
- /* This is an EOF condition */
- vdbeSorterIterZero(db, pIter);
- return SQLITE_OK;
+
+ if( pReadr->iReadOff>=pReadr->iEof ){
+ IncrMerger *pIncr = pReadr->pIncr;
+ int bEof = 1;
+ if( pIncr ){
+ rc = vdbeIncrSwap(pIncr);
+ if( rc==SQLITE_OK && pIncr->bEof==0 ){
+ rc = vdbePmaReaderSeek(
+ pIncr->pTask, pReadr, &pIncr->aFile[0], pIncr->iStartOff
+ );
+ bEof = 0;
+ }
+ }
+
+ if( bEof ){
+ /* This is an EOF condition */
+ vdbePmaReaderClear(pReadr);
+ testcase( rc!=SQLITE_OK );
+ return rc;
+ }
}
- rc = vdbeSorterIterVarint(db, pIter, &nRec);
if( rc==SQLITE_OK ){
- pIter->nKey = (int)nRec;
- rc = vdbeSorterIterRead(db, pIter, (int)nRec, &pIter->aKey);
+ rc = vdbePmaReadVarint(pReadr, &nRec);
+ }
+ if( rc==SQLITE_OK ){
+ pReadr->nKey = (int)nRec;
+ rc = vdbePmaReadBlob(pReadr, (int)nRec, &pReadr->aKey);
+ testcase( rc!=SQLITE_OK );
}
return rc;
}
/*
-** Initialize iterator pIter to scan through the PMA stored in file pFile
+** Initialize PmaReader pReadr to scan through the PMA stored in file pFile
** starting at offset iStart and ending at offset iEof-1. This function
-** leaves the iterator pointing to the first key in the PMA (or EOF if the
+** leaves the PmaReader pointing to the first key in the PMA (or EOF if the
** PMA is empty).
+**
+** If the pnByte parameter is NULL, then it is assumed that the file
+** contains a single PMA, and that that PMA omits the initial length varint.
*/
-static int vdbeSorterIterInit(
- sqlite3 *db, /* Database handle */
- const VdbeSorter *pSorter, /* Sorter object */
+static int vdbePmaReaderInit(
+ SortSubtask *pTask, /* Task context */
+ SorterFile *pFile, /* Sorter file to read from */
i64 iStart, /* Start offset in pFile */
- VdbeSorterIter *pIter, /* Iterator to populate */
+ PmaReader *pReadr, /* PmaReader to populate */
i64 *pnByte /* IN/OUT: Increment this value by PMA size */
){
- int rc = SQLITE_OK;
- int nBuf;
-
- nBuf = sqlite3BtreeGetPageSize(db->aDb[0].pBt);
-
- assert( pSorter->iWriteOff>iStart );
- assert( pIter->aAlloc==0 );
- assert( pIter->aBuffer==0 );
- pIter->pFile = pSorter->pTemp1;
- pIter->iReadOff = iStart;
- pIter->nAlloc = 128;
- pIter->aAlloc = (u8 *)sqlite3DbMallocRaw(db, pIter->nAlloc);
- pIter->nBuffer = nBuf;
- pIter->aBuffer = (u8 *)sqlite3DbMallocRaw(db, nBuf);
+ int rc;
- if( !pIter->aBuffer ){
- rc = SQLITE_NOMEM;
- }else{
- int iBuf;
+ assert( pFile->iEof>iStart );
+ assert( pReadr->aAlloc==0 && pReadr->nAlloc==0 );
+ assert( pReadr->aBuffer==0 );
+ assert( pReadr->aMap==0 );
- iBuf = iStart % nBuf;
- if( iBuf ){
- int nRead = nBuf - iBuf;
- if( (iStart + nRead) > pSorter->iWriteOff ){
- nRead = (int)(pSorter->iWriteOff - iStart);
- }
- rc = sqlite3OsRead(
- pSorter->pTemp1, &pIter->aBuffer[iBuf], nRead, iStart
- );
- }
-
- if( rc==SQLITE_OK ){
- u64 nByte; /* Size of PMA in bytes */
- pIter->iEof = pSorter->iWriteOff;
- rc = vdbeSorterIterVarint(db, pIter, &nByte);
- pIter->iEof = pIter->iReadOff + nByte;
- *pnByte += nByte;
- }
+ rc = vdbePmaReaderSeek(pTask, pReadr, pFile, iStart);
+ if( rc==SQLITE_OK ){
+ u64 nByte; /* Size of PMA in bytes */
+ rc = vdbePmaReadVarint(pReadr, &nByte);
+ pReadr->iEof = pReadr->iReadOff + nByte;
+ *pnByte += nByte;
}
if( rc==SQLITE_OK ){
- rc = vdbeSorterIterNext(db, pIter);
+ rc = vdbePmaReaderNext(pReadr);
}
return rc;
}
+/*
+** A version of vdbeSorterCompare() that assumes that it has already been
+** determined that the first field of key1 is equal to the first field of
+** key2.
+*/
+static int vdbeSorterCompareTail(
+ SortSubtask *pTask, /* Subtask context (for pKeyInfo) */
+ int *pbKey2Cached, /* True if pTask->pUnpacked is pKey2 */
+ const void *pKey1, int nKey1, /* Left side of comparison */
+ const void *pKey2, int nKey2 /* Right side of comparison */
+){
+ UnpackedRecord *r2 = pTask->pUnpacked;
+ if( *pbKey2Cached==0 ){
+ sqlite3VdbeRecordUnpack(pTask->pSorter->pKeyInfo, nKey2, pKey2, r2);
+ *pbKey2Cached = 1;
+ }
+ return sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, r2, 1);
+}
/*
** Compare key1 (buffer pKey1, size nKey1 bytes) with key2 (buffer pKey2,
-** size nKey2 bytes). Argument pKeyInfo supplies the collation functions
-** used by the comparison. If an error occurs, return an SQLite error code.
-** Otherwise, return SQLITE_OK and set *pRes to a negative, zero or positive
-** value, depending on whether key1 is smaller, equal to or larger than key2.
-**
-** If the bOmitRowid argument is non-zero, assume both keys end in a rowid
-** field. For the purposes of the comparison, ignore it. Also, if bOmitRowid
-** is true and key1 contains even a single NULL value, it is considered to
-** be less than key2. Even if key2 also contains NULL values.
-**
-** If pKey2 is passed a NULL pointer, then it is assumed that the pCsr->aSpace
-** has been allocated and contains an unpacked record that is used as key2.
-*/
-static void vdbeSorterCompare(
- const VdbeCursor *pCsr, /* Cursor object (for pKeyInfo) */
- int nKeyCol, /* Num of columns. 0 means "all" */
+** size nKey2 bytes). Use (pTask->pKeyInfo) for the collation sequences
+** used by the comparison. Return the result of the comparison.
+**
+** If IN/OUT parameter *pbKey2Cached is true when this function is called,
+** it is assumed that (pTask->pUnpacked) contains the unpacked version
+** of key2. If it is false, (pTask->pUnpacked) is populated with the unpacked
+** version of key2 and *pbKey2Cached set to true before returning.
+**
+** If an OOM error is encountered, (pTask->pUnpacked->error_rc) is set
+** to SQLITE_NOMEM.
+*/
+static int vdbeSorterCompare(
+ SortSubtask *pTask, /* Subtask context (for pKeyInfo) */
+ int *pbKey2Cached, /* True if pTask->pUnpacked is pKey2 */
const void *pKey1, int nKey1, /* Left side of comparison */
- const void *pKey2, int nKey2, /* Right side of comparison */
- int *pRes /* OUT: Result of comparison */
+ const void *pKey2, int nKey2 /* Right side of comparison */
){
- KeyInfo *pKeyInfo = pCsr->pKeyInfo;
- VdbeSorter *pSorter = pCsr->pSorter;
- UnpackedRecord *r2 = pSorter->pUnpacked;
- int i;
+ UnpackedRecord *r2 = pTask->pUnpacked;
+ if( !*pbKey2Cached ){
+ sqlite3VdbeRecordUnpack(pTask->pSorter->pKeyInfo, nKey2, pKey2, r2);
+ *pbKey2Cached = 1;
+ }
+ return sqlite3VdbeRecordCompare(nKey1, pKey1, r2);
+}
- if( pKey2 ){
- sqlite3VdbeRecordUnpack(pKeyInfo, nKey2, pKey2, r2);
+/*
+** A specially optimized version of vdbeSorterCompare() that assumes that
+** the first field of each key is a TEXT value and that the collation
+** sequence to compare them with is BINARY.
+*/
+static int vdbeSorterCompareText(
+ SortSubtask *pTask, /* Subtask context (for pKeyInfo) */
+ int *pbKey2Cached, /* True if pTask->pUnpacked is pKey2 */
+ const void *pKey1, int nKey1, /* Left side of comparison */
+ const void *pKey2, int nKey2 /* Right side of comparison */
+){
+ const u8 * const p1 = (const u8 * const)pKey1;
+ const u8 * const p2 = (const u8 * const)pKey2;
+ const u8 * const v1 = &p1[ p1[0] ]; /* Pointer to value 1 */
+ const u8 * const v2 = &p2[ p2[0] ]; /* Pointer to value 2 */
+
+ int n1;
+ int n2;
+ int res;
+
+ getVarint32(&p1[1], n1); n1 = (n1 - 13) / 2;
+ getVarint32(&p2[1], n2); n2 = (n2 - 13) / 2;
+ res = memcmp(v1, v2, MIN(n1, n2));
+ if( res==0 ){
+ res = n1 - n2;
}
- if( nKeyCol ){
- r2->nField = nKeyCol;
- for(i=0; i<nKeyCol; i++){
- if( r2->aMem[i].flags & MEM_Null ){
- *pRes = -1;
- return;
- }
+ if( res==0 ){
+ if( pTask->pSorter->pKeyInfo->nField>1 ){
+ res = vdbeSorterCompareTail(
+ pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2
+ );
+ }
+ }else{
+ if( pTask->pSorter->pKeyInfo->aSortOrder[0] ){
+ res = res * -1;
}
- assert( r2->default_rc==0 );
}
- *pRes = sqlite3VdbeRecordCompare(nKey1, pKey1, r2, 0);
+ return res;
}
/*
-** This function is called to compare two iterator keys when merging
-** multiple b-tree segments. Parameter iOut is the index of the aTree[]
-** value to recalculate.
+** A specially optimized version of vdbeSorterCompare() that assumes that
+** the first field of each key is an INTEGER value.
*/
-static int vdbeSorterDoCompare(const VdbeCursor *pCsr, int iOut){
- VdbeSorter *pSorter = pCsr->pSorter;
- int i1;
- int i2;
- int iRes;
- VdbeSorterIter *p1;
- VdbeSorterIter *p2;
-
- assert( iOut<pSorter->nTree && iOut>0 );
+static int vdbeSorterCompareInt(
+ SortSubtask *pTask, /* Subtask context (for pKeyInfo) */
+ int *pbKey2Cached, /* True if pTask->pUnpacked is pKey2 */
+ const void *pKey1, int nKey1, /* Left side of comparison */
+ const void *pKey2, int nKey2 /* Right side of comparison */
+){
+ const u8 * const p1 = (const u8 * const)pKey1;
+ const u8 * const p2 = (const u8 * const)pKey2;
+ const int s1 = p1[1]; /* Left hand serial type */
+ const int s2 = p2[1]; /* Right hand serial type */
+ const u8 * const v1 = &p1[ p1[0] ]; /* Pointer to value 1 */
+ const u8 * const v2 = &p2[ p2[0] ]; /* Pointer to value 2 */
+ int res; /* Return value */
+
+ assert( (s1>0 && s1<7) || s1==8 || s1==9 );
+ assert( (s2>0 && s2<7) || s2==8 || s2==9 );
+
+ if( s1>7 && s2>7 ){
+ res = s1 - s2;
+ }else{
+ if( s1==s2 ){
+ if( (*v1 ^ *v2) & 0x80 ){
+ /* The two values have different signs */
+ res = (*v1 & 0x80) ? -1 : +1;
+ }else{
+ /* The two values have the same sign. Compare using memcmp(). */
+ static const u8 aLen[] = {0, 1, 2, 3, 4, 6, 8 };
+ int i;
+ res = 0;
+ for(i=0; i<aLen[s1]; i++){
+ if( (res = v1[i] - v2[i]) ) break;
+ }
+ }
+ }else{
+ if( s2>7 ){
+ res = +1;
+ }else if( s1>7 ){
+ res = -1;
+ }else{
+ res = s1 - s2;
+ }
+ assert( res!=0 );
- if( iOut>=(pSorter->nTree/2) ){
- i1 = (iOut - pSorter->nTree/2) * 2;
- i2 = i1 + 1;
- }else{
- i1 = pSorter->aTree[iOut*2];
- i2 = pSorter->aTree[iOut*2+1];
+ if( res>0 ){
+ if( *v1 & 0x80 ) res = -1;
+ }else{
+ if( *v2 & 0x80 ) res = +1;
+ }
+ }
}
- p1 = &pSorter->aIter[i1];
- p2 = &pSorter->aIter[i2];
-
- if( p1->pFile==0 ){
- iRes = i2;
- }else if( p2->pFile==0 ){
- iRes = i1;
- }else{
- int res;
- assert( pCsr->pSorter->pUnpacked!=0 ); /* allocated in vdbeSorterMerge() */
- vdbeSorterCompare(
- pCsr, 0, p1->aKey, p1->nKey, p2->aKey, p2->nKey, &res
- );
- if( res<=0 ){
- iRes = i1;
- }else{
- iRes = i2;
+ if( res==0 ){
+ if( pTask->pSorter->pKeyInfo->nField>1 ){
+ res = vdbeSorterCompareTail(
+ pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2
+ );
}
+ }else if( pTask->pSorter->pKeyInfo->aSortOrder[0] ){
+ res = res * -1;
}
- pSorter->aTree[iOut] = iRes;
- return SQLITE_OK;
+ return res;
}
/*
** Initialize the temporary index cursor just opened as a sorter cursor.
+**
+** Usually, the sorter module uses the value of (pCsr->pKeyInfo->nField)
+** to determine the number of fields that should be compared from the
+** records being sorted. However, if the value passed as argument nField
+** is non-zero and the sorter is able to guarantee a stable sort, nField
+** is used instead. This is used when sorting records for a CREATE INDEX
+** statement. In this case, keys are always delivered to the sorter in
+** order of the primary key, which happens to be make up the final part
+** of the records being sorted. So if the sort is stable, there is never
+** any reason to compare PK fields and they can be ignored for a small
+** performance boost.
+**
+** The sorter can guarantee a stable sort when running in single-threaded
+** mode, but not in multi-threaded mode.
+**
+** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
*/
-SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *db, VdbeCursor *pCsr){
+SQLITE_PRIVATE int sqlite3VdbeSorterInit(
+ sqlite3 *db, /* Database connection (for malloc()) */
+ int nField, /* Number of key fields in each record */
+ VdbeCursor *pCsr /* Cursor that holds the new sorter */
+){
int pgsz; /* Page size of main database */
+ int i; /* Used to iterate through aTask[] */
int mxCache; /* Cache size */
VdbeSorter *pSorter; /* The new sorter */
- char *d; /* Dummy */
+ KeyInfo *pKeyInfo; /* Copy of pCsr->pKeyInfo with db==0 */
+ int szKeyInfo; /* Size of pCsr->pKeyInfo in bytes */
+ int sz; /* Size of pSorter in bytes */
+ int rc = SQLITE_OK;
+#if SQLITE_MAX_WORKER_THREADS==0
+# define nWorker 0
+#else
+ int nWorker;
+#endif
+
+ /* Initialize the upper limit on the number of worker threads */
+#if SQLITE_MAX_WORKER_THREADS>0
+ if( sqlite3TempInMemory(db) || sqlite3GlobalConfig.bCoreMutex==0 ){
+ nWorker = 0;
+ }else{
+ nWorker = db->aLimit[SQLITE_LIMIT_WORKER_THREADS];
+ }
+#endif
+
+ /* Do not allow the total number of threads (main thread + all workers)
+ ** to exceed the maximum merge count */
+#if SQLITE_MAX_WORKER_THREADS>=SORTER_MAX_MERGE_COUNT
+ if( nWorker>=SORTER_MAX_MERGE_COUNT ){
+ nWorker = SORTER_MAX_MERGE_COUNT-1;
+ }
+#endif
assert( pCsr->pKeyInfo && pCsr->pBt==0 );
- pCsr->pSorter = pSorter = sqlite3DbMallocZero(db, sizeof(VdbeSorter));
+ szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nField-1)*sizeof(CollSeq*);
+ sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask);
+
+ pSorter = (VdbeSorter*)sqlite3DbMallocZero(db, sz + szKeyInfo);
+ pCsr->pSorter = pSorter;
if( pSorter==0 ){
- return SQLITE_NOMEM;
- }
-
- pSorter->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pCsr->pKeyInfo, 0, 0, &d);
- if( pSorter->pUnpacked==0 ) return SQLITE_NOMEM;
- assert( pSorter->pUnpacked==(UnpackedRecord *)d );
+ rc = SQLITE_NOMEM;
+ }else{
+ pSorter->pKeyInfo = pKeyInfo = (KeyInfo*)((u8*)pSorter + sz);
+ memcpy(pKeyInfo, pCsr->pKeyInfo, szKeyInfo);
+ pKeyInfo->db = 0;
+ if( nField && nWorker==0 ){
+ pKeyInfo->nXField += (pKeyInfo->nField - nField);
+ pKeyInfo->nField = nField;
+ }
+ pSorter->pgsz = pgsz = sqlite3BtreeGetPageSize(db->aDb[0].pBt);
+ pSorter->nTask = nWorker + 1;
+ pSorter->iPrev = nWorker-1;
+ pSorter->bUseThreads = (pSorter->nTask>1);
+ pSorter->db = db;
+ for(i=0; i<pSorter->nTask; i++){
+ SortSubtask *pTask = &pSorter->aTask[i];
+ pTask->pSorter = pSorter;
+ }
+
+ if( !sqlite3TempInMemory(db) ){
+ u32 szPma = sqlite3GlobalConfig.szPma;
+ pSorter->mnPmaSize = szPma * pgsz;
+ mxCache = db->aDb[0].pSchema->cache_size;
+ if( mxCache<(int)szPma ) mxCache = (int)szPma;
+ pSorter->mxPmaSize = MIN((i64)mxCache*pgsz, SQLITE_MAX_PMASZ);
+
+ /* EVIDENCE-OF: R-26747-61719 When the application provides any amount of
+ ** scratch memory using SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary
+ ** large heap allocations.
+ */
+ if( sqlite3GlobalConfig.pScratch==0 ){
+ assert( pSorter->iMemory==0 );
+ pSorter->nMemory = pgsz;
+ pSorter->list.aMemory = (u8*)sqlite3Malloc(pgsz);
+ if( !pSorter->list.aMemory ) rc = SQLITE_NOMEM;
+ }
+ }
- if( !sqlite3TempInMemory(db) ){
- pgsz = sqlite3BtreeGetPageSize(db->aDb[0].pBt);
- pSorter->mnPmaSize = SORTER_MIN_WORKING * pgsz;
- mxCache = db->aDb[0].pSchema->cache_size;
- if( mxCache<SORTER_MIN_WORKING ) mxCache = SORTER_MIN_WORKING;
- pSorter->mxPmaSize = mxCache * pgsz;
+ if( (pKeyInfo->nField+pKeyInfo->nXField)<13
+ && (pKeyInfo->aColl[0]==0 || pKeyInfo->aColl[0]==db->pDfltColl)
+ ){
+ pSorter->typeMask = SORTER_TYPE_INTEGER | SORTER_TYPE_TEXT;
+ }
}
- return SQLITE_OK;
+ return rc;
}
+#undef nWorker /* Defined at the top of this function */
/*
** Free the list of sorted records starting at pRecord.
@@ -75496,37 +78921,227 @@ static void vdbeSorterRecordFree(sqlite3 *db, SorterRecord *pRecord){
SorterRecord *p;
SorterRecord *pNext;
for(p=pRecord; p; p=pNext){
- pNext = p->pNext;
+ pNext = p->u.pNext;
sqlite3DbFree(db, p);
}
}
/*
-** Reset a sorting cursor back to its original empty state.
+** Free all resources owned by the object indicated by argument pTask. All
+** fields of *pTask are zeroed before returning.
*/
-SQLITE_PRIVATE void sqlite3VdbeSorterReset(sqlite3 *db, VdbeSorter *pSorter){
- if( pSorter->aIter ){
- int i;
- for(i=0; i<pSorter->nTree; i++){
- vdbeSorterIterZero(db, &pSorter->aIter[i]);
+static void vdbeSortSubtaskCleanup(sqlite3 *db, SortSubtask *pTask){
+ sqlite3DbFree(db, pTask->pUnpacked);
+#if SQLITE_MAX_WORKER_THREADS>0
+ /* pTask->list.aMemory can only be non-zero if it was handed memory
+ ** from the main thread. That only occurs SQLITE_MAX_WORKER_THREADS>0 */
+ if( pTask->list.aMemory ){
+ sqlite3_free(pTask->list.aMemory);
+ }else
+#endif
+ {
+ assert( pTask->list.aMemory==0 );
+ vdbeSorterRecordFree(0, pTask->list.pList);
+ }
+ if( pTask->file.pFd ){
+ sqlite3OsCloseFree(pTask->file.pFd);
+ }
+ if( pTask->file2.pFd ){
+ sqlite3OsCloseFree(pTask->file2.pFd);
+ }
+ memset(pTask, 0, sizeof(SortSubtask));
+}
+
+#ifdef SQLITE_DEBUG_SORTER_THREADS
+static void vdbeSorterWorkDebug(SortSubtask *pTask, const char *zEvent){
+ i64 t;
+ int iTask = (pTask - pTask->pSorter->aTask);
+ sqlite3OsCurrentTimeInt64(pTask->pSorter->db->pVfs, &t);
+ fprintf(stderr, "%lld:%d %s\n", t, iTask, zEvent);
+}
+static void vdbeSorterRewindDebug(const char *zEvent){
+ i64 t;
+ sqlite3OsCurrentTimeInt64(sqlite3_vfs_find(0), &t);
+ fprintf(stderr, "%lld:X %s\n", t, zEvent);
+}
+static void vdbeSorterPopulateDebug(
+ SortSubtask *pTask,
+ const char *zEvent
+){
+ i64 t;
+ int iTask = (pTask - pTask->pSorter->aTask);
+ sqlite3OsCurrentTimeInt64(pTask->pSorter->db->pVfs, &t);
+ fprintf(stderr, "%lld:bg%d %s\n", t, iTask, zEvent);
+}
+static void vdbeSorterBlockDebug(
+ SortSubtask *pTask,
+ int bBlocked,
+ const char *zEvent
+){
+ if( bBlocked ){
+ i64 t;
+ sqlite3OsCurrentTimeInt64(pTask->pSorter->db->pVfs, &t);
+ fprintf(stderr, "%lld:main %s\n", t, zEvent);
+ }
+}
+#else
+# define vdbeSorterWorkDebug(x,y)
+# define vdbeSorterRewindDebug(y)
+# define vdbeSorterPopulateDebug(x,y)
+# define vdbeSorterBlockDebug(x,y,z)
+#endif
+
+#if SQLITE_MAX_WORKER_THREADS>0
+/*
+** Join thread pTask->thread.
+*/
+static int vdbeSorterJoinThread(SortSubtask *pTask){
+ int rc = SQLITE_OK;
+ if( pTask->pThread ){
+#ifdef SQLITE_DEBUG_SORTER_THREADS
+ int bDone = pTask->bDone;
+#endif
+ void *pRet = SQLITE_INT_TO_PTR(SQLITE_ERROR);
+ vdbeSorterBlockDebug(pTask, !bDone, "enter");
+ (void)sqlite3ThreadJoin(pTask->pThread, &pRet);
+ vdbeSorterBlockDebug(pTask, !bDone, "exit");
+ rc = SQLITE_PTR_TO_INT(pRet);
+ assert( pTask->bDone==1 );
+ pTask->bDone = 0;
+ pTask->pThread = 0;
+ }
+ return rc;
+}
+
+/*
+** Launch a background thread to run xTask(pIn).
+*/
+static int vdbeSorterCreateThread(
+ SortSubtask *pTask, /* Thread will use this task object */
+ void *(*xTask)(void*), /* Routine to run in a separate thread */
+ void *pIn /* Argument passed into xTask() */
+){
+ assert( pTask->pThread==0 && pTask->bDone==0 );
+ return sqlite3ThreadCreate(&pTask->pThread, xTask, pIn);
+}
+
+/*
+** Join all outstanding threads launched by SorterWrite() to create
+** level-0 PMAs.
+*/
+static int vdbeSorterJoinAll(VdbeSorter *pSorter, int rcin){
+ int rc = rcin;
+ int i;
+
+ /* This function is always called by the main user thread.
+ **
+ ** If this function is being called after SorterRewind() has been called,
+ ** it is possible that thread pSorter->aTask[pSorter->nTask-1].pThread
+ ** is currently attempt to join one of the other threads. To avoid a race
+ ** condition where this thread also attempts to join the same object, join
+ ** thread pSorter->aTask[pSorter->nTask-1].pThread first. */
+ for(i=pSorter->nTask-1; i>=0; i--){
+ SortSubtask *pTask = &pSorter->aTask[i];
+ int rc2 = vdbeSorterJoinThread(pTask);
+ if( rc==SQLITE_OK ) rc = rc2;
+ }
+ return rc;
+}
+#else
+# define vdbeSorterJoinAll(x,rcin) (rcin)
+# define vdbeSorterJoinThread(pTask) SQLITE_OK
+#endif
+
+/*
+** Allocate a new MergeEngine object capable of handling up to
+** nReader PmaReader inputs.
+**
+** nReader is automatically rounded up to the next power of two.
+** nReader may not exceed SORTER_MAX_MERGE_COUNT even after rounding up.
+*/
+static MergeEngine *vdbeMergeEngineNew(int nReader){
+ int N = 2; /* Smallest power of two >= nReader */
+ int nByte; /* Total bytes of space to allocate */
+ MergeEngine *pNew; /* Pointer to allocated object to return */
+
+ assert( nReader<=SORTER_MAX_MERGE_COUNT );
+
+ while( N<nReader ) N += N;
+ nByte = sizeof(MergeEngine) + N * (sizeof(int) + sizeof(PmaReader));
+
+ pNew = sqlite3FaultSim(100) ? 0 : (MergeEngine*)sqlite3MallocZero(nByte);
+ if( pNew ){
+ pNew->nTree = N;
+ pNew->pTask = 0;
+ pNew->aReadr = (PmaReader*)&pNew[1];
+ pNew->aTree = (int*)&pNew->aReadr[N];
+ }
+ return pNew;
+}
+
+/*
+** Free the MergeEngine object passed as the only argument.
+*/
+static void vdbeMergeEngineFree(MergeEngine *pMerger){
+ int i;
+ if( pMerger ){
+ for(i=0; i<pMerger->nTree; i++){
+ vdbePmaReaderClear(&pMerger->aReadr[i]);
}
- sqlite3DbFree(db, pSorter->aIter);
- pSorter->aIter = 0;
}
- if( pSorter->pTemp1 ){
- sqlite3OsCloseFree(pSorter->pTemp1);
- pSorter->pTemp1 = 0;
+ sqlite3_free(pMerger);
+}
+
+/*
+** Free all resources associated with the IncrMerger object indicated by
+** the first argument.
+*/
+static void vdbeIncrFree(IncrMerger *pIncr){
+ if( pIncr ){
+#if SQLITE_MAX_WORKER_THREADS>0
+ if( pIncr->bUseThread ){
+ vdbeSorterJoinThread(pIncr->pTask);
+ if( pIncr->aFile[0].pFd ) sqlite3OsCloseFree(pIncr->aFile[0].pFd);
+ if( pIncr->aFile[1].pFd ) sqlite3OsCloseFree(pIncr->aFile[1].pFd);
+ }
+#endif
+ vdbeMergeEngineFree(pIncr->pMerger);
+ sqlite3_free(pIncr);
}
- vdbeSorterRecordFree(db, pSorter->pRecord);
- pSorter->pRecord = 0;
- pSorter->iWriteOff = 0;
- pSorter->iReadOff = 0;
- pSorter->nInMemory = 0;
- pSorter->nTree = 0;
- pSorter->nPMA = 0;
- pSorter->aTree = 0;
}
+/*
+** Reset a sorting cursor back to its original empty state.
+*/
+SQLITE_PRIVATE void sqlite3VdbeSorterReset(sqlite3 *db, VdbeSorter *pSorter){
+ int i;
+ (void)vdbeSorterJoinAll(pSorter, SQLITE_OK);
+ assert( pSorter->bUseThreads || pSorter->pReader==0 );
+#if SQLITE_MAX_WORKER_THREADS>0
+ if( pSorter->pReader ){
+ vdbePmaReaderClear(pSorter->pReader);
+ sqlite3DbFree(db, pSorter->pReader);
+ pSorter->pReader = 0;
+ }
+#endif
+ vdbeMergeEngineFree(pSorter->pMerger);
+ pSorter->pMerger = 0;
+ for(i=0; i<pSorter->nTask; i++){
+ SortSubtask *pTask = &pSorter->aTask[i];
+ vdbeSortSubtaskCleanup(db, pTask);
+ pTask->pSorter = pSorter;
+ }
+ if( pSorter->list.aMemory==0 ){
+ vdbeSorterRecordFree(0, pSorter->list.pList);
+ }
+ pSorter->list.pList = 0;
+ pSorter->list.szPMA = 0;
+ pSorter->bUsePMA = 0;
+ pSorter->iMemory = 0;
+ pSorter->mxKeysize = 0;
+ sqlite3DbFree(db, pSorter->pUnpacked);
+ pSorter->pUnpacked = 0;
+}
/*
** Free any cursor components allocated by sqlite3VdbeSorterXXX routines.
@@ -75535,54 +79150,112 @@ SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){
VdbeSorter *pSorter = pCsr->pSorter;
if( pSorter ){
sqlite3VdbeSorterReset(db, pSorter);
- sqlite3DbFree(db, pSorter->pUnpacked);
+ sqlite3_free(pSorter->list.aMemory);
sqlite3DbFree(db, pSorter);
pCsr->pSorter = 0;
}
}
+#if SQLITE_MAX_MMAP_SIZE>0
+/*
+** The first argument is a file-handle open on a temporary file. The file
+** is guaranteed to be nByte bytes or smaller in size. This function
+** attempts to extend the file to nByte bytes in size and to ensure that
+** the VFS has memory mapped it.
+**
+** Whether or not the file does end up memory mapped of course depends on
+** the specific VFS implementation.
+*/
+static void vdbeSorterExtendFile(sqlite3 *db, sqlite3_file *pFd, i64 nByte){
+ if( nByte<=(i64)(db->nMaxSorterMmap) && pFd->pMethods->iVersion>=3 ){
+ void *p = 0;
+ int chunksize = 4*1024;
+ sqlite3OsFileControlHint(pFd, SQLITE_FCNTL_CHUNK_SIZE, &chunksize);
+ sqlite3OsFileControlHint(pFd, SQLITE_FCNTL_SIZE_HINT, &nByte);
+ sqlite3OsFetch(pFd, 0, (int)nByte, &p);
+ sqlite3OsUnfetch(pFd, 0, p);
+ }
+}
+#else
+# define vdbeSorterExtendFile(x,y,z)
+#endif
+
/*
** Allocate space for a file-handle and open a temporary file. If successful,
-** set *ppFile to point to the malloc'd file-handle and return SQLITE_OK.
-** Otherwise, set *ppFile to 0 and return an SQLite error code.
+** set *ppFd to point to the malloc'd file-handle and return SQLITE_OK.
+** Otherwise, set *ppFd to 0 and return an SQLite error code.
*/
-static int vdbeSorterOpenTempFile(sqlite3 *db, sqlite3_file **ppFile){
- int dummy;
- return sqlite3OsOpenMalloc(db->pVfs, 0, ppFile,
+static int vdbeSorterOpenTempFile(
+ sqlite3 *db, /* Database handle doing sort */
+ i64 nExtend, /* Attempt to extend file to this size */
+ sqlite3_file **ppFd
+){
+ int rc;
+ if( sqlite3FaultSim(202) ) return SQLITE_IOERR_ACCESS;
+ rc = sqlite3OsOpenMalloc(db->pVfs, 0, ppFd,
SQLITE_OPEN_TEMP_JOURNAL |
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
- SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE, &dummy
+ SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE, &rc
);
+ if( rc==SQLITE_OK ){
+ i64 max = SQLITE_MAX_MMAP_SIZE;
+ sqlite3OsFileControlHint(*ppFd, SQLITE_FCNTL_MMAP_SIZE, (void*)&max);
+ if( nExtend>0 ){
+ vdbeSorterExtendFile(db, *ppFd, nExtend);
+ }
+ }
+ return rc;
}
/*
+** If it has not already been allocated, allocate the UnpackedRecord
+** structure at pTask->pUnpacked. Return SQLITE_OK if successful (or
+** if no allocation was required), or SQLITE_NOMEM otherwise.
+*/
+static int vdbeSortAllocUnpacked(SortSubtask *pTask){
+ if( pTask->pUnpacked==0 ){
+ char *pFree;
+ pTask->pUnpacked = sqlite3VdbeAllocUnpackedRecord(
+ pTask->pSorter->pKeyInfo, 0, 0, &pFree
+ );
+ assert( pTask->pUnpacked==(UnpackedRecord*)pFree );
+ if( pFree==0 ) return SQLITE_NOMEM;
+ pTask->pUnpacked->nField = pTask->pSorter->pKeyInfo->nField;
+ pTask->pUnpacked->errCode = 0;
+ }
+ return SQLITE_OK;
+}
+
+
+/*
** Merge the two sorted lists p1 and p2 into a single list.
** Set *ppOut to the head of the new list.
*/
static void vdbeSorterMerge(
- const VdbeCursor *pCsr, /* For pKeyInfo */
+ SortSubtask *pTask, /* Calling thread context */
SorterRecord *p1, /* First list to merge */
SorterRecord *p2, /* Second list to merge */
SorterRecord **ppOut /* OUT: Head of merged list */
){
SorterRecord *pFinal = 0;
SorterRecord **pp = &pFinal;
- void *pVal2 = p2 ? p2->pVal : 0;
+ int bCached = 0;
while( p1 && p2 ){
int res;
- vdbeSorterCompare(pCsr, 0, p1->pVal, p1->nVal, pVal2, p2->nVal, &res);
+ res = pTask->xCompare(
+ pTask, &bCached, SRVAL(p1), p1->nVal, SRVAL(p2), p2->nVal
+ );
+
if( res<=0 ){
*pp = p1;
- pp = &p1->pNext;
- p1 = p1->pNext;
- pVal2 = 0;
+ pp = &p1->u.pNext;
+ p1 = p1->u.pNext;
}else{
*pp = p2;
- pp = &p2->pNext;
- p2 = p2->pNext;
- if( p2==0 ) break;
- pVal2 = p2->pVal;
+ pp = &p2->u.pNext;
+ p2 = p2->u.pNext;
+ bCached = 0;
}
}
*pp = p1 ? p1 : p2;
@@ -75590,27 +79263,56 @@ static void vdbeSorterMerge(
}
/*
-** Sort the linked list of records headed at pCsr->pRecord. Return SQLITE_OK
-** if successful, or an SQLite error code (i.e. SQLITE_NOMEM) if an error
-** occurs.
+** Return the SorterCompare function to compare values collected by the
+** sorter object passed as the only argument.
+*/
+static SorterCompare vdbeSorterGetCompare(VdbeSorter *p){
+ if( p->typeMask==SORTER_TYPE_INTEGER ){
+ return vdbeSorterCompareInt;
+ }else if( p->typeMask==SORTER_TYPE_TEXT ){
+ return vdbeSorterCompareText;
+ }
+ return vdbeSorterCompare;
+}
+
+/*
+** Sort the linked list of records headed at pTask->pList. Return
+** SQLITE_OK if successful, or an SQLite error code (i.e. SQLITE_NOMEM) if
+** an error occurs.
*/
-static int vdbeSorterSort(const VdbeCursor *pCsr){
+static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){
int i;
SorterRecord **aSlot;
SorterRecord *p;
- VdbeSorter *pSorter = pCsr->pSorter;
+ int rc;
+
+ rc = vdbeSortAllocUnpacked(pTask);
+ if( rc!=SQLITE_OK ) return rc;
+
+ p = pList->pList;
+ pTask->xCompare = vdbeSorterGetCompare(pTask->pSorter);
aSlot = (SorterRecord **)sqlite3MallocZero(64 * sizeof(SorterRecord *));
if( !aSlot ){
return SQLITE_NOMEM;
}
- p = pSorter->pRecord;
while( p ){
- SorterRecord *pNext = p->pNext;
- p->pNext = 0;
+ SorterRecord *pNext;
+ if( pList->aMemory ){
+ if( (u8*)p==pList->aMemory ){
+ pNext = 0;
+ }else{
+ assert( p->u.iNext<sqlite3MallocSize(pList->aMemory) );
+ pNext = (SorterRecord*)&pList->aMemory[p->u.iNext];
+ }
+ }else{
+ pNext = p->u.pNext;
+ }
+
+ p->u.pNext = 0;
for(i=0; aSlot[i]; i++){
- vdbeSorterMerge(pCsr, p, aSlot[i], &p);
+ vdbeSorterMerge(pTask, p, aSlot[i], &p);
aSlot[i] = 0;
}
aSlot[i] = p;
@@ -75619,42 +79321,43 @@ static int vdbeSorterSort(const VdbeCursor *pCsr){
p = 0;
for(i=0; i<64; i++){
- vdbeSorterMerge(pCsr, p, aSlot[i], &p);
+ vdbeSorterMerge(pTask, p, aSlot[i], &p);
}
- pSorter->pRecord = p;
+ pList->pList = p;
sqlite3_free(aSlot);
- return SQLITE_OK;
+ assert( pTask->pUnpacked->errCode==SQLITE_OK
+ || pTask->pUnpacked->errCode==SQLITE_NOMEM
+ );
+ return pTask->pUnpacked->errCode;
}
/*
-** Initialize a file-writer object.
+** Initialize a PMA-writer object.
*/
-static void fileWriterInit(
- sqlite3 *db, /* Database (for malloc) */
- sqlite3_file *pFile, /* File to write to */
- FileWriter *p, /* Object to populate */
- i64 iStart /* Offset of pFile to begin writing at */
+static void vdbePmaWriterInit(
+ sqlite3_file *pFd, /* File handle to write to */
+ PmaWriter *p, /* Object to populate */
+ int nBuf, /* Buffer size */
+ i64 iStart /* Offset of pFd to begin writing at */
){
- int nBuf = sqlite3BtreeGetPageSize(db->aDb[0].pBt);
-
- memset(p, 0, sizeof(FileWriter));
- p->aBuffer = (u8 *)sqlite3DbMallocRaw(db, nBuf);
+ memset(p, 0, sizeof(PmaWriter));
+ p->aBuffer = (u8*)sqlite3Malloc(nBuf);
if( !p->aBuffer ){
p->eFWErr = SQLITE_NOMEM;
}else{
p->iBufEnd = p->iBufStart = (iStart % nBuf);
p->iWriteOff = iStart - p->iBufStart;
p->nBuffer = nBuf;
- p->pFile = pFile;
+ p->pFd = pFd;
}
}
/*
-** Write nData bytes of data to the file-write object. Return SQLITE_OK
+** Write nData bytes of data to the PMA. Return SQLITE_OK
** if successful, or an SQLite error code if an error occurs.
*/
-static void fileWriterWrite(FileWriter *p, u8 *pData, int nData){
+static void vdbePmaWriteBlob(PmaWriter *p, u8 *pData, int nData){
int nRem = nData;
while( nRem>0 && p->eFWErr==0 ){
int nCopy = nRem;
@@ -75665,7 +79368,7 @@ static void fileWriterWrite(FileWriter *p, u8 *pData, int nData){
memcpy(&p->aBuffer[p->iBufEnd], &pData[nData-nRem], nCopy);
p->iBufEnd += nCopy;
if( p->iBufEnd==p->nBuffer ){
- p->eFWErr = sqlite3OsWrite(p->pFile,
+ p->eFWErr = sqlite3OsWrite(p->pFd,
&p->aBuffer[p->iBufStart], p->iBufEnd - p->iBufStart,
p->iWriteOff + p->iBufStart
);
@@ -75679,43 +79382,44 @@ static void fileWriterWrite(FileWriter *p, u8 *pData, int nData){
}
/*
-** Flush any buffered data to disk and clean up the file-writer object.
-** The results of using the file-writer after this call are undefined.
+** Flush any buffered data to disk and clean up the PMA-writer object.
+** The results of using the PMA-writer after this call are undefined.
** Return SQLITE_OK if flushing the buffered data succeeds or is not
** required. Otherwise, return an SQLite error code.
**
** Before returning, set *piEof to the offset immediately following the
** last byte written to the file.
*/
-static int fileWriterFinish(sqlite3 *db, FileWriter *p, i64 *piEof){
+static int vdbePmaWriterFinish(PmaWriter *p, i64 *piEof){
int rc;
if( p->eFWErr==0 && ALWAYS(p->aBuffer) && p->iBufEnd>p->iBufStart ){
- p->eFWErr = sqlite3OsWrite(p->pFile,
+ p->eFWErr = sqlite3OsWrite(p->pFd,
&p->aBuffer[p->iBufStart], p->iBufEnd - p->iBufStart,
p->iWriteOff + p->iBufStart
);
}
*piEof = (p->iWriteOff + p->iBufEnd);
- sqlite3DbFree(db, p->aBuffer);
+ sqlite3_free(p->aBuffer);
rc = p->eFWErr;
- memset(p, 0, sizeof(FileWriter));
+ memset(p, 0, sizeof(PmaWriter));
return rc;
}
/*
-** Write value iVal encoded as a varint to the file-write object. Return
+** Write value iVal encoded as a varint to the PMA. Return
** SQLITE_OK if successful, or an SQLite error code if an error occurs.
*/
-static void fileWriterWriteVarint(FileWriter *p, u64 iVal){
+static void vdbePmaWriteVarint(PmaWriter *p, u64 iVal){
int nByte;
u8 aByte[10];
nByte = sqlite3PutVarint(aByte, iVal);
- fileWriterWrite(p, aByte, nByte);
+ vdbePmaWriteBlob(p, aByte, nByte);
}
/*
-** Write the current contents of the in-memory linked-list to a PMA. Return
-** SQLITE_OK if successful, or an SQLite error code otherwise.
+** Write the current contents of in-memory linked-list pList to a level-0
+** PMA in the temp file belonging to sub-task pTask. Return SQLITE_OK if
+** successful, or an SQLite error code otherwise.
**
** The format of a PMA is:
**
@@ -75726,76 +79430,255 @@ static void fileWriterWriteVarint(FileWriter *p, u64 iVal){
** Each record consists of a varint followed by a blob of data (the
** key). The varint is the number of bytes in the blob of data.
*/
-static int vdbeSorterListToPMA(sqlite3 *db, const VdbeCursor *pCsr){
+static int vdbeSorterListToPMA(SortSubtask *pTask, SorterList *pList){
+ sqlite3 *db = pTask->pSorter->db;
int rc = SQLITE_OK; /* Return code */
- VdbeSorter *pSorter = pCsr->pSorter;
- FileWriter writer;
+ PmaWriter writer; /* Object used to write to the file */
- memset(&writer, 0, sizeof(FileWriter));
+#ifdef SQLITE_DEBUG
+ /* Set iSz to the expected size of file pTask->file after writing the PMA.
+ ** This is used by an assert() statement at the end of this function. */
+ i64 iSz = pList->szPMA + sqlite3VarintLen(pList->szPMA) + pTask->file.iEof;
+#endif
- if( pSorter->nInMemory==0 ){
- assert( pSorter->pRecord==0 );
- return rc;
+ vdbeSorterWorkDebug(pTask, "enter");
+ memset(&writer, 0, sizeof(PmaWriter));
+ assert( pList->szPMA>0 );
+
+ /* If the first temporary PMA file has not been opened, open it now. */
+ if( pTask->file.pFd==0 ){
+ rc = vdbeSorterOpenTempFile(db, 0, &pTask->file.pFd);
+ assert( rc!=SQLITE_OK || pTask->file.pFd );
+ assert( pTask->file.iEof==0 );
+ assert( pTask->nPMA==0 );
}
- rc = vdbeSorterSort(pCsr);
+ /* Try to get the file to memory map */
+ if( rc==SQLITE_OK ){
+ vdbeSorterExtendFile(db, pTask->file.pFd, pTask->file.iEof+pList->szPMA+9);
+ }
- /* If the first temporary PMA file has not been opened, open it now. */
- if( rc==SQLITE_OK && pSorter->pTemp1==0 ){
- rc = vdbeSorterOpenTempFile(db, &pSorter->pTemp1);
- assert( rc!=SQLITE_OK || pSorter->pTemp1 );
- assert( pSorter->iWriteOff==0 );
- assert( pSorter->nPMA==0 );
+ /* Sort the list */
+ if( rc==SQLITE_OK ){
+ rc = vdbeSorterSort(pTask, pList);
}
if( rc==SQLITE_OK ){
SorterRecord *p;
SorterRecord *pNext = 0;
- fileWriterInit(db, pSorter->pTemp1, &writer, pSorter->iWriteOff);
- pSorter->nPMA++;
- fileWriterWriteVarint(&writer, pSorter->nInMemory);
- for(p=pSorter->pRecord; p; p=pNext){
- pNext = p->pNext;
- fileWriterWriteVarint(&writer, p->nVal);
- fileWriterWrite(&writer, p->pVal, p->nVal);
- sqlite3DbFree(db, p);
+ vdbePmaWriterInit(pTask->file.pFd, &writer, pTask->pSorter->pgsz,
+ pTask->file.iEof);
+ pTask->nPMA++;
+ vdbePmaWriteVarint(&writer, pList->szPMA);
+ for(p=pList->pList; p; p=pNext){
+ pNext = p->u.pNext;
+ vdbePmaWriteVarint(&writer, p->nVal);
+ vdbePmaWriteBlob(&writer, SRVAL(p), p->nVal);
+ if( pList->aMemory==0 ) sqlite3_free(p);
}
- pSorter->pRecord = p;
- rc = fileWriterFinish(db, &writer, &pSorter->iWriteOff);
+ pList->pList = p;
+ rc = vdbePmaWriterFinish(&writer, &pTask->file.iEof);
}
+ vdbeSorterWorkDebug(pTask, "exit");
+ assert( rc!=SQLITE_OK || pList->pList==0 );
+ assert( rc!=SQLITE_OK || pTask->file.iEof==iSz );
return rc;
}
/*
+** Advance the MergeEngine to its next entry.
+** Set *pbEof to true there is no next entry because
+** the MergeEngine has reached the end of all its inputs.
+**
+** Return SQLITE_OK if successful or an error code if an error occurs.
+*/
+static int vdbeMergeEngineStep(
+ MergeEngine *pMerger, /* The merge engine to advance to the next row */
+ int *pbEof /* Set TRUE at EOF. Set false for more content */
+){
+ int rc;
+ int iPrev = pMerger->aTree[1];/* Index of PmaReader to advance */
+ SortSubtask *pTask = pMerger->pTask;
+
+ /* Advance the current PmaReader */
+ rc = vdbePmaReaderNext(&pMerger->aReadr[iPrev]);
+
+ /* Update contents of aTree[] */
+ if( rc==SQLITE_OK ){
+ int i; /* Index of aTree[] to recalculate */
+ PmaReader *pReadr1; /* First PmaReader to compare */
+ PmaReader *pReadr2; /* Second PmaReader to compare */
+ int bCached = 0;
+
+ /* Find the first two PmaReaders to compare. The one that was just
+ ** advanced (iPrev) and the one next to it in the array. */
+ pReadr1 = &pMerger->aReadr[(iPrev & 0xFFFE)];
+ pReadr2 = &pMerger->aReadr[(iPrev | 0x0001)];
+
+ for(i=(pMerger->nTree+iPrev)/2; i>0; i=i/2){
+ /* Compare pReadr1 and pReadr2. Store the result in variable iRes. */
+ int iRes;
+ if( pReadr1->pFd==0 ){
+ iRes = +1;
+ }else if( pReadr2->pFd==0 ){
+ iRes = -1;
+ }else{
+ iRes = pTask->xCompare(pTask, &bCached,
+ pReadr1->aKey, pReadr1->nKey, pReadr2->aKey, pReadr2->nKey
+ );
+ }
+
+ /* If pReadr1 contained the smaller value, set aTree[i] to its index.
+ ** Then set pReadr2 to the next PmaReader to compare to pReadr1. In this
+ ** case there is no cache of pReadr2 in pTask->pUnpacked, so set
+ ** pKey2 to point to the record belonging to pReadr2.
+ **
+ ** Alternatively, if pReadr2 contains the smaller of the two values,
+ ** set aTree[i] to its index and update pReadr1. If vdbeSorterCompare()
+ ** was actually called above, then pTask->pUnpacked now contains
+ ** a value equivalent to pReadr2. So set pKey2 to NULL to prevent
+ ** vdbeSorterCompare() from decoding pReadr2 again.
+ **
+ ** If the two values were equal, then the value from the oldest
+ ** PMA should be considered smaller. The VdbeSorter.aReadr[] array
+ ** is sorted from oldest to newest, so pReadr1 contains older values
+ ** than pReadr2 iff (pReadr1<pReadr2). */
+ if( iRes<0 || (iRes==0 && pReadr1<pReadr2) ){
+ pMerger->aTree[i] = (int)(pReadr1 - pMerger->aReadr);
+ pReadr2 = &pMerger->aReadr[ pMerger->aTree[i ^ 0x0001] ];
+ bCached = 0;
+ }else{
+ if( pReadr1->pFd ) bCached = 0;
+ pMerger->aTree[i] = (int)(pReadr2 - pMerger->aReadr);
+ pReadr1 = &pMerger->aReadr[ pMerger->aTree[i ^ 0x0001] ];
+ }
+ }
+ *pbEof = (pMerger->aReadr[pMerger->aTree[1]].pFd==0);
+ }
+
+ return (rc==SQLITE_OK ? pTask->pUnpacked->errCode : rc);
+}
+
+#if SQLITE_MAX_WORKER_THREADS>0
+/*
+** The main routine for background threads that write level-0 PMAs.
+*/
+static void *vdbeSorterFlushThread(void *pCtx){
+ SortSubtask *pTask = (SortSubtask*)pCtx;
+ int rc; /* Return code */
+ assert( pTask->bDone==0 );
+ rc = vdbeSorterListToPMA(pTask, &pTask->list);
+ pTask->bDone = 1;
+ return SQLITE_INT_TO_PTR(rc);
+}
+#endif /* SQLITE_MAX_WORKER_THREADS>0 */
+
+/*
+** Flush the current contents of VdbeSorter.list to a new PMA, possibly
+** using a background thread.
+*/
+static int vdbeSorterFlushPMA(VdbeSorter *pSorter){
+#if SQLITE_MAX_WORKER_THREADS==0
+ pSorter->bUsePMA = 1;
+ return vdbeSorterListToPMA(&pSorter->aTask[0], &pSorter->list);
+#else
+ int rc = SQLITE_OK;
+ int i;
+ SortSubtask *pTask = 0; /* Thread context used to create new PMA */
+ int nWorker = (pSorter->nTask-1);
+
+ /* Set the flag to indicate that at least one PMA has been written.
+ ** Or will be, anyhow. */
+ pSorter->bUsePMA = 1;
+
+ /* Select a sub-task to sort and flush the current list of in-memory
+ ** records to disk. If the sorter is running in multi-threaded mode,
+ ** round-robin between the first (pSorter->nTask-1) tasks. Except, if
+ ** the background thread from a sub-tasks previous turn is still running,
+ ** skip it. If the first (pSorter->nTask-1) sub-tasks are all still busy,
+ ** fall back to using the final sub-task. The first (pSorter->nTask-1)
+ ** sub-tasks are prefered as they use background threads - the final
+ ** sub-task uses the main thread. */
+ for(i=0; i<nWorker; i++){
+ int iTest = (pSorter->iPrev + i + 1) % nWorker;
+ pTask = &pSorter->aTask[iTest];
+ if( pTask->bDone ){
+ rc = vdbeSorterJoinThread(pTask);
+ }
+ if( rc!=SQLITE_OK || pTask->pThread==0 ) break;
+ }
+
+ if( rc==SQLITE_OK ){
+ if( i==nWorker ){
+ /* Use the foreground thread for this operation */
+ rc = vdbeSorterListToPMA(&pSorter->aTask[nWorker], &pSorter->list);
+ }else{
+ /* Launch a background thread for this operation */
+ u8 *aMem = pTask->list.aMemory;
+ void *pCtx = (void*)pTask;
+
+ assert( pTask->pThread==0 && pTask->bDone==0 );
+ assert( pTask->list.pList==0 );
+ assert( pTask->list.aMemory==0 || pSorter->list.aMemory!=0 );
+
+ pSorter->iPrev = (u8)(pTask - pSorter->aTask);
+ pTask->list = pSorter->list;
+ pSorter->list.pList = 0;
+ pSorter->list.szPMA = 0;
+ if( aMem ){
+ pSorter->list.aMemory = aMem;
+ pSorter->nMemory = sqlite3MallocSize(aMem);
+ }else if( pSorter->list.aMemory ){
+ pSorter->list.aMemory = sqlite3Malloc(pSorter->nMemory);
+ if( !pSorter->list.aMemory ) return SQLITE_NOMEM;
+ }
+
+ rc = vdbeSorterCreateThread(pTask, vdbeSorterFlushThread, pCtx);
+ }
+ }
+
+ return rc;
+#endif /* SQLITE_MAX_WORKER_THREADS!=0 */
+}
+
+/*
** Add a record to the sorter.
*/
SQLITE_PRIVATE int sqlite3VdbeSorterWrite(
- sqlite3 *db, /* Database handle */
- const VdbeCursor *pCsr, /* Sorter cursor */
+ const VdbeCursor *pCsr, /* Sorter cursor */
Mem *pVal /* Memory cell containing record */
){
VdbeSorter *pSorter = pCsr->pSorter;
int rc = SQLITE_OK; /* Return Code */
SorterRecord *pNew; /* New list element */
- assert( pSorter );
- pSorter->nInMemory += sqlite3VarintLen(pVal->n) + pVal->n;
+ int bFlush; /* True to flush contents of memory to PMA */
+ int nReq; /* Bytes of memory required */
+ int nPMA; /* Bytes of PMA space required */
+ int t; /* serial type of first record field */
- pNew = (SorterRecord *)sqlite3DbMallocRaw(db, pVal->n + sizeof(SorterRecord));
- if( pNew==0 ){
- rc = SQLITE_NOMEM;
+ getVarint32((const u8*)&pVal->z[1], t);
+ if( t>0 && t<10 && t!=7 ){
+ pSorter->typeMask &= SORTER_TYPE_INTEGER;
+ }else if( t>10 && (t & 0x01) ){
+ pSorter->typeMask &= SORTER_TYPE_TEXT;
}else{
- pNew->pVal = (void *)&pNew[1];
- memcpy(pNew->pVal, pVal->z, pVal->n);
- pNew->nVal = pVal->n;
- pNew->pNext = pSorter->pRecord;
- pSorter->pRecord = pNew;
+ pSorter->typeMask = 0;
}
- /* See if the contents of the sorter should now be written out. They
- ** are written out when either of the following are true:
+ assert( pSorter );
+
+ /* Figure out whether or not the current contents of memory should be
+ ** flushed to a PMA before continuing. If so, do so.
+ **
+ ** If using the single large allocation mode (pSorter->aMemory!=0), then
+ ** flush the contents of memory to a new PMA if (a) at least one value is
+ ** already in memory and (b) the new value will not fit in memory.
+ **
+ ** Or, if using separate allocations for each record, flush the contents
+ ** of memory to a PMA if either of the following are true:
**
** * The total memory allocated for the in-memory list is greater
** than (page-size * cache-size), or
@@ -75803,161 +79686,809 @@ SQLITE_PRIVATE int sqlite3VdbeSorterWrite(
** * The total memory allocated for the in-memory list is greater
** than (page-size * 10) and sqlite3HeapNearlyFull() returns true.
*/
- if( rc==SQLITE_OK && pSorter->mxPmaSize>0 && (
- (pSorter->nInMemory>pSorter->mxPmaSize)
- || (pSorter->nInMemory>pSorter->mnPmaSize && sqlite3HeapNearlyFull())
- )){
-#ifdef SQLITE_DEBUG
- i64 nExpect = pSorter->iWriteOff
- + sqlite3VarintLen(pSorter->nInMemory)
- + pSorter->nInMemory;
+ nReq = pVal->n + sizeof(SorterRecord);
+ nPMA = pVal->n + sqlite3VarintLen(pVal->n);
+ if( pSorter->mxPmaSize ){
+ if( pSorter->list.aMemory ){
+ bFlush = pSorter->iMemory && (pSorter->iMemory+nReq) > pSorter->mxPmaSize;
+ }else{
+ bFlush = (
+ (pSorter->list.szPMA > pSorter->mxPmaSize)
+ || (pSorter->list.szPMA > pSorter->mnPmaSize && sqlite3HeapNearlyFull())
+ );
+ }
+ if( bFlush ){
+ rc = vdbeSorterFlushPMA(pSorter);
+ pSorter->list.szPMA = 0;
+ pSorter->iMemory = 0;
+ assert( rc!=SQLITE_OK || pSorter->list.pList==0 );
+ }
+ }
+
+ pSorter->list.szPMA += nPMA;
+ if( nPMA>pSorter->mxKeysize ){
+ pSorter->mxKeysize = nPMA;
+ }
+
+ if( pSorter->list.aMemory ){
+ int nMin = pSorter->iMemory + nReq;
+
+ if( nMin>pSorter->nMemory ){
+ u8 *aNew;
+ int nNew = pSorter->nMemory * 2;
+ while( nNew < nMin ) nNew = nNew*2;
+ if( nNew > pSorter->mxPmaSize ) nNew = pSorter->mxPmaSize;
+ if( nNew < nMin ) nNew = nMin;
+
+ aNew = sqlite3Realloc(pSorter->list.aMemory, nNew);
+ if( !aNew ) return SQLITE_NOMEM;
+ pSorter->list.pList = (SorterRecord*)(
+ aNew + ((u8*)pSorter->list.pList - pSorter->list.aMemory)
+ );
+ pSorter->list.aMemory = aNew;
+ pSorter->nMemory = nNew;
+ }
+
+ pNew = (SorterRecord*)&pSorter->list.aMemory[pSorter->iMemory];
+ pSorter->iMemory += ROUND8(nReq);
+ pNew->u.iNext = (int)((u8*)(pSorter->list.pList) - pSorter->list.aMemory);
+ }else{
+ pNew = (SorterRecord *)sqlite3Malloc(nReq);
+ if( pNew==0 ){
+ return SQLITE_NOMEM;
+ }
+ pNew->u.pNext = pSorter->list.pList;
+ }
+
+ memcpy(SRVAL(pNew), pVal->z, pVal->n);
+ pNew->nVal = pVal->n;
+ pSorter->list.pList = pNew;
+
+ return rc;
+}
+
+/*
+** Read keys from pIncr->pMerger and populate pIncr->aFile[1]. The format
+** of the data stored in aFile[1] is the same as that used by regular PMAs,
+** except that the number-of-bytes varint is omitted from the start.
+*/
+static int vdbeIncrPopulate(IncrMerger *pIncr){
+ int rc = SQLITE_OK;
+ int rc2;
+ i64 iStart = pIncr->iStartOff;
+ SorterFile *pOut = &pIncr->aFile[1];
+ SortSubtask *pTask = pIncr->pTask;
+ MergeEngine *pMerger = pIncr->pMerger;
+ PmaWriter writer;
+ assert( pIncr->bEof==0 );
+
+ vdbeSorterPopulateDebug(pTask, "enter");
+
+ vdbePmaWriterInit(pOut->pFd, &writer, pTask->pSorter->pgsz, iStart);
+ while( rc==SQLITE_OK ){
+ int dummy;
+ PmaReader *pReader = &pMerger->aReadr[ pMerger->aTree[1] ];
+ int nKey = pReader->nKey;
+ i64 iEof = writer.iWriteOff + writer.iBufEnd;
+
+ /* Check if the output file is full or if the input has been exhausted.
+ ** In either case exit the loop. */
+ if( pReader->pFd==0 ) break;
+ if( (iEof + nKey + sqlite3VarintLen(nKey))>(iStart + pIncr->mxSz) ) break;
+
+ /* Write the next key to the output. */
+ vdbePmaWriteVarint(&writer, nKey);
+ vdbePmaWriteBlob(&writer, pReader->aKey, nKey);
+ assert( pIncr->pMerger->pTask==pTask );
+ rc = vdbeMergeEngineStep(pIncr->pMerger, &dummy);
+ }
+
+ rc2 = vdbePmaWriterFinish(&writer, &pOut->iEof);
+ if( rc==SQLITE_OK ) rc = rc2;
+ vdbeSorterPopulateDebug(pTask, "exit");
+ return rc;
+}
+
+#if SQLITE_MAX_WORKER_THREADS>0
+/*
+** The main routine for background threads that populate aFile[1] of
+** multi-threaded IncrMerger objects.
+*/
+static void *vdbeIncrPopulateThread(void *pCtx){
+ IncrMerger *pIncr = (IncrMerger*)pCtx;
+ void *pRet = SQLITE_INT_TO_PTR( vdbeIncrPopulate(pIncr) );
+ pIncr->pTask->bDone = 1;
+ return pRet;
+}
+
+/*
+** Launch a background thread to populate aFile[1] of pIncr.
+*/
+static int vdbeIncrBgPopulate(IncrMerger *pIncr){
+ void *p = (void*)pIncr;
+ assert( pIncr->bUseThread );
+ return vdbeSorterCreateThread(pIncr->pTask, vdbeIncrPopulateThread, p);
+}
+#endif
+
+/*
+** This function is called when the PmaReader corresponding to pIncr has
+** finished reading the contents of aFile[0]. Its purpose is to "refill"
+** aFile[0] such that the PmaReader should start rereading it from the
+** beginning.
+**
+** For single-threaded objects, this is accomplished by literally reading
+** keys from pIncr->pMerger and repopulating aFile[0].
+**
+** For multi-threaded objects, all that is required is to wait until the
+** background thread is finished (if it is not already) and then swap
+** aFile[0] and aFile[1] in place. If the contents of pMerger have not
+** been exhausted, this function also launches a new background thread
+** to populate the new aFile[1].
+**
+** SQLITE_OK is returned on success, or an SQLite error code otherwise.
+*/
+static int vdbeIncrSwap(IncrMerger *pIncr){
+ int rc = SQLITE_OK;
+
+#if SQLITE_MAX_WORKER_THREADS>0
+ if( pIncr->bUseThread ){
+ rc = vdbeSorterJoinThread(pIncr->pTask);
+
+ if( rc==SQLITE_OK ){
+ SorterFile f0 = pIncr->aFile[0];
+ pIncr->aFile[0] = pIncr->aFile[1];
+ pIncr->aFile[1] = f0;
+ }
+
+ if( rc==SQLITE_OK ){
+ if( pIncr->aFile[0].iEof==pIncr->iStartOff ){
+ pIncr->bEof = 1;
+ }else{
+ rc = vdbeIncrBgPopulate(pIncr);
+ }
+ }
+ }else
#endif
- rc = vdbeSorterListToPMA(db, pCsr);
- pSorter->nInMemory = 0;
- assert( rc!=SQLITE_OK || (nExpect==pSorter->iWriteOff) );
+ {
+ rc = vdbeIncrPopulate(pIncr);
+ pIncr->aFile[0] = pIncr->aFile[1];
+ if( pIncr->aFile[0].iEof==pIncr->iStartOff ){
+ pIncr->bEof = 1;
+ }
}
return rc;
}
/*
-** Helper function for sqlite3VdbeSorterRewind().
+** Allocate and return a new IncrMerger object to read data from pMerger.
+**
+** If an OOM condition is encountered, return NULL. In this case free the
+** pMerger argument before returning.
*/
-static int vdbeSorterInitMerge(
- sqlite3 *db, /* Database handle */
- const VdbeCursor *pCsr, /* Cursor handle for this sorter */
- i64 *pnByte /* Sum of bytes in all opened PMAs */
+static int vdbeIncrMergerNew(
+ SortSubtask *pTask, /* The thread that will be using the new IncrMerger */
+ MergeEngine *pMerger, /* The MergeEngine that the IncrMerger will control */
+ IncrMerger **ppOut /* Write the new IncrMerger here */
+){
+ int rc = SQLITE_OK;
+ IncrMerger *pIncr = *ppOut = (IncrMerger*)
+ (sqlite3FaultSim(100) ? 0 : sqlite3MallocZero(sizeof(*pIncr)));
+ if( pIncr ){
+ pIncr->pMerger = pMerger;
+ pIncr->pTask = pTask;
+ pIncr->mxSz = MAX(pTask->pSorter->mxKeysize+9,pTask->pSorter->mxPmaSize/2);
+ pTask->file2.iEof += pIncr->mxSz;
+ }else{
+ vdbeMergeEngineFree(pMerger);
+ rc = SQLITE_NOMEM;
+ }
+ return rc;
+}
+
+#if SQLITE_MAX_WORKER_THREADS>0
+/*
+** Set the "use-threads" flag on object pIncr.
+*/
+static void vdbeIncrMergerSetThreads(IncrMerger *pIncr){
+ pIncr->bUseThread = 1;
+ pIncr->pTask->file2.iEof -= pIncr->mxSz;
+}
+#endif /* SQLITE_MAX_WORKER_THREADS>0 */
+
+
+
+/*
+** Recompute pMerger->aTree[iOut] by comparing the next keys on the
+** two PmaReaders that feed that entry. Neither of the PmaReaders
+** are advanced. This routine merely does the comparison.
+*/
+static void vdbeMergeEngineCompare(
+ MergeEngine *pMerger, /* Merge engine containing PmaReaders to compare */
+ int iOut /* Store the result in pMerger->aTree[iOut] */
+){
+ int i1;
+ int i2;
+ int iRes;
+ PmaReader *p1;
+ PmaReader *p2;
+
+ assert( iOut<pMerger->nTree && iOut>0 );
+
+ if( iOut>=(pMerger->nTree/2) ){
+ i1 = (iOut - pMerger->nTree/2) * 2;
+ i2 = i1 + 1;
+ }else{
+ i1 = pMerger->aTree[iOut*2];
+ i2 = pMerger->aTree[iOut*2+1];
+ }
+
+ p1 = &pMerger->aReadr[i1];
+ p2 = &pMerger->aReadr[i2];
+
+ if( p1->pFd==0 ){
+ iRes = i2;
+ }else if( p2->pFd==0 ){
+ iRes = i1;
+ }else{
+ SortSubtask *pTask = pMerger->pTask;
+ int bCached = 0;
+ int res;
+ assert( pTask->pUnpacked!=0 ); /* from vdbeSortSubtaskMain() */
+ res = pTask->xCompare(
+ pTask, &bCached, p1->aKey, p1->nKey, p2->aKey, p2->nKey
+ );
+ if( res<=0 ){
+ iRes = i1;
+ }else{
+ iRes = i2;
+ }
+ }
+
+ pMerger->aTree[iOut] = iRes;
+}
+
+/*
+** Allowed values for the eMode parameter to vdbeMergeEngineInit()
+** and vdbePmaReaderIncrMergeInit().
+**
+** Only INCRINIT_NORMAL is valid in single-threaded builds (when
+** SQLITE_MAX_WORKER_THREADS==0). The other values are only used
+** when there exists one or more separate worker threads.
+*/
+#define INCRINIT_NORMAL 0
+#define INCRINIT_TASK 1
+#define INCRINIT_ROOT 2
+
+/*
+** Forward reference required as the vdbeIncrMergeInit() and
+** vdbePmaReaderIncrInit() routines are called mutually recursively when
+** building a merge tree.
+*/
+static int vdbePmaReaderIncrInit(PmaReader *pReadr, int eMode);
+
+/*
+** Initialize the MergeEngine object passed as the second argument. Once this
+** function returns, the first key of merged data may be read from the
+** MergeEngine object in the usual fashion.
+**
+** If argument eMode is INCRINIT_ROOT, then it is assumed that any IncrMerge
+** objects attached to the PmaReader objects that the merger reads from have
+** already been populated, but that they have not yet populated aFile[0] and
+** set the PmaReader objects up to read from it. In this case all that is
+** required is to call vdbePmaReaderNext() on each PmaReader to point it at
+** its first key.
+**
+** Otherwise, if eMode is any value other than INCRINIT_ROOT, then use
+** vdbePmaReaderIncrMergeInit() to initialize each PmaReader that feeds data
+** to pMerger.
+**
+** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
+*/
+static int vdbeMergeEngineInit(
+ SortSubtask *pTask, /* Thread that will run pMerger */
+ MergeEngine *pMerger, /* MergeEngine to initialize */
+ int eMode /* One of the INCRINIT_XXX constants */
){
- VdbeSorter *pSorter = pCsr->pSorter;
int rc = SQLITE_OK; /* Return code */
- int i; /* Used to iterator through aIter[] */
- i64 nByte = 0; /* Total bytes in all opened PMAs */
+ int i; /* For looping over PmaReader objects */
+ int nTree = pMerger->nTree;
+
+ /* eMode is always INCRINIT_NORMAL in single-threaded mode */
+ assert( SQLITE_MAX_WORKER_THREADS>0 || eMode==INCRINIT_NORMAL );
+
+ /* Verify that the MergeEngine is assigned to a single thread */
+ assert( pMerger->pTask==0 );
+ pMerger->pTask = pTask;
+
+ for(i=0; i<nTree; i++){
+ if( SQLITE_MAX_WORKER_THREADS>0 && eMode==INCRINIT_ROOT ){
+ /* PmaReaders should be normally initialized in order, as if they are
+ ** reading from the same temp file this makes for more linear file IO.
+ ** However, in the INCRINIT_ROOT case, if PmaReader aReadr[nTask-1] is
+ ** in use it will block the vdbePmaReaderNext() call while it uses
+ ** the main thread to fill its buffer. So calling PmaReaderNext()
+ ** on this PmaReader before any of the multi-threaded PmaReaders takes
+ ** better advantage of multi-processor hardware. */
+ rc = vdbePmaReaderNext(&pMerger->aReadr[nTree-i-1]);
+ }else{
+ rc = vdbePmaReaderIncrInit(&pMerger->aReadr[i], INCRINIT_NORMAL);
+ }
+ if( rc!=SQLITE_OK ) return rc;
+ }
- /* Initialize the iterators. */
- for(i=0; i<SORTER_MAX_MERGE_COUNT; i++){
- VdbeSorterIter *pIter = &pSorter->aIter[i];
- rc = vdbeSorterIterInit(db, pSorter, pSorter->iReadOff, pIter, &nByte);
- pSorter->iReadOff = pIter->iEof;
- assert( rc!=SQLITE_OK || pSorter->iReadOff<=pSorter->iWriteOff );
- if( rc!=SQLITE_OK || pSorter->iReadOff>=pSorter->iWriteOff ) break;
+ for(i=pMerger->nTree-1; i>0; i--){
+ vdbeMergeEngineCompare(pMerger, i);
}
+ return pTask->pUnpacked->errCode;
+}
- /* Initialize the aTree[] array. */
- for(i=pSorter->nTree-1; rc==SQLITE_OK && i>0; i--){
- rc = vdbeSorterDoCompare(pCsr, i);
+/*
+** The PmaReader passed as the first argument is guaranteed to be an
+** incremental-reader (pReadr->pIncr!=0). This function serves to open
+** and/or initialize the temp file related fields of the IncrMerge
+** object at (pReadr->pIncr).
+**
+** If argument eMode is set to INCRINIT_NORMAL, then all PmaReaders
+** in the sub-tree headed by pReadr are also initialized. Data is then
+** loaded into the buffers belonging to pReadr and it is set to point to
+** the first key in its range.
+**
+** If argument eMode is set to INCRINIT_TASK, then pReadr is guaranteed
+** to be a multi-threaded PmaReader and this function is being called in a
+** background thread. In this case all PmaReaders in the sub-tree are
+** initialized as for INCRINIT_NORMAL and the aFile[1] buffer belonging to
+** pReadr is populated. However, pReadr itself is not set up to point
+** to its first key. A call to vdbePmaReaderNext() is still required to do
+** that.
+**
+** The reason this function does not call vdbePmaReaderNext() immediately
+** in the INCRINIT_TASK case is that vdbePmaReaderNext() assumes that it has
+** to block on thread (pTask->thread) before accessing aFile[1]. But, since
+** this entire function is being run by thread (pTask->thread), that will
+** lead to the current background thread attempting to join itself.
+**
+** Finally, if argument eMode is set to INCRINIT_ROOT, it may be assumed
+** that pReadr->pIncr is a multi-threaded IncrMerge objects, and that all
+** child-trees have already been initialized using IncrInit(INCRINIT_TASK).
+** In this case vdbePmaReaderNext() is called on all child PmaReaders and
+** the current PmaReader set to point to the first key in its range.
+**
+** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
+*/
+static int vdbePmaReaderIncrMergeInit(PmaReader *pReadr, int eMode){
+ int rc = SQLITE_OK;
+ IncrMerger *pIncr = pReadr->pIncr;
+ SortSubtask *pTask = pIncr->pTask;
+ sqlite3 *db = pTask->pSorter->db;
+
+ /* eMode is always INCRINIT_NORMAL in single-threaded mode */
+ assert( SQLITE_MAX_WORKER_THREADS>0 || eMode==INCRINIT_NORMAL );
+
+ rc = vdbeMergeEngineInit(pTask, pIncr->pMerger, eMode);
+
+ /* Set up the required files for pIncr. A multi-theaded IncrMerge object
+ ** requires two temp files to itself, whereas a single-threaded object
+ ** only requires a region of pTask->file2. */
+ if( rc==SQLITE_OK ){
+ int mxSz = pIncr->mxSz;
+#if SQLITE_MAX_WORKER_THREADS>0
+ if( pIncr->bUseThread ){
+ rc = vdbeSorterOpenTempFile(db, mxSz, &pIncr->aFile[0].pFd);
+ if( rc==SQLITE_OK ){
+ rc = vdbeSorterOpenTempFile(db, mxSz, &pIncr->aFile[1].pFd);
+ }
+ }else
+#endif
+ /*if( !pIncr->bUseThread )*/{
+ if( pTask->file2.pFd==0 ){
+ assert( pTask->file2.iEof>0 );
+ rc = vdbeSorterOpenTempFile(db, pTask->file2.iEof, &pTask->file2.pFd);
+ pTask->file2.iEof = 0;
+ }
+ if( rc==SQLITE_OK ){
+ pIncr->aFile[1].pFd = pTask->file2.pFd;
+ pIncr->iStartOff = pTask->file2.iEof;
+ pTask->file2.iEof += mxSz;
+ }
+ }
+ }
+
+#if SQLITE_MAX_WORKER_THREADS>0
+ if( rc==SQLITE_OK && pIncr->bUseThread ){
+ /* Use the current thread to populate aFile[1], even though this
+ ** PmaReader is multi-threaded. If this is an INCRINIT_TASK object,
+ ** then this function is already running in background thread
+ ** pIncr->pTask->thread.
+ **
+ ** If this is the INCRINIT_ROOT object, then it is running in the
+ ** main VDBE thread. But that is Ok, as that thread cannot return
+ ** control to the VDBE or proceed with anything useful until the
+ ** first results are ready from this merger object anyway.
+ */
+ assert( eMode==INCRINIT_ROOT || eMode==INCRINIT_TASK );
+ rc = vdbeIncrPopulate(pIncr);
+ }
+#endif
+
+ if( rc==SQLITE_OK && (SQLITE_MAX_WORKER_THREADS==0 || eMode!=INCRINIT_TASK) ){
+ rc = vdbePmaReaderNext(pReadr);
}
- *pnByte = nByte;
return rc;
}
+#if SQLITE_MAX_WORKER_THREADS>0
/*
-** Once the sorter has been populated, this function is called to prepare
-** for iterating through its contents in sorted order.
+** The main routine for vdbePmaReaderIncrMergeInit() operations run in
+** background threads.
*/
-SQLITE_PRIVATE int sqlite3VdbeSorterRewind(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){
- VdbeSorter *pSorter = pCsr->pSorter;
- int rc; /* Return code */
- sqlite3_file *pTemp2 = 0; /* Second temp file to use */
- i64 iWrite2 = 0; /* Write offset for pTemp2 */
- int nIter; /* Number of iterators used */
- int nByte; /* Bytes of space required for aIter/aTree */
- int N = 2; /* Power of 2 >= nIter */
+static void *vdbePmaReaderBgIncrInit(void *pCtx){
+ PmaReader *pReader = (PmaReader*)pCtx;
+ void *pRet = SQLITE_INT_TO_PTR(
+ vdbePmaReaderIncrMergeInit(pReader,INCRINIT_TASK)
+ );
+ pReader->pIncr->pTask->bDone = 1;
+ return pRet;
+}
+#endif
- assert( pSorter );
+/*
+** If the PmaReader passed as the first argument is not an incremental-reader
+** (if pReadr->pIncr==0), then this function is a no-op. Otherwise, it invokes
+** the vdbePmaReaderIncrMergeInit() function with the parameters passed to
+** this routine to initialize the incremental merge.
+**
+** If the IncrMerger object is multi-threaded (IncrMerger.bUseThread==1),
+** then a background thread is launched to call vdbePmaReaderIncrMergeInit().
+** Or, if the IncrMerger is single threaded, the same function is called
+** using the current thread.
+*/
+static int vdbePmaReaderIncrInit(PmaReader *pReadr, int eMode){
+ IncrMerger *pIncr = pReadr->pIncr; /* Incremental merger */
+ int rc = SQLITE_OK; /* Return code */
+ if( pIncr ){
+#if SQLITE_MAX_WORKER_THREADS>0
+ assert( pIncr->bUseThread==0 || eMode==INCRINIT_TASK );
+ if( pIncr->bUseThread ){
+ void *pCtx = (void*)pReadr;
+ rc = vdbeSorterCreateThread(pIncr->pTask, vdbePmaReaderBgIncrInit, pCtx);
+ }else
+#endif
+ {
+ rc = vdbePmaReaderIncrMergeInit(pReadr, eMode);
+ }
+ }
+ return rc;
+}
- /* If no data has been written to disk, then do not do so now. Instead,
- ** sort the VdbeSorter.pRecord list. The vdbe layer will read data directly
- ** from the in-memory list. */
- if( pSorter->nPMA==0 ){
- *pbEof = !pSorter->pRecord;
- assert( pSorter->aTree==0 );
- return vdbeSorterSort(pCsr);
+/*
+** Allocate a new MergeEngine object to merge the contents of nPMA level-0
+** PMAs from pTask->file. If no error occurs, set *ppOut to point to
+** the new object and return SQLITE_OK. Or, if an error does occur, set *ppOut
+** to NULL and return an SQLite error code.
+**
+** When this function is called, *piOffset is set to the offset of the
+** first PMA to read from pTask->file. Assuming no error occurs, it is
+** set to the offset immediately following the last byte of the last
+** PMA before returning. If an error does occur, then the final value of
+** *piOffset is undefined.
+*/
+static int vdbeMergeEngineLevel0(
+ SortSubtask *pTask, /* Sorter task to read from */
+ int nPMA, /* Number of PMAs to read */
+ i64 *piOffset, /* IN/OUT: Readr offset in pTask->file */
+ MergeEngine **ppOut /* OUT: New merge-engine */
+){
+ MergeEngine *pNew; /* Merge engine to return */
+ i64 iOff = *piOffset;
+ int i;
+ int rc = SQLITE_OK;
+
+ *ppOut = pNew = vdbeMergeEngineNew(nPMA);
+ if( pNew==0 ) rc = SQLITE_NOMEM;
+
+ for(i=0; i<nPMA && rc==SQLITE_OK; i++){
+ i64 nDummy;
+ PmaReader *pReadr = &pNew->aReadr[i];
+ rc = vdbePmaReaderInit(pTask, &pTask->file, iOff, pReadr, &nDummy);
+ iOff = pReadr->iEof;
}
- /* Write the current in-memory list to a PMA. */
- rc = vdbeSorterListToPMA(db, pCsr);
- if( rc!=SQLITE_OK ) return rc;
+ if( rc!=SQLITE_OK ){
+ vdbeMergeEngineFree(pNew);
+ *ppOut = 0;
+ }
+ *piOffset = iOff;
+ return rc;
+}
- /* Allocate space for aIter[] and aTree[]. */
- nIter = pSorter->nPMA;
- if( nIter>SORTER_MAX_MERGE_COUNT ) nIter = SORTER_MAX_MERGE_COUNT;
- assert( nIter>0 );
- while( N<nIter ) N += N;
- nByte = N * (sizeof(int) + sizeof(VdbeSorterIter));
- pSorter->aIter = (VdbeSorterIter *)sqlite3DbMallocZero(db, nByte);
- if( !pSorter->aIter ) return SQLITE_NOMEM;
- pSorter->aTree = (int *)&pSorter->aIter[N];
- pSorter->nTree = N;
+/*
+** Return the depth of a tree comprising nPMA PMAs, assuming a fanout of
+** SORTER_MAX_MERGE_COUNT. The returned value does not include leaf nodes.
+**
+** i.e.
+**
+** nPMA<=16 -> TreeDepth() == 0
+** nPMA<=256 -> TreeDepth() == 1
+** nPMA<=65536 -> TreeDepth() == 2
+*/
+static int vdbeSorterTreeDepth(int nPMA){
+ int nDepth = 0;
+ i64 nDiv = SORTER_MAX_MERGE_COUNT;
+ while( nDiv < (i64)nPMA ){
+ nDiv = nDiv * SORTER_MAX_MERGE_COUNT;
+ nDepth++;
+ }
+ return nDepth;
+}
- do {
- int iNew; /* Index of new, merged, PMA */
+/*
+** pRoot is the root of an incremental merge-tree with depth nDepth (according
+** to vdbeSorterTreeDepth()). pLeaf is the iSeq'th leaf to be added to the
+** tree, counting from zero. This function adds pLeaf to the tree.
+**
+** If successful, SQLITE_OK is returned. If an error occurs, an SQLite error
+** code is returned and pLeaf is freed.
+*/
+static int vdbeSorterAddToTree(
+ SortSubtask *pTask, /* Task context */
+ int nDepth, /* Depth of tree according to TreeDepth() */
+ int iSeq, /* Sequence number of leaf within tree */
+ MergeEngine *pRoot, /* Root of tree */
+ MergeEngine *pLeaf /* Leaf to add to tree */
+){
+ int rc = SQLITE_OK;
+ int nDiv = 1;
+ int i;
+ MergeEngine *p = pRoot;
+ IncrMerger *pIncr;
- for(iNew=0;
- rc==SQLITE_OK && iNew*SORTER_MAX_MERGE_COUNT<pSorter->nPMA;
- iNew++
- ){
- int rc2; /* Return code from fileWriterFinish() */
- FileWriter writer; /* Object used to write to disk */
- i64 nWrite; /* Number of bytes in new PMA */
+ rc = vdbeIncrMergerNew(pTask, pLeaf, &pIncr);
- memset(&writer, 0, sizeof(FileWriter));
+ for(i=1; i<nDepth; i++){
+ nDiv = nDiv * SORTER_MAX_MERGE_COUNT;
+ }
- /* If there are SORTER_MAX_MERGE_COUNT or less PMAs in file pTemp1,
- ** initialize an iterator for each of them and break out of the loop.
- ** These iterators will be incrementally merged as the VDBE layer calls
- ** sqlite3VdbeSorterNext().
- **
- ** Otherwise, if pTemp1 contains more than SORTER_MAX_MERGE_COUNT PMAs,
- ** initialize interators for SORTER_MAX_MERGE_COUNT of them. These PMAs
- ** are merged into a single PMA that is written to file pTemp2.
- */
- rc = vdbeSorterInitMerge(db, pCsr, &nWrite);
- assert( rc!=SQLITE_OK || pSorter->aIter[ pSorter->aTree[1] ].pFile );
- if( rc!=SQLITE_OK || pSorter->nPMA<=SORTER_MAX_MERGE_COUNT ){
- break;
+ for(i=1; i<nDepth && rc==SQLITE_OK; i++){
+ int iIter = (iSeq / nDiv) % SORTER_MAX_MERGE_COUNT;
+ PmaReader *pReadr = &p->aReadr[iIter];
+
+ if( pReadr->pIncr==0 ){
+ MergeEngine *pNew = vdbeMergeEngineNew(SORTER_MAX_MERGE_COUNT);
+ if( pNew==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ rc = vdbeIncrMergerNew(pTask, pNew, &pReadr->pIncr);
}
+ }
+ if( rc==SQLITE_OK ){
+ p = pReadr->pIncr->pMerger;
+ nDiv = nDiv / SORTER_MAX_MERGE_COUNT;
+ }
+ }
- /* Open the second temp file, if it is not already open. */
- if( pTemp2==0 ){
- assert( iWrite2==0 );
- rc = vdbeSorterOpenTempFile(db, &pTemp2);
+ if( rc==SQLITE_OK ){
+ p->aReadr[iSeq % SORTER_MAX_MERGE_COUNT].pIncr = pIncr;
+ }else{
+ vdbeIncrFree(pIncr);
+ }
+ return rc;
+}
+
+/*
+** This function is called as part of a SorterRewind() operation on a sorter
+** that has already written two or more level-0 PMAs to one or more temp
+** files. It builds a tree of MergeEngine/IncrMerger/PmaReader objects that
+** can be used to incrementally merge all PMAs on disk.
+**
+** If successful, SQLITE_OK is returned and *ppOut set to point to the
+** MergeEngine object at the root of the tree before returning. Or, if an
+** error occurs, an SQLite error code is returned and the final value
+** of *ppOut is undefined.
+*/
+static int vdbeSorterMergeTreeBuild(
+ VdbeSorter *pSorter, /* The VDBE cursor that implements the sort */
+ MergeEngine **ppOut /* Write the MergeEngine here */
+){
+ MergeEngine *pMain = 0;
+ int rc = SQLITE_OK;
+ int iTask;
+
+#if SQLITE_MAX_WORKER_THREADS>0
+ /* If the sorter uses more than one task, then create the top-level
+ ** MergeEngine here. This MergeEngine will read data from exactly
+ ** one PmaReader per sub-task. */
+ assert( pSorter->bUseThreads || pSorter->nTask==1 );
+ if( pSorter->nTask>1 ){
+ pMain = vdbeMergeEngineNew(pSorter->nTask);
+ if( pMain==0 ) rc = SQLITE_NOMEM;
+ }
+#endif
+
+ for(iTask=0; rc==SQLITE_OK && iTask<pSorter->nTask; iTask++){
+ SortSubtask *pTask = &pSorter->aTask[iTask];
+ assert( pTask->nPMA>0 || SQLITE_MAX_WORKER_THREADS>0 );
+ if( SQLITE_MAX_WORKER_THREADS==0 || pTask->nPMA ){
+ MergeEngine *pRoot = 0; /* Root node of tree for this task */
+ int nDepth = vdbeSorterTreeDepth(pTask->nPMA);
+ i64 iReadOff = 0;
+
+ if( pTask->nPMA<=SORTER_MAX_MERGE_COUNT ){
+ rc = vdbeMergeEngineLevel0(pTask, pTask->nPMA, &iReadOff, &pRoot);
+ }else{
+ int i;
+ int iSeq = 0;
+ pRoot = vdbeMergeEngineNew(SORTER_MAX_MERGE_COUNT);
+ if( pRoot==0 ) rc = SQLITE_NOMEM;
+ for(i=0; i<pTask->nPMA && rc==SQLITE_OK; i += SORTER_MAX_MERGE_COUNT){
+ MergeEngine *pMerger = 0; /* New level-0 PMA merger */
+ int nReader; /* Number of level-0 PMAs to merge */
+
+ nReader = MIN(pTask->nPMA - i, SORTER_MAX_MERGE_COUNT);
+ rc = vdbeMergeEngineLevel0(pTask, nReader, &iReadOff, &pMerger);
+ if( rc==SQLITE_OK ){
+ rc = vdbeSorterAddToTree(pTask, nDepth, iSeq++, pRoot, pMerger);
+ }
+ }
}
if( rc==SQLITE_OK ){
- int bEof = 0;
- fileWriterInit(db, pTemp2, &writer, iWrite2);
- fileWriterWriteVarint(&writer, nWrite);
- while( rc==SQLITE_OK && bEof==0 ){
- VdbeSorterIter *pIter = &pSorter->aIter[ pSorter->aTree[1] ];
- assert( pIter->pFile );
+#if SQLITE_MAX_WORKER_THREADS>0
+ if( pMain!=0 ){
+ rc = vdbeIncrMergerNew(pTask, pRoot, &pMain->aReadr[iTask].pIncr);
+ }else
+#endif
+ {
+ assert( pMain==0 );
+ pMain = pRoot;
+ }
+ }else{
+ vdbeMergeEngineFree(pRoot);
+ }
+ }
+ }
+
+ if( rc!=SQLITE_OK ){
+ vdbeMergeEngineFree(pMain);
+ pMain = 0;
+ }
+ *ppOut = pMain;
+ return rc;
+}
+
+/*
+** This function is called as part of an sqlite3VdbeSorterRewind() operation
+** on a sorter that has written two or more PMAs to temporary files. It sets
+** up either VdbeSorter.pMerger (for single threaded sorters) or pReader
+** (for multi-threaded sorters) so that it can be used to iterate through
+** all records stored in the sorter.
+**
+** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
+*/
+static int vdbeSorterSetupMerge(VdbeSorter *pSorter){
+ int rc; /* Return code */
+ SortSubtask *pTask0 = &pSorter->aTask[0];
+ MergeEngine *pMain = 0;
+#if SQLITE_MAX_WORKER_THREADS
+ sqlite3 *db = pTask0->pSorter->db;
+ int i;
+ SorterCompare xCompare = vdbeSorterGetCompare(pSorter);
+ for(i=0; i<pSorter->nTask; i++){
+ pSorter->aTask[i].xCompare = xCompare;
+ }
+#endif
- fileWriterWriteVarint(&writer, pIter->nKey);
- fileWriterWrite(&writer, pIter->aKey, pIter->nKey);
- rc = sqlite3VdbeSorterNext(db, pCsr, &bEof);
+ rc = vdbeSorterMergeTreeBuild(pSorter, &pMain);
+ if( rc==SQLITE_OK ){
+#if SQLITE_MAX_WORKER_THREADS
+ assert( pSorter->bUseThreads==0 || pSorter->nTask>1 );
+ if( pSorter->bUseThreads ){
+ int iTask;
+ PmaReader *pReadr = 0;
+ SortSubtask *pLast = &pSorter->aTask[pSorter->nTask-1];
+ rc = vdbeSortAllocUnpacked(pLast);
+ if( rc==SQLITE_OK ){
+ pReadr = (PmaReader*)sqlite3DbMallocZero(db, sizeof(PmaReader));
+ pSorter->pReader = pReadr;
+ if( pReadr==0 ) rc = SQLITE_NOMEM;
+ }
+ if( rc==SQLITE_OK ){
+ rc = vdbeIncrMergerNew(pLast, pMain, &pReadr->pIncr);
+ if( rc==SQLITE_OK ){
+ vdbeIncrMergerSetThreads(pReadr->pIncr);
+ for(iTask=0; iTask<(pSorter->nTask-1); iTask++){
+ IncrMerger *pIncr;
+ if( (pIncr = pMain->aReadr[iTask].pIncr) ){
+ vdbeIncrMergerSetThreads(pIncr);
+ assert( pIncr->pTask!=pLast );
+ }
+ }
+ for(iTask=0; rc==SQLITE_OK && iTask<pSorter->nTask; iTask++){
+ /* Check that:
+ **
+ ** a) The incremental merge object is configured to use the
+ ** right task, and
+ ** b) If it is using task (nTask-1), it is configured to run
+ ** in single-threaded mode. This is important, as the
+ ** root merge (INCRINIT_ROOT) will be using the same task
+ ** object.
+ */
+ PmaReader *p = &pMain->aReadr[iTask];
+ assert( p->pIncr==0 || (
+ (p->pIncr->pTask==&pSorter->aTask[iTask]) /* a */
+ && (iTask!=pSorter->nTask-1 || p->pIncr->bUseThread==0) /* b */
+ ));
+ rc = vdbePmaReaderIncrInit(p, INCRINIT_TASK);
+ }
}
- rc2 = fileWriterFinish(db, &writer, &iWrite2);
- if( rc==SQLITE_OK ) rc = rc2;
+ pMain = 0;
}
+ if( rc==SQLITE_OK ){
+ rc = vdbePmaReaderIncrMergeInit(pReadr, INCRINIT_ROOT);
+ }
+ }else
+#endif
+ {
+ rc = vdbeMergeEngineInit(pTask0, pMain, INCRINIT_NORMAL);
+ pSorter->pMerger = pMain;
+ pMain = 0;
}
+ }
- if( pSorter->nPMA<=SORTER_MAX_MERGE_COUNT ){
- break;
+ if( rc!=SQLITE_OK ){
+ vdbeMergeEngineFree(pMain);
+ }
+ return rc;
+}
+
+
+/*
+** Once the sorter has been populated by calls to sqlite3VdbeSorterWrite,
+** this function is called to prepare for iterating through the records
+** in sorted order.
+*/
+SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *pCsr, int *pbEof){
+ VdbeSorter *pSorter = pCsr->pSorter;
+ int rc = SQLITE_OK; /* Return code */
+
+ assert( pSorter );
+
+ /* If no data has been written to disk, then do not do so now. Instead,
+ ** sort the VdbeSorter.pRecord list. The vdbe layer will read data directly
+ ** from the in-memory list. */
+ if( pSorter->bUsePMA==0 ){
+ if( pSorter->list.pList ){
+ *pbEof = 0;
+ rc = vdbeSorterSort(&pSorter->aTask[0], &pSorter->list);
}else{
- sqlite3_file *pTmp = pSorter->pTemp1;
- pSorter->nPMA = iNew;
- pSorter->pTemp1 = pTemp2;
- pTemp2 = pTmp;
- pSorter->iWriteOff = iWrite2;
- pSorter->iReadOff = 0;
- iWrite2 = 0;
+ *pbEof = 1;
}
- }while( rc==SQLITE_OK );
+ return rc;
+ }
+
+ /* Write the current in-memory list to a PMA. When the VdbeSorterWrite()
+ ** function flushes the contents of memory to disk, it immediately always
+ ** creates a new list consisting of a single key immediately afterwards.
+ ** So the list is never empty at this point. */
+ assert( pSorter->list.pList );
+ rc = vdbeSorterFlushPMA(pSorter);
+
+ /* Join all threads */
+ rc = vdbeSorterJoinAll(pSorter, rc);
- if( pTemp2 ){
- sqlite3OsCloseFree(pTemp2);
+ vdbeSorterRewindDebug("rewind");
+
+ /* Assuming no errors have occurred, set up a merger structure to
+ ** incrementally read and merge all remaining PMAs. */
+ assert( pSorter->pReader==0 );
+ if( rc==SQLITE_OK ){
+ rc = vdbeSorterSetupMerge(pSorter);
+ *pbEof = 0;
}
- *pbEof = (pSorter->aIter[pSorter->aTree[1]].pFile==0);
+
+ vdbeSorterRewindDebug("rewinddone");
return rc;
}
@@ -75968,63 +80499,28 @@ SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, in
VdbeSorter *pSorter = pCsr->pSorter;
int rc; /* Return code */
- if( pSorter->aTree ){
- int iPrev = pSorter->aTree[1];/* Index of iterator to advance */
- rc = vdbeSorterIterNext(db, &pSorter->aIter[iPrev]);
- if( rc==SQLITE_OK ){
- int i; /* Index of aTree[] to recalculate */
- VdbeSorterIter *pIter1; /* First iterator to compare */
- VdbeSorterIter *pIter2; /* Second iterator to compare */
- u8 *pKey2; /* To pIter2->aKey, or 0 if record cached */
-
- /* Find the first two iterators to compare. The one that was just
- ** advanced (iPrev) and the one next to it in the array. */
- pIter1 = &pSorter->aIter[(iPrev & 0xFFFE)];
- pIter2 = &pSorter->aIter[(iPrev | 0x0001)];
- pKey2 = pIter2->aKey;
-
- for(i=(pSorter->nTree+iPrev)/2; i>0; i=i/2){
- /* Compare pIter1 and pIter2. Store the result in variable iRes. */
- int iRes;
- if( pIter1->pFile==0 ){
- iRes = +1;
- }else if( pIter2->pFile==0 ){
- iRes = -1;
- }else{
- vdbeSorterCompare(pCsr, 0,
- pIter1->aKey, pIter1->nKey, pKey2, pIter2->nKey, &iRes
- );
- }
-
- /* If pIter1 contained the smaller value, set aTree[i] to its index.
- ** Then set pIter2 to the next iterator to compare to pIter1. In this
- ** case there is no cache of pIter2 in pSorter->pUnpacked, so set
- ** pKey2 to point to the record belonging to pIter2.
- **
- ** Alternatively, if pIter2 contains the smaller of the two values,
- ** set aTree[i] to its index and update pIter1. If vdbeSorterCompare()
- ** was actually called above, then pSorter->pUnpacked now contains
- ** a value equivalent to pIter2. So set pKey2 to NULL to prevent
- ** vdbeSorterCompare() from decoding pIter2 again. */
- if( iRes<=0 ){
- pSorter->aTree[i] = (int)(pIter1 - pSorter->aIter);
- pIter2 = &pSorter->aIter[ pSorter->aTree[i ^ 0x0001] ];
- pKey2 = pIter2->aKey;
- }else{
- if( pIter1->pFile ) pKey2 = 0;
- pSorter->aTree[i] = (int)(pIter2 - pSorter->aIter);
- pIter1 = &pSorter->aIter[ pSorter->aTree[i ^ 0x0001] ];
- }
-
- }
- *pbEof = (pSorter->aIter[pSorter->aTree[1]].pFile==0);
+ assert( pSorter->bUsePMA || (pSorter->pReader==0 && pSorter->pMerger==0) );
+ if( pSorter->bUsePMA ){
+ assert( pSorter->pReader==0 || pSorter->pMerger==0 );
+ assert( pSorter->bUseThreads==0 || pSorter->pReader );
+ assert( pSorter->bUseThreads==1 || pSorter->pMerger );
+#if SQLITE_MAX_WORKER_THREADS>0
+ if( pSorter->bUseThreads ){
+ rc = vdbePmaReaderNext(pSorter->pReader);
+ *pbEof = (pSorter->pReader->pFd==0);
+ }else
+#endif
+ /*if( !pSorter->bUseThreads )*/ {
+ assert( pSorter->pMerger!=0 );
+ assert( pSorter->pMerger->pTask==(&pSorter->aTask[0]) );
+ rc = vdbeMergeEngineStep(pSorter->pMerger, pbEof);
}
}else{
- SorterRecord *pFree = pSorter->pRecord;
- pSorter->pRecord = pFree->pNext;
- pFree->pNext = 0;
- vdbeSorterRecordFree(db, pFree);
- *pbEof = !pSorter->pRecord;
+ SorterRecord *pFree = pSorter->list.pList;
+ pSorter->list.pList = pFree->u.pNext;
+ pFree->u.pNext = 0;
+ if( pSorter->list.aMemory==0 ) vdbeSorterRecordFree(db, pFree);
+ *pbEof = !pSorter->list.pList;
rc = SQLITE_OK;
}
return rc;
@@ -76039,14 +80535,21 @@ static void *vdbeSorterRowkey(
int *pnKey /* OUT: Size of current key in bytes */
){
void *pKey;
- if( pSorter->aTree ){
- VdbeSorterIter *pIter;
- pIter = &pSorter->aIter[ pSorter->aTree[1] ];
- *pnKey = pIter->nKey;
- pKey = pIter->aKey;
+ if( pSorter->bUsePMA ){
+ PmaReader *pReader;
+#if SQLITE_MAX_WORKER_THREADS>0
+ if( pSorter->bUseThreads ){
+ pReader = pSorter->pReader;
+ }else
+#endif
+ /*if( !pSorter->bUseThreads )*/{
+ pReader = &pSorter->pMerger->aReadr[pSorter->pMerger->aTree[1]];
+ }
+ *pnKey = pReader->nKey;
+ pKey = pReader->aKey;
}else{
- *pnKey = pSorter->pRecord->nVal;
- pKey = pSorter->pRecord->pVal;
+ *pnKey = pSorter->list.pList->nVal;
+ pKey = SRVAL(pSorter->list.pList);
}
return pKey;
}
@@ -76059,7 +80562,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(const VdbeCursor *pCsr, Mem *pOut){
void *pKey; int nKey; /* Sorter key to copy into pOut */
pKey = vdbeSorterRowkey(pSorter, &nKey);
- if( sqlite3VdbeMemGrow(pOut, nKey, 0) ){
+ if( sqlite3VdbeMemClearAndResize(pOut, nKey) ){
return SQLITE_NOMEM;
}
pOut->n = nKey;
@@ -76074,22 +80577,48 @@ SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(const VdbeCursor *pCsr, Mem *pOut){
** passed as the first argument currently points to. For the purposes of
** the comparison, ignore the rowid field at the end of each record.
**
+** If the sorter cursor key contains any NULL values, consider it to be
+** less than pVal. Even if pVal also contains NULL values.
+**
** If an error occurs, return an SQLite error code (i.e. SQLITE_NOMEM).
** Otherwise, set *pRes to a negative, zero or positive value if the
** key in pVal is smaller than, equal to or larger than the current sorter
** key.
+**
+** This routine forms the core of the OP_SorterCompare opcode, which in
+** turn is used to verify uniqueness when constructing a UNIQUE INDEX.
*/
SQLITE_PRIVATE int sqlite3VdbeSorterCompare(
const VdbeCursor *pCsr, /* Sorter cursor */
Mem *pVal, /* Value to compare to current sorter key */
- int nKeyCol, /* Only compare this many fields */
+ int nKeyCol, /* Compare this many columns */
int *pRes /* OUT: Result of comparison */
){
VdbeSorter *pSorter = pCsr->pSorter;
+ UnpackedRecord *r2 = pSorter->pUnpacked;
+ KeyInfo *pKeyInfo = pCsr->pKeyInfo;
+ int i;
void *pKey; int nKey; /* Sorter key to compare pVal with */
+ if( r2==0 ){
+ char *p;
+ r2 = pSorter->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pKeyInfo,0,0,&p);
+ assert( pSorter->pUnpacked==(UnpackedRecord*)p );
+ if( r2==0 ) return SQLITE_NOMEM;
+ r2->nField = nKeyCol;
+ }
+ assert( r2->nField==nKeyCol );
+
pKey = vdbeSorterRowkey(pSorter, &nKey);
- vdbeSorterCompare(pCsr, nKeyCol, pVal->z, pVal->n, pKey, nKey, pRes);
+ sqlite3VdbeRecordUnpack(pKeyInfo, nKey, pKey, r2);
+ for(i=0; i<nKeyCol; i++){
+ if( r2->aMem[i].flags & MEM_Null ){
+ *pRes = -1;
+ return SQLITE_OK;
+ }
+ }
+
+ *pRes = sqlite3VdbeRecordCompare(pVal->n, pVal->z, r2);
return SQLITE_OK;
}
@@ -76380,7 +80909,7 @@ typedef struct FileChunk FileChunk;
**
** The size chosen is a little less than a power of two. That way,
** the FileChunk object will have a size that almost exactly fills
-** a power-of-two allocation. This mimimizes wasted space in power-of-two
+** a power-of-two allocation. This minimizes wasted space in power-of-two
** memory allocators.
*/
#define JOURNAL_CHUNKSIZE ((int)(1024-sizeof(FileChunk*)))
@@ -76630,7 +81159,7 @@ SQLITE_PRIVATE int sqlite3MemJournalSize(void){
/*
** Walk an expression tree. Invoke the callback once for each node
-** of the expression, while decending. (In other words, the callback
+** of the expression, while descending. (In other words, the callback
** is invoked before visiting children.)
**
** The return value from the callback should be one of the WRC_*
@@ -76795,7 +81324,7 @@ SQLITE_PRIVATE int sqlite3WalkSelect(Walker *pWalker, Select *p){
** is a helper function - a callback for the tree walker.
*/
static int incrAggDepth(Walker *pWalker, Expr *pExpr){
- if( pExpr->op==TK_AGG_FUNCTION ) pExpr->op2 += pWalker->u.i;
+ if( pExpr->op==TK_AGG_FUNCTION ) pExpr->op2 += pWalker->u.n;
return WRC_Continue;
}
static void incrAggFunctionDepth(Expr *pExpr, int N){
@@ -76803,7 +81332,7 @@ static void incrAggFunctionDepth(Expr *pExpr, int N){
Walker w;
memset(&w, 0, sizeof(w));
w.xExprCallback = incrAggDepth;
- w.u.i = N;
+ w.u.n = N;
sqlite3WalkExpr(&w, pExpr);
}
}
@@ -76846,7 +81375,7 @@ static void incrAggFunctionDepth(Expr *pExpr, int N){
** SELECT a+b, c+d FROM t1 ORDER BY (a+b) COLLATE nocase;
**
** The nSubquery parameter specifies how many levels of subquery the
-** alias is removed from the original expression. The usually value is
+** alias is removed from the original expression. The usual value is
** zero but it might be more if the alias is contained within a subquery
** of the original expression. The Expr.op2 field of TK_AGG_FUNCTION
** structures must be increased by the nSubquery amount.
@@ -76866,7 +81395,6 @@ static void resolveAlias(
assert( iCol>=0 && iCol<pEList->nExpr );
pOrig = pEList->a[iCol].pExpr;
assert( pOrig!=0 );
- assert( pOrig->flags & EP_Resolved );
db = pParse->db;
pDup = sqlite3ExprDup(db, pOrig, 0);
if( pDup==0 ) return;
@@ -77014,9 +81542,10 @@ static int lookupName(
testcase( pNC->ncFlags & NC_PartIdx );
testcase( pNC->ncFlags & NC_IsCheck );
if( (pNC->ncFlags & (NC_PartIdx|NC_IsCheck))!=0 ){
- /* Silently ignore database qualifiers inside CHECK constraints and partial
- ** indices. Do not raise errors because that might break legacy and
- ** because it does not hurt anything to just ignore the database name. */
+ /* Silently ignore database qualifiers inside CHECK constraints and
+ ** partial indices. Do not raise errors because that might break
+ ** legacy and because it does not hurt anything to just ignore the
+ ** database name. */
zDb = 0;
}else{
for(i=0; i<db->nDb; i++){
@@ -77087,6 +81616,11 @@ static int lookupName(
if( pMatch ){
pExpr->iTable = pMatch->iCursor;
pExpr->pTab = pMatch->pTab;
+ /* RIGHT JOIN not (yet) supported */
+ assert( (pMatch->jointype & JT_RIGHT)==0 );
+ if( (pMatch->jointype & JT_LEFT)!=0 ){
+ ExprSetProperty(pExpr, EP_CanBeNull);
+ }
pSchema = pExpr->pTab->pSchema;
}
} /* if( pSrcList ) */
@@ -77351,7 +81885,7 @@ static int exprProbability(Expr *p){
sqlite3AtoF(p->u.zToken, &r, sqlite3Strlen30(p->u.zToken), SQLITE_UTF8);
assert( r>=0.0 );
if( r>1.0 ) return -1;
- return (int)(r*1000.0);
+ return (int)(r*134217728.0);
}
/*
@@ -77404,7 +81938,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
pExpr->affinity = SQLITE_AFF_INTEGER;
break;
}
-#endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) */
+#endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT)
+ && !defined(SQLITE_OMIT_SUBQUERY) */
/* A lone identifier is the name of a column.
*/
@@ -77469,26 +82004,25 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
if( n==2 ){
pExpr->iTable = exprProbability(pList->a[1].pExpr);
if( pExpr->iTable<0 ){
- sqlite3ErrorMsg(pParse, "second argument to likelihood() must be a "
- "constant between 0.0 and 1.0");
+ sqlite3ErrorMsg(pParse,
+ "second argument to likelihood() must be a "
+ "constant between 0.0 and 1.0");
pNC->nErr++;
}
}else{
- /* EVIDENCE-OF: R-61304-29449 The unlikely(X) function is equivalent to
- ** likelihood(X, 0.0625).
- ** EVIDENCE-OF: R-01283-11636 The unlikely(X) function is short-hand for
- ** likelihood(X,0.0625).
- ** EVIDENCE-OF: R-36850-34127 The likely(X) function is short-hand for
- ** likelihood(X,0.9375).
- ** EVIDENCE-OF: R-53436-40973 The likely(X) function is equivalent to
- ** likelihood(X,0.9375). */
+ /* EVIDENCE-OF: R-61304-29449 The unlikely(X) function is
+ ** equivalent to likelihood(X, 0.0625).
+ ** EVIDENCE-OF: R-01283-11636 The unlikely(X) function is
+ ** short-hand for likelihood(X,0.0625).
+ ** EVIDENCE-OF: R-36850-34127 The likely(X) function is short-hand
+ ** for likelihood(X,0.9375).
+ ** EVIDENCE-OF: R-53436-40973 The likely(X) function is equivalent
+ ** to likelihood(X,0.9375). */
/* TUNING: unlikely() probability is 0.0625. likely() is 0.9375 */
- pExpr->iTable = pDef->zName[0]=='u' ? 62 : 938;
+ pExpr->iTable = pDef->zName[0]=='u' ? 8388608 : 125829120;
}
}
- }
#ifndef SQLITE_OMIT_AUTHORIZATION
- if( pDef ){
auth = sqlite3AuthCheck(pParse, SQLITE_FUNCTION, 0, pDef->zName, 0);
if( auth!=SQLITE_OK ){
if( auth==SQLITE_DENY ){
@@ -77499,9 +82033,11 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
pExpr->op = TK_NULL;
return WRC_Prune;
}
- if( pDef->funcFlags & SQLITE_FUNC_CONSTANT ) ExprSetProperty(pExpr,EP_Constant);
- }
#endif
+ if( pDef->funcFlags & SQLITE_FUNC_CONSTANT ){
+ ExprSetProperty(pExpr,EP_ConstFunc);
+ }
+ }
if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){
sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId);
pNC->nErr++;
@@ -77524,7 +82060,13 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
pExpr->op2++;
pNC2 = pNC2->pNext;
}
- if( pNC2 ) pNC2->ncFlags |= NC_HasAgg;
+ assert( pDef!=0 );
+ if( pNC2 ){
+ assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg );
+ testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 );
+ pNC2->ncFlags |= NC_HasAgg | (pDef->funcFlags & SQLITE_FUNC_MINMAX);
+
+ }
pNC->ncFlags |= NC_AllowAgg;
}
/* FIX ME: Compute pExpr->affinity based on the expected return
@@ -77746,9 +82288,11 @@ static int resolveCompoundOrderBy(
if( pItem->pExpr==pE ){
pItem->pExpr = pNew;
}else{
- assert( pItem->pExpr->op==TK_COLLATE );
- assert( pItem->pExpr->pLeft==pE );
- pItem->pExpr->pLeft = pNew;
+ Expr *pParent = pItem->pExpr;
+ assert( pParent->op==TK_COLLATE );
+ while( pParent->pLeft->op==TK_COLLATE ) pParent = pParent->pLeft;
+ assert( pParent->pLeft==pE );
+ pParent->pLeft = pNew;
}
sqlite3ExprDelete(db, pE);
pItem->u.x.iOrderByCol = (u16)iCol;
@@ -77805,7 +82349,8 @@ SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(
resolveOutOfRangeError(pParse, zType, i+1, pEList->nExpr);
return 1;
}
- resolveAlias(pParse, pEList, pItem->u.x.iOrderByCol-1, pItem->pExpr, zType,0);
+ resolveAlias(pParse, pEList, pItem->u.x.iOrderByCol-1, pItem->pExpr,
+ zType,0);
}
}
return 0;
@@ -77885,7 +82430,7 @@ static int resolveOrderGroupBy(
}
/*
-** Resolve names in the SELECT statement p and all of its descendents.
+** Resolve names in the SELECT statement p and all of its descendants.
*/
static int resolveSelectStep(Walker *pWalker, Select *p){
NameContext *pOuterNC; /* Context that contains this SELECT */
@@ -77938,6 +82483,20 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
sqlite3ResolveExprNames(&sNC, p->pOffset) ){
return WRC_Abort;
}
+
+ /* If the SF_Converted flags is set, then this Select object was
+ ** was created by the convertCompoundSelectToSubquery() function.
+ ** In this case the ORDER BY clause (p->pOrderBy) should be resolved
+ ** as if it were part of the sub-query, not the parent. This block
+ ** moves the pOrderBy down to the sub-query. It will be moved back
+ ** after the names have been resolved. */
+ if( p->selFlags & SF_Converted ){
+ Select *pSub = p->pSrc->a[0].pSelect;
+ assert( p->pSrc->nSrc==1 && p->pOrderBy );
+ assert( pSub->pPrior && pSub->pOrderBy==0 );
+ pSub->pOrderBy = p->pOrderBy;
+ p->pOrderBy = 0;
+ }
/* Recursively resolve names in all subqueries
*/
@@ -77989,7 +82548,8 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
assert( (p->selFlags & SF_Aggregate)==0 );
pGroupBy = p->pGroupBy;
if( pGroupBy || (sNC.ncFlags & NC_HasAgg)!=0 ){
- p->selFlags |= SF_Aggregate;
+ assert( NC_MinMaxAgg==SF_MinMaxAgg );
+ p->selFlags |= SF_Aggregate | (sNC.ncFlags&NC_MinMaxAgg);
}else{
sNC.ncFlags &= ~NC_AllowAgg;
}
@@ -78019,12 +82579,30 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
sNC.pNext = 0;
sNC.ncFlags |= NC_AllowAgg;
+ /* If this is a converted compound query, move the ORDER BY clause from
+ ** the sub-query back to the parent query. At this point each term
+ ** within the ORDER BY clause has been transformed to an integer value.
+ ** These integers will be replaced by copies of the corresponding result
+ ** set expressions by the call to resolveOrderGroupBy() below. */
+ if( p->selFlags & SF_Converted ){
+ Select *pSub = p->pSrc->a[0].pSelect;
+ p->pOrderBy = pSub->pOrderBy;
+ pSub->pOrderBy = 0;
+ }
+
/* Process the ORDER BY clause for singleton SELECT statements.
** The ORDER BY clause for compounds SELECT statements is handled
** below, after all of the result-sets for all of the elements of
** the compound have been resolved.
+ **
+ ** If there is an ORDER BY clause on a term of a compound-select other
+ ** than the right-most term, then that is a syntax error. But the error
+ ** is not detected until much later, and so we need to go ahead and
+ ** resolve those symbols on the incorrect ORDER BY for consistency.
*/
- if( !isCompound && resolveOrderGroupBy(&sNC, p, p->pOrderBy, "ORDER") ){
+ if( isCompound<=nCompound /* Defer right-most ORDER BY of a compound */
+ && resolveOrderGroupBy(&sNC, p, p->pOrderBy, "ORDER")
+ ){
return WRC_Abort;
}
if( db->mallocFailed ){
@@ -78117,7 +82695,7 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames(
NameContext *pNC, /* Namespace to resolve expressions in. */
Expr *pExpr /* The expression to be analyzed. */
){
- u8 savedHasAgg;
+ u16 savedHasAgg;
Walker w;
if( pExpr==0 ) return 0;
@@ -78130,8 +82708,8 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames(
pParse->nHeight += pExpr->nHeight;
}
#endif
- savedHasAgg = pNC->ncFlags & NC_HasAgg;
- pNC->ncFlags &= ~NC_HasAgg;
+ savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg);
+ pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg);
memset(&w, 0, sizeof(w));
w.xExprCallback = resolveExprStep;
w.xSelectCallback = resolveSelectStep;
@@ -78146,9 +82724,8 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames(
}
if( pNC->ncFlags & NC_HasAgg ){
ExprSetProperty(pExpr, EP_Agg);
- }else if( savedHasAgg ){
- pNC->ncFlags |= NC_HasAgg;
}
+ pNC->ncFlags |= savedHasAgg;
return ExprHasProperty(pExpr, EP_Error);
}
@@ -78248,7 +82825,7 @@ SQLITE_PRIVATE void sqlite3ResolveSelfReference(
** affinity of that column is returned. Otherwise, 0x00 is returned,
** indicating no affinity for the expression.
**
-** i.e. the WHERE clause expresssions in the following statements all
+** i.e. the WHERE clause expressions in the following statements all
** have an affinity:
**
** CREATE TABLE t1(a);
@@ -78295,10 +82872,11 @@ SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr){
SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(
Parse *pParse, /* Parsing context */
Expr *pExpr, /* Add the "COLLATE" clause to this expression */
- const Token *pCollName /* Name of collating sequence */
+ const Token *pCollName, /* Name of collating sequence */
+ int dequote /* True to dequote pCollName */
){
if( pCollName->n>0 ){
- Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, 1);
+ Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, dequote);
if( pNew ){
pNew->pLeft = pExpr;
pNew->flags |= EP_Collate|EP_Skip;
@@ -78312,7 +82890,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse *pParse, Expr *pExpr, con
assert( zC!=0 );
s.z = zC;
s.n = sqlite3Strlen30(s.z);
- return sqlite3ExprAddCollateToken(pParse, pExpr, &s);
+ return sqlite3ExprAddCollateToken(pParse, pExpr, &s, 0);
}
/*
@@ -78358,9 +82936,9 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken);
break;
}
- if( p->pTab!=0
- && (op==TK_AGG_COLUMN || op==TK_COLUMN
+ if( (op==TK_AGG_COLUMN || op==TK_COLUMN
|| op==TK_REGISTER || op==TK_TRIGGER)
+ && p->pTab!=0
){
/* op==TK_REGISTER && p->pTab!=0 happens when pExpr was originally
** a TK_COLUMN but was previously evaluated and cached in a register */
@@ -78372,10 +82950,25 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
break;
}
if( p->flags & EP_Collate ){
- if( ALWAYS(p->pLeft) && (p->pLeft->flags & EP_Collate)!=0 ){
+ if( p->pLeft && (p->pLeft->flags & EP_Collate)!=0 ){
p = p->pLeft;
}else{
- p = p->pRight;
+ Expr *pNext = p->pRight;
+ /* The Expr.x union is never used at the same time as Expr.pRight */
+ assert( p->x.pList==0 || p->pRight==0 );
+ /* p->flags holds EP_Collate and p->pLeft->flags does not. And
+ ** p->x.pSelect cannot. So if p->x.pLeft exists, it must hold at
+ ** least one EP_Collate. Thus the following two ALWAYS. */
+ if( p->x.pList!=0 && ALWAYS(!ExprHasProperty(p, EP_xIsSelect)) ){
+ int i;
+ for(i=0; ALWAYS(i<p->x.pList->nExpr); i++){
+ if( ExprHasProperty(p->x.pList->a[i].pExpr, EP_Collate) ){
+ pNext = p->x.pList->a[i].pExpr;
+ break;
+ }
+ }
+ }
+ p = pNext;
}
}else{
break;
@@ -78581,6 +83174,9 @@ static void heightOfSelect(Select *p, int *pnHeight){
** Expr.pSelect member has a height of 1. Any other expression
** has a height equal to the maximum height of any other
** referenced Expr plus one.
+**
+** Also propagate EP_Propagate flags up from Expr.x.pList to Expr.flags,
+** if appropriate.
*/
static void exprSetHeight(Expr *p){
int nHeight = 0;
@@ -78588,8 +83184,9 @@ static void exprSetHeight(Expr *p){
heightOfExpr(p->pRight, &nHeight);
if( ExprHasProperty(p, EP_xIsSelect) ){
heightOfSelect(p->x.pSelect, &nHeight);
- }else{
+ }else if( p->x.pList ){
heightOfExprList(p->x.pList, &nHeight);
+ p->flags |= EP_Propagate & sqlite3ExprListFlags(p->x.pList);
}
p->nHeight = nHeight + 1;
}
@@ -78598,8 +83195,12 @@ static void exprSetHeight(Expr *p){
** Set the Expr.nHeight variable using the exprSetHeight() function. If
** the height is greater than the maximum allowed expression depth,
** leave an error in pParse.
+**
+** Also propagate all EP_Propagate flags from the Expr.x.pList into
+** Expr.flags.
*/
-SQLITE_PRIVATE void sqlite3ExprSetHeight(Parse *pParse, Expr *p){
+SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){
+ if( pParse->nErr ) return;
exprSetHeight(p);
sqlite3ExprCheckHeight(pParse, p->nHeight);
}
@@ -78613,8 +83214,17 @@ SQLITE_PRIVATE int sqlite3SelectExprHeight(Select *p){
heightOfSelect(p, &nHeight);
return nHeight;
}
-#else
- #define exprSetHeight(y)
+#else /* ABOVE: Height enforcement enabled. BELOW: Height enforcement off */
+/*
+** Propagate all EP_Propagate flags from the Expr.x.pList into
+** Expr.flags.
+*/
+SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){
+ if( p && p->x.pList && !ExprHasProperty(p, EP_xIsSelect) ){
+ p->flags |= EP_Propagate & sqlite3ExprListFlags(p->x.pList);
+ }
+}
+#define exprSetHeight(y)
#endif /* SQLITE_MAX_EXPR_DEPTH>0 */
/*
@@ -78716,18 +83326,18 @@ SQLITE_PRIVATE void sqlite3ExprAttachSubtrees(
}else{
if( pRight ){
pRoot->pRight = pRight;
- pRoot->flags |= EP_Collate & pRight->flags;
+ pRoot->flags |= EP_Propagate & pRight->flags;
}
if( pLeft ){
pRoot->pLeft = pLeft;
- pRoot->flags |= EP_Collate & pLeft->flags;
+ pRoot->flags |= EP_Propagate & pLeft->flags;
}
exprSetHeight(pRoot);
}
}
/*
-** Allocate a Expr node which joins as many as two subtrees.
+** Allocate an Expr node which joins as many as two subtrees.
**
** One or both of the subtrees can be NULL. Return a pointer to the new
** Expr node. Or, if an OOM error occurs, set pParse->db->mallocFailed,
@@ -78741,7 +83351,7 @@ SQLITE_PRIVATE Expr *sqlite3PExpr(
const Token *pToken /* Argument token */
){
Expr *p;
- if( op==TK_AND && pLeft && pRight ){
+ if( op==TK_AND && pLeft && pRight && pParse->nErr==0 ){
/* Take advantage of short-circuit false optimization for AND */
p = sqlite3ExprAnd(pParse->db, pLeft, pRight);
}else{
@@ -78820,7 +83430,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *
}
pNew->x.pList = pList;
assert( !ExprHasProperty(pNew, EP_xIsSelect) );
- sqlite3ExprSetHeight(pParse, pNew);
+ sqlite3ExprSetHeightAndFlags(pParse, pNew);
return pNew;
}
@@ -78837,7 +83447,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *
**
** Wildcards of the form ":aaa", "@aaa", or "$aaa" are assigned the same number
** as the previous instance of the same wildcard. Or if this is the first
-** instance of the wildcard, the next sequenial variable number is
+** instance of the wildcard, the next sequential variable number is
** assigned.
*/
SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
@@ -78972,7 +83582,7 @@ static int exprStructSize(Expr *p){
** During expression analysis, extra information is computed and moved into
** later parts of teh Expr object and that extra information might get chopped
** off if the expression is reduced. Note also that it does not work to
-** make a EXPRDUP_REDUCE copy of a reduced expression. It is only legal
+** make an EXPRDUP_REDUCE copy of a reduced expression. It is only legal
** to reduce a pristine expression tree from the parser. The implementation
** of dupedExprStructSize() contain multiple assert() statements that attempt
** to enforce this constraint.
@@ -79041,7 +83651,7 @@ static int dupedExprSize(Expr *p, int flags){
** is not NULL then *pzBuffer is assumed to point to a buffer large enough
** to store the copy of expression p, the copies of p->u.zToken
** (if applicable), and the copies of the p->pLeft and p->pRight expressions,
-** if any. Before returning, *pzBuffer is set to the first byte passed the
+** if any. Before returning, *pzBuffer is set to the first byte past the
** portion of the buffer copied into by this function.
*/
static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){
@@ -79295,6 +83905,7 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
pNew->addrOpenEphm[1] = -1;
pNew->nSelectRow = p->nSelectRow;
pNew->pWith = withDup(db, p->pWith);
+ sqlite3SelectSetName(pNew, p->zSelName);
return pNew;
}
#else
@@ -79435,37 +84046,67 @@ SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
}
/*
-** These routines are Walker callbacks. Walker.u.pi is a pointer
-** to an integer. These routines are checking an expression to see
-** if it is a constant. Set *Walker.u.pi to 0 if the expression is
-** not constant.
+** Return the bitwise-OR of all Expr.flags fields in the given
+** ExprList.
+*/
+SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList *pList){
+ int i;
+ u32 m = 0;
+ if( pList ){
+ for(i=0; i<pList->nExpr; i++){
+ Expr *pExpr = pList->a[i].pExpr;
+ if( ALWAYS(pExpr) ) m |= pExpr->flags;
+ }
+ }
+ return m;
+}
+
+/*
+** These routines are Walker callbacks used to check expressions to
+** see if they are "constant" for some definition of constant. The
+** Walker.eCode value determines the type of "constant" we are looking
+** for.
**
** These callback routines are used to implement the following:
**
-** sqlite3ExprIsConstant()
-** sqlite3ExprIsConstantNotJoin()
-** sqlite3ExprIsConstantOrFunction()
+** sqlite3ExprIsConstant() pWalker->eCode==1
+** sqlite3ExprIsConstantNotJoin() pWalker->eCode==2
+** sqlite3ExprRefOneTableOnly() pWalker->eCode==3
+** sqlite3ExprIsConstantOrFunction() pWalker->eCode==4 or 5
**
+** In all cases, the callbacks set Walker.eCode=0 and abort if the expression
+** is found to not be a constant.
+**
+** The sqlite3ExprIsConstantOrFunction() is used for evaluating expressions
+** in a CREATE TABLE statement. The Walker.eCode value is 5 when parsing
+** an existing schema and 4 when processing a new statement. A bound
+** parameter raises an error for new statements, but is silently converted
+** to NULL for existing schemas. This allows sqlite_master tables that
+** contain a bound parameter because they were generated by older versions
+** of SQLite to be parsed by newer versions of SQLite without raising a
+** malformed schema error.
*/
static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
- /* If pWalker->u.i is 3 then any term of the expression that comes from
- ** the ON or USING clauses of a join disqualifies the expression
+ /* If pWalker->eCode is 2 then any term of the expression that comes from
+ ** the ON or USING clauses of a left join disqualifies the expression
** from being considered constant. */
- if( pWalker->u.i==3 && ExprHasProperty(pExpr, EP_FromJoin) ){
- pWalker->u.i = 0;
+ if( pWalker->eCode==2 && ExprHasProperty(pExpr, EP_FromJoin) ){
+ pWalker->eCode = 0;
return WRC_Abort;
}
switch( pExpr->op ){
/* Consider functions to be constant if all their arguments are constant
- ** and either pWalker->u.i==2 or the function as the SQLITE_FUNC_CONST
- ** flag. */
+ ** and either pWalker->eCode==4 or 5 or the function has the
+ ** SQLITE_FUNC_CONST flag. */
case TK_FUNCTION:
- if( pWalker->u.i==2 || ExprHasProperty(pExpr,EP_Constant) ){
+ if( pWalker->eCode>=4 || ExprHasProperty(pExpr,EP_ConstFunc) ){
return WRC_Continue;
+ }else{
+ pWalker->eCode = 0;
+ return WRC_Abort;
}
- /* Fall through */
case TK_ID:
case TK_COLUMN:
case TK_AGG_FUNCTION:
@@ -79474,8 +84115,25 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
testcase( pExpr->op==TK_COLUMN );
testcase( pExpr->op==TK_AGG_FUNCTION );
testcase( pExpr->op==TK_AGG_COLUMN );
- pWalker->u.i = 0;
- return WRC_Abort;
+ if( pWalker->eCode==3 && pExpr->iTable==pWalker->u.iCur ){
+ return WRC_Continue;
+ }else{
+ pWalker->eCode = 0;
+ return WRC_Abort;
+ }
+ case TK_VARIABLE:
+ if( pWalker->eCode==5 ){
+ /* Silently convert bound parameters that appear inside of CREATE
+ ** statements into a NULL when parsing the CREATE statement text out
+ ** of the sqlite_master table */
+ pExpr->op = TK_NULL;
+ }else if( pWalker->eCode==4 ){
+ /* A bound parameter in a CREATE statement that originates from
+ ** sqlite3_prepare() causes an error */
+ pWalker->eCode = 0;
+ return WRC_Abort;
+ }
+ /* Fall through */
default:
testcase( pExpr->op==TK_SELECT ); /* selectNodeIsConstant will disallow */
testcase( pExpr->op==TK_EXISTS ); /* selectNodeIsConstant will disallow */
@@ -79484,21 +84142,22 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
}
static int selectNodeIsConstant(Walker *pWalker, Select *NotUsed){
UNUSED_PARAMETER(NotUsed);
- pWalker->u.i = 0;
+ pWalker->eCode = 0;
return WRC_Abort;
}
-static int exprIsConst(Expr *p, int initFlag){
+static int exprIsConst(Expr *p, int initFlag, int iCur){
Walker w;
memset(&w, 0, sizeof(w));
- w.u.i = initFlag;
+ w.eCode = initFlag;
w.xExprCallback = exprNodeIsConstant;
w.xSelectCallback = selectNodeIsConstant;
+ w.u.iCur = iCur;
sqlite3WalkExpr(&w, p);
- return w.u.i;
+ return w.eCode;
}
/*
-** Walk an expression tree. Return 1 if the expression is constant
+** Walk an expression tree. Return non-zero if the expression is constant
** and 0 if it involves variables or function calls.
**
** For the purposes of this function, a double-quoted string (ex: "abc")
@@ -79506,21 +84165,31 @@ static int exprIsConst(Expr *p, int initFlag){
** a constant.
*/
SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr *p){
- return exprIsConst(p, 1);
+ return exprIsConst(p, 1, 0);
}
/*
-** Walk an expression tree. Return 1 if the expression is constant
+** Walk an expression tree. Return non-zero if the expression is constant
** that does no originate from the ON or USING clauses of a join.
** Return 0 if it involves variables or function calls or terms from
** an ON or USING clause.
*/
SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr *p){
- return exprIsConst(p, 3);
+ return exprIsConst(p, 2, 0);
+}
+
+/*
+** Walk an expression tree. Return non-zero if the expression constant
+** for any single row of the table with cursor iCur. In other words, the
+** expression must not refer to any non-deterministic function nor any
+** table other than iCur.
+*/
+SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr *p, int iCur){
+ return exprIsConst(p, 3, iCur);
}
/*
-** Walk an expression tree. Return 1 if the expression is constant
+** Walk an expression tree. Return non-zero if the expression is constant
** or a function call with constant arguments. Return and 0 if there
** are any variables.
**
@@ -79528,8 +84197,9 @@ SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr *p){
** is considered a variable but a single-quoted string (ex: 'abc') is
** a constant.
*/
-SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr *p){
- return exprIsConst(p, 2);
+SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr *p, u8 isInit){
+ assert( isInit==0 || isInit==1 );
+ return exprIsConst(p, 4+isInit, 0);
}
/*
@@ -79596,7 +84266,8 @@ SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr *p){
return 0;
case TK_COLUMN:
assert( p->pTab!=0 );
- return p->iColumn>=0 && p->pTab->aCol[p->iColumn].notNull==0;
+ return ExprHasProperty(p, EP_CanBeNull) ||
+ (p->iColumn>=0 && p->pTab->aCol[p->iColumn].notNull==0);
default:
return 1;
}
@@ -79767,7 +84438,7 @@ static int sqlite3InRhsIsConstant(Expr *pIn){
**
** If the RHS of the IN operator is a list or a more complex subquery, then
** an ephemeral table might need to be generated from the RHS and then
-** pX->iTable made to point to the ephermeral table instead of an
+** pX->iTable made to point to the ephemeral table instead of an
** existing table.
**
** The inFlags parameter must contain exactly one of the bits
@@ -79824,7 +84495,7 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int
** ephemeral table.
*/
p = (ExprHasProperty(pX, EP_xIsSelect) ? pX->x.pSelect : 0);
- if( ALWAYS(pParse->nErr==0) && isCandidateForInOpt(p) ){
+ if( pParse->nErr==0 && isCandidateForInOpt(p) ){
sqlite3 *db = pParse->db; /* Database connection */
Table *pTab; /* Table <table>. */
Expr *pExpr; /* Expression <column> */
@@ -79897,7 +84568,7 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int
** and IN_INDEX_NOOP is an allowed reply
** and the RHS of the IN operator is a list, not a subquery
** and the RHS is not contant or has two or fewer terms,
- ** then it is not worth creating an ephermeral table to evaluate
+ ** then it is not worth creating an ephemeral table to evaluate
** the IN operator so return IN_INDEX_NOOP.
*/
if( eType==0
@@ -80039,7 +84710,6 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
pSelect->iLimit = 0;
testcase( pSelect->selFlags & SF_Distinct );
- pSelect->selFlags &= ~SF_Distinct;
testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */
if( sqlite3Select(pParse, pSelect, &dest) ){
sqlite3KeyInfoUnref(pKeyInfo);
@@ -80138,6 +84808,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
sqlite3SelectDestInit(&dest, 0, ++pParse->nMem);
if( pExpr->op==TK_SELECT ){
dest.eDest = SRT_Mem;
+ dest.iSdst = dest.iSDParm;
sqlite3VdbeAddOp2(v, OP_Null, 0, dest.iSDParm);
VdbeComment((v, "Init subquery result"));
}else{
@@ -80149,6 +84820,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0,
&sqlite3IntTokens[1]);
pSel->iLimit = 0;
+ pSel->selFlags &= ~SF_MultiValue;
if( sqlite3Select(pParse, pSel, &dest) ){
return 0;
}
@@ -80437,7 +85109,8 @@ SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int
int idxLru;
struct yColCache *p;
- assert( iReg>0 ); /* Register numbers are always positive */
+ /* Unless an error has occurred, register numbers are always positive. */
+ assert( iReg>0 || pParse->nErr || pParse->db->mallocFailed );
assert( iCol>=-1 && iCol<32768 ); /* Finite column numbers */
/* The SQLITE_ColumnCache flag disables the column cache. This is used
@@ -80657,16 +85330,9 @@ SQLITE_PRIVATE void sqlite3ExprCacheAffinityChange(Parse *pParse, int iStart, in
** over to iTo..iTo+nReg-1. Keep the column cache up-to-date.
*/
SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){
- int i;
- struct yColCache *p;
assert( iFrom>=iTo+nReg || iFrom+nReg<=iTo );
sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg);
- for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
- int x = p->iReg;
- if( x>=iFrom && x<iFrom+nReg ){
- p->iReg += iTo-iFrom;
- }
- }
+ sqlite3ExprCacheRemove(pParse, iFrom, nReg);
}
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
@@ -80821,26 +85487,13 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
#ifndef SQLITE_OMIT_CAST
case TK_CAST: {
/* Expressions of the form: CAST(pLeft AS token) */
- int aff, to_op;
inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
- assert( !ExprHasProperty(pExpr, EP_IntValue) );
- aff = sqlite3AffinityType(pExpr->u.zToken, 0);
- to_op = aff - SQLITE_AFF_TEXT + OP_ToText;
- assert( to_op==OP_ToText || aff!=SQLITE_AFF_TEXT );
- assert( to_op==OP_ToBlob || aff!=SQLITE_AFF_NONE );
- assert( to_op==OP_ToNumeric || aff!=SQLITE_AFF_NUMERIC );
- assert( to_op==OP_ToInt || aff!=SQLITE_AFF_INTEGER );
- assert( to_op==OP_ToReal || aff!=SQLITE_AFF_REAL );
- testcase( to_op==OP_ToText );
- testcase( to_op==OP_ToBlob );
- testcase( to_op==OP_ToNumeric );
- testcase( to_op==OP_ToInt );
- testcase( to_op==OP_ToReal );
if( inReg!=target ){
sqlite3VdbeAddOp2(v, OP_SCopy, inReg, target);
inReg = target;
}
- sqlite3VdbeAddOp1(v, to_op, inReg);
+ sqlite3VdbeAddOp2(v, OP_Cast, target,
+ sqlite3AffinityType(pExpr->u.zToken, 0));
testcase( usedAsColumnCache(pParse, inReg, inReg) );
sqlite3ExprCacheAffinityChange(pParse, inReg, 1);
break;
@@ -80996,7 +85649,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
}
/* Attempt a direct implementation of the built-in COALESCE() and
- ** IFNULL() functions. This avoids unnecessary evalation of
+ ** IFNULL() functions. This avoids unnecessary evaluation of
** arguments past the first non-NULL argument.
*/
if( pDef->funcFlags & SQLITE_FUNC_COALESCE ){
@@ -81205,7 +85858,10 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
#ifndef SQLITE_OMIT_FLOATING_POINT
/* If the column has REAL affinity, it may currently be stored as an
- ** integer. Use OP_RealAffinity to make sure it is really real. */
+ ** integer. Use OP_RealAffinity to make sure it is really real.
+ **
+ ** EVIDENCE-OF: R-60985-57662 SQLite will convert the value back to
+ ** floating point when extracting it from the record. */
if( pExpr->iColumn>=0
&& pTab->aCol[pExpr->iColumn].affinity==SQLITE_AFF_REAL
){
@@ -81435,7 +86091,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int ta
}
/*
-** Generate code that evalutes the given expression and puts the result
+** Generate code that evaluates the given expression and puts the result
** in register target.
**
** Also make a copy of the expression results into another "cache" register
@@ -81458,90 +86114,86 @@ SQLITE_PRIVATE void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int targ
exprToRegister(pExpr, iMem);
}
-#if defined(SQLITE_ENABLE_TREE_EXPLAIN)
+#ifdef SQLITE_DEBUG
/*
** Generate a human-readable explanation of an expression tree.
*/
-SQLITE_PRIVATE void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){
- int op; /* The opcode being coded */
+SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
const char *zBinOp = 0; /* Binary operator */
const char *zUniOp = 0; /* Unary operator */
+ pView = sqlite3TreeViewPush(pView, moreToFollow);
if( pExpr==0 ){
- op = TK_NULL;
- }else{
- op = pExpr->op;
+ sqlite3TreeViewLine(pView, "nil");
+ sqlite3TreeViewPop(pView);
+ return;
}
- switch( op ){
+ switch( pExpr->op ){
case TK_AGG_COLUMN: {
- sqlite3ExplainPrintf(pOut, "AGG{%d:%d}",
+ sqlite3TreeViewLine(pView, "AGG{%d:%d}",
pExpr->iTable, pExpr->iColumn);
break;
}
case TK_COLUMN: {
if( pExpr->iTable<0 ){
/* This only happens when coding check constraints */
- sqlite3ExplainPrintf(pOut, "COLUMN(%d)", pExpr->iColumn);
+ sqlite3TreeViewLine(pView, "COLUMN(%d)", pExpr->iColumn);
}else{
- sqlite3ExplainPrintf(pOut, "{%d:%d}",
+ sqlite3TreeViewLine(pView, "{%d:%d}",
pExpr->iTable, pExpr->iColumn);
}
break;
}
case TK_INTEGER: {
if( pExpr->flags & EP_IntValue ){
- sqlite3ExplainPrintf(pOut, "%d", pExpr->u.iValue);
+ sqlite3TreeViewLine(pView, "%d", pExpr->u.iValue);
}else{
- sqlite3ExplainPrintf(pOut, "%s", pExpr->u.zToken);
+ sqlite3TreeViewLine(pView, "%s", pExpr->u.zToken);
}
break;
}
#ifndef SQLITE_OMIT_FLOATING_POINT
case TK_FLOAT: {
- sqlite3ExplainPrintf(pOut,"%s", pExpr->u.zToken);
+ sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken);
break;
}
#endif
case TK_STRING: {
- sqlite3ExplainPrintf(pOut,"%Q", pExpr->u.zToken);
+ sqlite3TreeViewLine(pView,"%Q", pExpr->u.zToken);
break;
}
case TK_NULL: {
- sqlite3ExplainPrintf(pOut,"NULL");
+ sqlite3TreeViewLine(pView,"NULL");
break;
}
#ifndef SQLITE_OMIT_BLOB_LITERAL
case TK_BLOB: {
- sqlite3ExplainPrintf(pOut,"%s", pExpr->u.zToken);
+ sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken);
break;
}
#endif
case TK_VARIABLE: {
- sqlite3ExplainPrintf(pOut,"VARIABLE(%s,%d)",
- pExpr->u.zToken, pExpr->iColumn);
+ sqlite3TreeViewLine(pView,"VARIABLE(%s,%d)",
+ pExpr->u.zToken, pExpr->iColumn);
break;
}
case TK_REGISTER: {
- sqlite3ExplainPrintf(pOut,"REGISTER(%d)", pExpr->iTable);
+ sqlite3TreeViewLine(pView,"REGISTER(%d)", pExpr->iTable);
break;
}
case TK_AS: {
- sqlite3ExplainExpr(pOut, pExpr->pLeft);
+ sqlite3TreeViewLine(pView,"AS %Q", pExpr->u.zToken);
+ sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
+ break;
+ }
+ case TK_ID: {
+ sqlite3TreeViewLine(pView,"ID \"%w\"", pExpr->u.zToken);
break;
}
#ifndef SQLITE_OMIT_CAST
case TK_CAST: {
/* Expressions of the form: CAST(pLeft AS token) */
- const char *zAff = "unk";
- switch( sqlite3AffinityType(pExpr->u.zToken, 0) ){
- case SQLITE_AFF_TEXT: zAff = "TEXT"; break;
- case SQLITE_AFF_NONE: zAff = "NONE"; break;
- case SQLITE_AFF_NUMERIC: zAff = "NUMERIC"; break;
- case SQLITE_AFF_INTEGER: zAff = "INTEGER"; break;
- case SQLITE_AFF_REAL: zAff = "REAL"; break;
- }
- sqlite3ExplainPrintf(pOut, "CAST-%s(", zAff);
- sqlite3ExplainExpr(pOut, pExpr->pLeft);
- sqlite3ExplainPrintf(pOut, ")");
+ sqlite3TreeViewLine(pView,"CAST %Q", pExpr->u.zToken);
+ sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
break;
}
#endif /* SQLITE_OMIT_CAST */
@@ -81565,6 +86217,7 @@ SQLITE_PRIVATE void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){
case TK_LSHIFT: zBinOp = "LSHIFT"; break;
case TK_RSHIFT: zBinOp = "RSHIFT"; break;
case TK_CONCAT: zBinOp = "CONCAT"; break;
+ case TK_DOT: zBinOp = "DOT"; break;
case TK_UMINUS: zUniOp = "UMINUS"; break;
case TK_UPLUS: zUniOp = "UPLUS"; break;
@@ -81574,8 +86227,8 @@ SQLITE_PRIVATE void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){
case TK_NOTNULL: zUniOp = "NOTNULL"; break;
case TK_COLLATE: {
- sqlite3ExplainExpr(pOut, pExpr->pLeft);
- sqlite3ExplainPrintf(pOut,".COLLATE(%s)",pExpr->u.zToken);
+ sqlite3TreeViewLine(pView, "COLLATE %Q", pExpr->u.zToken);
+ sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
break;
}
@@ -81587,41 +86240,36 @@ SQLITE_PRIVATE void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){
}else{
pFarg = pExpr->x.pList;
}
- if( op==TK_AGG_FUNCTION ){
- sqlite3ExplainPrintf(pOut, "AGG_FUNCTION%d:%s(",
+ if( pExpr->op==TK_AGG_FUNCTION ){
+ sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q",
pExpr->op2, pExpr->u.zToken);
}else{
- sqlite3ExplainPrintf(pOut, "FUNCTION:%s(", pExpr->u.zToken);
+ sqlite3TreeViewLine(pView, "FUNCTION %Q", pExpr->u.zToken);
}
if( pFarg ){
- sqlite3ExplainExprList(pOut, pFarg);
+ sqlite3TreeViewExprList(pView, pFarg, 0, 0);
}
- sqlite3ExplainPrintf(pOut, ")");
break;
}
#ifndef SQLITE_OMIT_SUBQUERY
case TK_EXISTS: {
- sqlite3ExplainPrintf(pOut, "EXISTS(");
- sqlite3ExplainSelect(pOut, pExpr->x.pSelect);
- sqlite3ExplainPrintf(pOut,")");
+ sqlite3TreeViewLine(pView, "EXISTS-expr");
+ sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
break;
}
case TK_SELECT: {
- sqlite3ExplainPrintf(pOut, "(");
- sqlite3ExplainSelect(pOut, pExpr->x.pSelect);
- sqlite3ExplainPrintf(pOut, ")");
+ sqlite3TreeViewLine(pView, "SELECT-expr");
+ sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
break;
}
case TK_IN: {
- sqlite3ExplainPrintf(pOut, "IN(");
- sqlite3ExplainExpr(pOut, pExpr->pLeft);
- sqlite3ExplainPrintf(pOut, ",");
+ sqlite3TreeViewLine(pView, "IN");
+ sqlite3TreeViewExpr(pView, pExpr->pLeft, 1);
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
- sqlite3ExplainSelect(pOut, pExpr->x.pSelect);
+ sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
}else{
- sqlite3ExplainExprList(pOut, pExpr->x.pList);
+ sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0);
}
- sqlite3ExplainPrintf(pOut, ")");
break;
}
#endif /* SQLITE_OMIT_SUBQUERY */
@@ -81641,13 +86289,10 @@ SQLITE_PRIVATE void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){
Expr *pX = pExpr->pLeft;
Expr *pY = pExpr->x.pList->a[0].pExpr;
Expr *pZ = pExpr->x.pList->a[1].pExpr;
- sqlite3ExplainPrintf(pOut, "BETWEEN(");
- sqlite3ExplainExpr(pOut, pX);
- sqlite3ExplainPrintf(pOut, ",");
- sqlite3ExplainExpr(pOut, pY);
- sqlite3ExplainPrintf(pOut, ",");
- sqlite3ExplainExpr(pOut, pZ);
- sqlite3ExplainPrintf(pOut, ")");
+ sqlite3TreeViewLine(pView, "BETWEEN");
+ sqlite3TreeViewExpr(pView, pX, 1);
+ sqlite3TreeViewExpr(pView, pY, 1);
+ sqlite3TreeViewExpr(pView, pZ, 0);
break;
}
case TK_TRIGGER: {
@@ -81658,15 +86303,14 @@ SQLITE_PRIVATE void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){
** is set to the column of the pseudo-table to read, or to -1 to
** read the rowid field.
*/
- sqlite3ExplainPrintf(pOut, "%s(%d)",
+ sqlite3TreeViewLine(pView, "%s(%d)",
pExpr->iTable ? "NEW" : "OLD", pExpr->iColumn);
break;
}
case TK_CASE: {
- sqlite3ExplainPrintf(pOut, "CASE(");
- sqlite3ExplainExpr(pOut, pExpr->pLeft);
- sqlite3ExplainPrintf(pOut, ",");
- sqlite3ExplainExprList(pOut, pExpr->x.pList);
+ sqlite3TreeViewLine(pView, "CASE");
+ sqlite3TreeViewExpr(pView, pExpr->pLeft, 1);
+ sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0);
break;
}
#ifndef SQLITE_OMIT_TRIGGER
@@ -81678,55 +86322,57 @@ SQLITE_PRIVATE void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){
case OE_Fail: zType = "fail"; break;
case OE_Ignore: zType = "ignore"; break;
}
- sqlite3ExplainPrintf(pOut, "RAISE-%s(%s)", zType, pExpr->u.zToken);
+ sqlite3TreeViewLine(pView, "RAISE %s(%Q)", zType, pExpr->u.zToken);
break;
}
#endif
+ default: {
+ sqlite3TreeViewLine(pView, "op=%d", pExpr->op);
+ break;
+ }
}
if( zBinOp ){
- sqlite3ExplainPrintf(pOut,"%s(", zBinOp);
- sqlite3ExplainExpr(pOut, pExpr->pLeft);
- sqlite3ExplainPrintf(pOut,",");
- sqlite3ExplainExpr(pOut, pExpr->pRight);
- sqlite3ExplainPrintf(pOut,")");
+ sqlite3TreeViewLine(pView, "%s", zBinOp);
+ sqlite3TreeViewExpr(pView, pExpr->pLeft, 1);
+ sqlite3TreeViewExpr(pView, pExpr->pRight, 0);
}else if( zUniOp ){
- sqlite3ExplainPrintf(pOut,"%s(", zUniOp);
- sqlite3ExplainExpr(pOut, pExpr->pLeft);
- sqlite3ExplainPrintf(pOut,")");
+ sqlite3TreeViewLine(pView, "%s", zUniOp);
+ sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
}
+ sqlite3TreeViewPop(pView);
}
-#endif /* defined(SQLITE_ENABLE_TREE_EXPLAIN) */
+#endif /* SQLITE_DEBUG */
-#if defined(SQLITE_ENABLE_TREE_EXPLAIN)
+#ifdef SQLITE_DEBUG
/*
** Generate a human-readable explanation of an expression list.
*/
-SQLITE_PRIVATE void sqlite3ExplainExprList(Vdbe *pOut, ExprList *pList){
+SQLITE_PRIVATE void sqlite3TreeViewExprList(
+ TreeView *pView,
+ const ExprList *pList,
+ u8 moreToFollow,
+ const char *zLabel
+){
int i;
- if( pList==0 || pList->nExpr==0 ){
- sqlite3ExplainPrintf(pOut, "(empty-list)");
- return;
- }else if( pList->nExpr==1 ){
- sqlite3ExplainExpr(pOut, pList->a[0].pExpr);
+ pView = sqlite3TreeViewPush(pView, moreToFollow);
+ if( zLabel==0 || zLabel[0]==0 ) zLabel = "LIST";
+ if( pList==0 ){
+ sqlite3TreeViewLine(pView, "%s (empty)", zLabel);
}else{
- sqlite3ExplainPush(pOut);
+ sqlite3TreeViewLine(pView, "%s", zLabel);
for(i=0; i<pList->nExpr; i++){
- sqlite3ExplainPrintf(pOut, "item[%d] = ", i);
- sqlite3ExplainPush(pOut);
- sqlite3ExplainExpr(pOut, pList->a[i].pExpr);
- sqlite3ExplainPop(pOut);
- if( pList->a[i].zName ){
+ sqlite3TreeViewExpr(pView, pList->a[i].pExpr, i<pList->nExpr-1);
+#if 0
+ if( pList->a[i].zName ){
sqlite3ExplainPrintf(pOut, " AS %s", pList->a[i].zName);
}
if( pList->a[i].bSpanIsTab ){
sqlite3ExplainPrintf(pOut, " (%s)", pList->a[i].zSpan);
}
- if( i<pList->nExpr-1 ){
- sqlite3ExplainNL(pOut);
- }
+#endif
}
- sqlite3ExplainPop(pOut);
}
+ sqlite3TreeViewPop(pView);
}
#endif /* SQLITE_DEBUG */
@@ -81790,7 +86436,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList(
** x>=y AND x<=z
**
** Code it as such, taking care to do the common subexpression
-** elementation of x.
+** elimination of x.
*/
static void exprCodeBetween(
Parse *pParse, /* Parsing and code generating context */
@@ -82175,7 +86821,7 @@ SQLITE_PRIVATE int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){
if( sqlite3ExprCompare(pA->pLeft, pB->pLeft, iTab) ) return 2;
if( sqlite3ExprCompare(pA->pRight, pB->pRight, iTab) ) return 2;
if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2;
- if( ALWAYS((combinedFlags & EP_Reduced)==0) ){
+ if( ALWAYS((combinedFlags & EP_Reduced)==0) && pA->op!=TK_STRING ){
if( pA->iColumn!=pB->iColumn ) return 2;
if( pA->iTable!=pB->iTable
&& (pA->iTable!=iTab || NEVER(pB->iTable>=0)) ) return 2;
@@ -82277,10 +86923,11 @@ static int exprSrcCount(Walker *pWalker, Expr *pExpr){
int i;
struct SrcCount *p = pWalker->u.pSrcCount;
SrcList *pSrc = p->pSrc;
- for(i=0; i<pSrc->nSrc; i++){
+ int nSrc = pSrc ? pSrc->nSrc : 0;
+ for(i=0; i<nSrc; i++){
if( pExpr->iTable==pSrc->a[i].iCursor ) break;
}
- if( i<pSrc->nSrc ){
+ if( i<nSrc ){
p->nThis++;
}else{
p->nOther++;
@@ -82527,7 +87174,7 @@ SQLITE_PRIVATE int sqlite3GetTempReg(Parse *pParse){
** purpose.
**
** If a register is currently being used by the column cache, then
-** the dallocation is deferred until the column cache line that uses
+** the deallocation is deferred until the column cache line that uses
** the register becomes stale.
*/
SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse *pParse, int iReg){
@@ -82706,6 +87353,7 @@ static void renameParentFunc(
n = sqlite3GetToken(z, &token);
}while( token==TK_SPACE );
+ if( token==TK_ILLEGAL ) break;
zParent = sqlite3DbStrNDup(db, (const char *)z, n);
if( zParent==0 ) break;
sqlite3Dequote(zParent);
@@ -82754,8 +87402,8 @@ static void renameTriggerFunc(
UNUSED_PARAMETER(NotUsed);
/* The principle used to locate the table name in the CREATE TRIGGER
- ** statement is that the table name is the first token that is immediatedly
- ** preceded by either TK_ON or TK_DOT and immediatedly followed by one
+ ** statement is that the table name is the first token that is immediately
+ ** preceded by either TK_ON or TK_DOT and immediately followed by one
** of TK_WHEN, TK_BEGIN or TK_FOR.
*/
if( zSql ){
@@ -83270,7 +87918,10 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
*/
if( pDflt ){
sqlite3_value *pVal = 0;
- if( sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_NONE, &pVal) ){
+ int rc;
+ rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_NONE, &pVal);
+ assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
+ if( rc!=SQLITE_OK ){
db->mallocFailed = 1;
return;
}
@@ -83446,7 +88097,7 @@ exit_begin_add_column:
** not possible to enable both STAT3 and STAT4 at the same time. If they
** are both enabled, then STAT4 takes precedence.
**
-** For most applications, sqlite_stat1 provides all the statisics required
+** For most applications, sqlite_stat1 provides all the statistics required
** for the query planner to make good choices.
**
** Format of sqlite_stat1:
@@ -83797,8 +88448,9 @@ static void stat4Destructor(void *pOld){
** original WITHOUT ROWID table as N==K as a special case.
**
** This routine allocates the Stat4Accum object in heap memory. The return
-** value is a pointer to the the Stat4Accum object encoded as a blob (i.e.
-** the size of the blob is sizeof(void*) bytes).
+** value is a pointer to the Stat4Accum object. The datatype of the
+** return value is BLOB, but it is really just a pointer to the Stat4Accum
+** object.
*/
static void statInit(
sqlite3_context *context,
@@ -83857,7 +88509,7 @@ static void statInit(
p->mxSample = mxSample;
p->nPSample = (tRowcnt)(sqlite3_value_int64(argv[2])/(mxSample/3+1) + 1);
p->current.anLt = &p->current.anEq[nColUp];
- p->iPrn = nCol*0x689e962d ^ sqlite3_value_int(argv[2])*0xd0944565;
+ p->iPrn = 0x689e962d*(u32)nCol ^ 0xd0944565*(u32)sqlite3_value_int(argv[2]);
/* Set up the Stat4Accum.a[] and aBest[] arrays */
p->a = (struct Stat4Sample*)&p->current.anLt[nColUp];
@@ -83876,8 +88528,11 @@ static void statInit(
}
#endif
- /* Return a pointer to the allocated object to the caller */
- sqlite3_result_blob(context, p, sizeof(p), stat4Destructor);
+ /* Return a pointer to the allocated object to the caller. Note that
+ ** only the pointer (the 2nd parameter) matters. The size of the object
+ ** (given by the 3rd parameter) is never used and can be any positive
+ ** value. */
+ sqlite3_result_blob(context, p, sizeof(*p), stat4Destructor);
}
static const FuncDef statInitFuncdef = {
2+IsStat34, /* nArg */
@@ -84203,7 +88858,7 @@ static const FuncDef statPushFuncdef = {
** Implementation of the stat_get(P,J) SQL function. This routine is
** used to query statistical information that has been gathered into
** the Stat4Accum object by prior calls to stat_push(). The P parameter
-** is a BLOB which is decoded into a pointer to the Stat4Accum objects.
+** has type BLOB but it is really just a pointer to the Stat4Accum object.
** The content to returned is determined by the parameter J
** which is one of the STAT_GET_xxxx values defined above.
**
@@ -84607,7 +89262,8 @@ static void analyzeOneTable(
/* Add the entry to the stat1 table. */
callStatGet(v, regStat4, STAT_GET_STAT1, regStat1);
- sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "aaa", 0);
+ assert( "BBB"[0]==SQLITE_AFF_TEXT );
+ sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0);
sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid);
sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid);
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
@@ -84670,7 +89326,8 @@ static void analyzeOneTable(
sqlite3VdbeAddOp2(v, OP_Count, iTabCur, regStat1);
jZeroRows = sqlite3VdbeAddOp1(v, OP_IfNot, regStat1); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Null, 0, regIdxname);
- sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "aaa", 0);
+ assert( "BBB"[0]==SQLITE_AFF_TEXT );
+ sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0);
sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid);
sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid);
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
@@ -84841,7 +89498,7 @@ static void decodeIntArray(
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
if( z==0 ) z = "";
#else
- if( NEVER(z==0) ) z = "";
+ assert( z!=0 );
#endif
for(i=0; *z && i<nOut; i++){
v = 0;
@@ -84850,36 +89507,39 @@ static void decodeIntArray(
z++;
}
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
- if( aOut ){
- aOut[i] = v;
- }else
+ if( aOut ) aOut[i] = v;
+ if( aLog ) aLog[i] = sqlite3LogEst(v);
#else
assert( aOut==0 );
UNUSED_PARAMETER(aOut);
+ assert( aLog!=0 );
+ aLog[i] = sqlite3LogEst(v);
#endif
- {
- aLog[i] = sqlite3LogEst(v);
- }
if( *z==' ' ) z++;
}
#ifndef SQLITE_ENABLE_STAT3_OR_STAT4
- assert( pIndex!=0 );
+ assert( pIndex!=0 ); {
#else
- if( pIndex )
+ if( pIndex ){
#endif
- while( z[0] ){
- if( sqlite3_strglob("unordered*", z)==0 ){
- pIndex->bUnordered = 1;
- }else if( sqlite3_strglob("sz=[0-9]*", z)==0 ){
- pIndex->szIdxRow = sqlite3LogEst(sqlite3Atoi(z+3));
- }
+ pIndex->bUnordered = 0;
+ pIndex->noSkipScan = 0;
+ while( z[0] ){
+ if( sqlite3_strglob("unordered*", z)==0 ){
+ pIndex->bUnordered = 1;
+ }else if( sqlite3_strglob("sz=[0-9]*", z)==0 ){
+ pIndex->szIdxRow = sqlite3LogEst(sqlite3Atoi(z+3));
+ }else if( sqlite3_strglob("noskipscan*", z)==0 ){
+ pIndex->noSkipScan = 1;
+ }
#ifdef SQLITE_ENABLE_COSTMULT
- else if( sqlite3_strglob("costmult=[0-9]*",z)==0 ){
- pIndex->pTable->costMult = sqlite3LogEst(sqlite3Atoi(z+9));
- }
+ else if( sqlite3_strglob("costmult=[0-9]*",z)==0 ){
+ pIndex->pTable->costMult = sqlite3LogEst(sqlite3Atoi(z+9));
+ }
#endif
- while( z[0]!=0 && z[0]!=' ' ) z++;
- while( z[0]==' ' ) z++;
+ while( z[0]!=0 && z[0]!=' ' ) z++;
+ while( z[0]==' ' ) z++;
+ }
}
}
@@ -84920,8 +89580,20 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
z = argv[2];
if( pIndex ){
+ tRowcnt *aiRowEst = 0;
+ int nCol = pIndex->nKeyCol+1;
+#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+ /* Index.aiRowEst may already be set here if there are duplicate
+ ** sqlite_stat1 entries for this index. In that case just clobber
+ ** the old data with the new instead of allocating a new array. */
+ if( pIndex->aiRowEst==0 ){
+ pIndex->aiRowEst = (tRowcnt*)sqlite3MallocZero(sizeof(tRowcnt) * nCol);
+ if( pIndex->aiRowEst==0 ) pInfo->db->mallocFailed = 1;
+ }
+ aiRowEst = pIndex->aiRowEst;
+#endif
pIndex->bUnordered = 0;
- decodeIntArray((char*)z, pIndex->nKeyCol+1, 0, pIndex->aiRowLogEst, pIndex);
+ decodeIntArray((char*)z, nCol, aiRowEst, pIndex->aiRowLogEst, pIndex);
if( pIndex->pPartIdxWhere==0 ) pTable->nRowLogEst = pIndex->aiRowLogEst[0];
}else{
Index fakeIdx;
@@ -84980,25 +89652,39 @@ static void initAvgEq(Index *pIdx){
pIdx->aAvgEq[nCol] = 1;
}
for(iCol=0; iCol<nCol; iCol++){
+ int nSample = pIdx->nSample;
int i; /* Used to iterate through samples */
tRowcnt sumEq = 0; /* Sum of the nEq values */
- tRowcnt nSum = 0; /* Number of terms contributing to sumEq */
tRowcnt avgEq = 0;
- tRowcnt nDLt = pFinal->anDLt[iCol];
+ tRowcnt nRow; /* Number of rows in index */
+ i64 nSum100 = 0; /* Number of terms contributing to sumEq */
+ i64 nDist100; /* Number of distinct values in index */
+
+ if( !pIdx->aiRowEst || iCol>=pIdx->nKeyCol || pIdx->aiRowEst[iCol+1]==0 ){
+ nRow = pFinal->anLt[iCol];
+ nDist100 = (i64)100 * pFinal->anDLt[iCol];
+ nSample--;
+ }else{
+ nRow = pIdx->aiRowEst[0];
+ nDist100 = ((i64)100 * pIdx->aiRowEst[0]) / pIdx->aiRowEst[iCol+1];
+ }
+ pIdx->nRowEst0 = nRow;
/* Set nSum to the number of distinct (iCol+1) field prefixes that
- ** occur in the stat4 table for this index before pFinal. Set
- ** sumEq to the sum of the nEq values for column iCol for the same
- ** set (adding the value only once where there exist dupicate
- ** prefixes). */
- for(i=0; i<(pIdx->nSample-1); i++){
- if( aSample[i].anDLt[iCol]!=aSample[i+1].anDLt[iCol] ){
+ ** occur in the stat4 table for this index. Set sumEq to the sum of
+ ** the nEq values for column iCol for the same set (adding the value
+ ** only once where there exist duplicate prefixes). */
+ for(i=0; i<nSample; i++){
+ if( i==(pIdx->nSample-1)
+ || aSample[i].anDLt[iCol]!=aSample[i+1].anDLt[iCol]
+ ){
sumEq += aSample[i].anEq[iCol];
- nSum++;
+ nSum100 += 100;
}
}
- if( nDLt>nSum ){
- avgEq = (pFinal->anLt[iCol] - sumEq)/(nDLt - nSum);
+
+ if( nDist100>nSum100 ){
+ avgEq = ((i64)100 * (nRow - sumEq))/(nDist100 - nSum100);
}
if( avgEq==0 ) avgEq = 1;
pIdx->aAvgEq[iCol] = avgEq;
@@ -85244,12 +89930,17 @@ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
/* Load the statistics from the sqlite_stat4 table. */
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
- if( rc==SQLITE_OK ){
+ if( rc==SQLITE_OK && OptimizationEnabled(db, SQLITE_Stat34) ){
int lookasideEnabled = db->lookaside.bEnabled;
db->lookaside.bEnabled = 0;
rc = loadStat4(db, sInfo.zDatabase);
db->lookaside.bEnabled = lookasideEnabled;
}
+ for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
+ Index *pIdx = sqliteHashData(i);
+ sqlite3_free(pIdx->aiRowEst);
+ pIdx->aiRowEst = 0;
+ }
#endif
if( rc==SQLITE_NOMEM ){
@@ -85414,6 +90105,7 @@ static void attachFunc(
"attached databases must use the same text encoding as main database");
rc = SQLITE_ERROR;
}
+ sqlite3BtreeEnter(aNew->pBt);
pPager = sqlite3BtreePager(aNew->pBt);
sqlite3PagerLockingMode(pPager, db->dfltLockMode);
sqlite3BtreeSecureDelete(aNew->pBt,
@@ -85421,6 +90113,7 @@ static void attachFunc(
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
sqlite3BtreeSetPagerFlags(aNew->pBt, 3 | (db->flags & PAGER_FLAGS_MASK));
#endif
+ sqlite3BtreeLeave(aNew->pBt);
}
aNew->safety_level = 3;
aNew->zName = sqlite3DbStrDup(db, zName);
@@ -85453,7 +90146,7 @@ static void attachFunc(
case SQLITE_NULL:
/* No key specified. Use the key from the main database */
sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
- if( nKey>0 || sqlite3BtreeGetReserve(db->aDb[0].pBt)>0 ){
+ if( nKey>0 || sqlite3BtreeGetOptimalReserve(db->aDb[0].pBt)>0 ){
rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
}
break;
@@ -85471,6 +90164,15 @@ static void attachFunc(
rc = sqlite3Init(db, &zErrDyn);
sqlite3BtreeLeaveAll(db);
}
+#ifdef SQLITE_USER_AUTHENTICATION
+ if( rc==SQLITE_OK ){
+ u8 newAuth = 0;
+ rc = sqlite3UserAuthCheckLogin(db, zName, &newAuth);
+ if( newAuth<db->auth.authLevel ){
+ rc = SQLITE_AUTH_USER;
+ }
+ }
+#endif
if( rc ){
int iDb = db->nDb - 1;
assert( iDb>=2 );
@@ -85551,7 +90253,7 @@ static void detachFunc(
sqlite3BtreeClose(pDb->pBt);
pDb->pBt = 0;
pDb->pSchema = 0;
- sqlite3ResetAllSchemasOfConnection(db);
+ sqlite3CollapseDatabaseArray(db);
return;
detach_error:
@@ -85585,7 +90287,6 @@ static void codeAttach(
SQLITE_OK!=(rc = resolveAttachExpr(&sName, pDbname)) ||
SQLITE_OK!=(rc = resolveAttachExpr(&sName, pKey))
){
- pParse->nErr++;
goto attach_end;
}
@@ -85907,13 +90608,16 @@ SQLITE_PRIVATE int sqlite3FixTriggerStep(
** Setting the auth function to NULL disables this hook. The default
** setting of the auth function is NULL.
*/
-SQLITE_API int sqlite3_set_authorizer(
+SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer(
sqlite3 *db,
int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
void *pArg
){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
sqlite3_mutex_enter(db->mutex);
- db->xAuth = xAuth;
+ db->xAuth = (sqlite3_xauth)xAuth;
db->pAuthArg = pArg;
sqlite3ExpirePreparedStatements(db);
sqlite3_mutex_leave(db->mutex);
@@ -85948,7 +90652,11 @@ SQLITE_PRIVATE int sqlite3AuthReadCol(
char *zDb = db->aDb[iDb].zName; /* Name of attached database */
int rc; /* Auth callback return code */
- rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext);
+ rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext
+#ifdef SQLITE_USER_AUTHENTICATION
+ ,db->auth.zAuthUser
+#endif
+ );
if( rc==SQLITE_DENY ){
if( db->nDb>2 || iDb!=0 ){
sqlite3ErrorMsg(pParse, "access to %s.%s.%s is prohibited",zDb,zTab,zCol);
@@ -86048,7 +90756,11 @@ SQLITE_PRIVATE int sqlite3AuthCheck(
if( db->xAuth==0 ){
return SQLITE_OK;
}
- rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext);
+ rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext
+#ifdef SQLITE_USER_AUTHENTICATION
+ ,db->auth.zAuthUser
+#endif
+ );
if( rc==SQLITE_DENY ){
sqlite3ErrorMsg(pParse, "not authorized");
pParse->rc = SQLITE_AUTH;
@@ -86233,9 +90945,11 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
assert( pParse->pToplevel==0 );
db = pParse->db;
- if( db->mallocFailed ) return;
if( pParse->nested ) return;
- if( pParse->nErr ) return;
+ if( db->mallocFailed || pParse->nErr ){
+ if( pParse->rc==SQLITE_OK ) pParse->rc = SQLITE_ERROR;
+ return;
+ }
/* Begin by generating some termination code at the end of the
** vdbe program
@@ -86247,6 +90961,17 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
while( sqlite3VdbeDeletePriorOpcode(v, OP_Close) ){}
sqlite3VdbeAddOp0(v, OP_Halt);
+#if SQLITE_USER_AUTHENTICATION
+ if( pParse->nTableLock>0 && db->init.busy==0 ){
+ sqlite3UserAuthInit(db);
+ if( db->auth.authLevel<UAUTH_User ){
+ pParse->rc = SQLITE_AUTH_USER;
+ sqlite3ErrorMsg(pParse, "user not authenticated");
+ return;
+ }
+ }
+#endif
+
/* The cookie mask contains one bit for each database file open.
** (Bit 0 is for main, bit 1 is for temp, and so forth.) Bits are
** set for each database that is used. Generate code to start a
@@ -86306,7 +91031,7 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
/* Get the VDBE program ready for execution
*/
- if( v && ALWAYS(pParse->nErr==0) && !db->mallocFailed ){
+ if( v && pParse->nErr==0 && !db->mallocFailed ){
assert( pParse->iCacheLevel==0 ); /* Disables and re-enables match */
/* A minimum of one cursor is required if autoincrement is used
* See ticket [a696379c1f08866] */
@@ -86362,6 +91087,16 @@ SQLITE_PRIVATE void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
pParse->nested--;
}
+#if SQLITE_USER_AUTHENTICATION
+/*
+** Return TRUE if zTable is the name of the system table that stores the
+** list of users and their access credentials.
+*/
+SQLITE_PRIVATE int sqlite3UserAuthTable(const char *zTable){
+ return sqlite3_stricmp(zTable, "sqlite_user")==0;
+}
+#endif
+
/*
** Locate the in-memory structure that describes a particular database
** table given the name of that table and (optionally) the name of the
@@ -86377,16 +91112,21 @@ SQLITE_PRIVATE void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){
Table *p = 0;
int i;
- int nName;
- assert( zName!=0 );
- nName = sqlite3Strlen30(zName);
+
/* All mutexes are required for schema access. Make sure we hold them. */
assert( zDatabase!=0 || sqlite3BtreeHoldsAllMutexes(db) );
+#if SQLITE_USER_AUTHENTICATION
+ /* Only the admin user is allowed to know that the sqlite_user table
+ ** exists */
+ if( db->auth.authLevel<UAUTH_Admin && sqlite3UserAuthTable(zName)!=0 ){
+ return 0;
+ }
+#endif
for(i=OMIT_TEMPDB; i<db->nDb; i++){
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
if( zDatabase!=0 && sqlite3StrICmp(zDatabase, db->aDb[j].zName) ) continue;
assert( sqlite3SchemaMutexHeld(db, j, 0) );
- p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName, nName);
+ p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName);
if( p ) break;
}
return p;
@@ -86426,6 +91166,12 @@ SQLITE_PRIVATE Table *sqlite3LocateTable(
}
pParse->checkSchema = 1;
}
+#if SQLITE_USER_AUTHENICATION
+ else if( pParse->db->auth.authLevel<UAUTH_User ){
+ sqlite3ErrorMsg(pParse, "user not authenticated");
+ p = 0;
+ }
+#endif
return p;
}
@@ -86469,7 +91215,6 @@ SQLITE_PRIVATE Table *sqlite3LocateTableItem(
SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){
Index *p = 0;
int i;
- int nName = sqlite3Strlen30(zName);
/* All mutexes are required for schema access. Make sure we hold them. */
assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) );
for(i=OMIT_TEMPDB; i<db->nDb; i++){
@@ -86478,7 +91223,7 @@ SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const cha
assert( pSchema );
if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zName) ) continue;
assert( sqlite3SchemaMutexHeld(db, j, 0) );
- p = sqlite3HashFind(&pSchema->idxHash, zName, nName);
+ p = sqlite3HashFind(&pSchema->idxHash, zName);
if( p ) break;
}
return p;
@@ -86491,10 +91236,12 @@ static void freeIndex(sqlite3 *db, Index *p){
#ifndef SQLITE_OMIT_ANALYZE
sqlite3DeleteIndexSamples(db, p);
#endif
- if( db==0 || db->pnBytesFreed==0 ) sqlite3KeyInfoUnref(p->pKeyInfo);
sqlite3ExprDelete(db, p->pPartIdxWhere);
sqlite3DbFree(db, p->zColAff);
if( p->isResized ) sqlite3DbFree(db, p->azColl);
+#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+ sqlite3_free(p->aiRowEst);
+#endif
sqlite3DbFree(db, p);
}
@@ -86506,13 +91253,11 @@ static void freeIndex(sqlite3 *db, Index *p){
*/
SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){
Index *pIndex;
- int len;
Hash *pHash;
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
pHash = &db->aDb[iDb].pSchema->idxHash;
- len = sqlite3Strlen30(zIdxName);
- pIndex = sqlite3HashInsert(pHash, zIdxName, len, 0);
+ pIndex = sqlite3HashInsert(pHash, zIdxName, 0);
if( ALWAYS(pIndex) ){
if( pIndex->pTable->pIndex==pIndex ){
pIndex->pTable->pIndex = pIndex->pNext;
@@ -86672,7 +91417,7 @@ SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
if( !db || db->pnBytesFreed==0 ){
char *zName = pIndex->zName;
TESTONLY ( Index *pOld = ) sqlite3HashInsert(
- &pIndex->pSchema->idxHash, zName, sqlite3Strlen30(zName), 0
+ &pIndex->pSchema->idxHash, zName, 0
);
assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) );
assert( pOld==pIndex || pOld==0 );
@@ -86715,8 +91460,7 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
testcase( zTabName[0]==0 ); /* Zero-length table names are allowed */
pDb = &db->aDb[iDb];
- p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName,
- sqlite3Strlen30(zTabName),0);
+ p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, 0);
sqlite3DeleteTable(db, p);
db->flags |= SQLITE_InternChanges;
}
@@ -86822,14 +91566,12 @@ SQLITE_PRIVATE int sqlite3TwoPartName(
if( ALWAYS(pName2!=0) && pName2->n>0 ){
if( db->init.busy ) {
sqlite3ErrorMsg(pParse, "corrupt database");
- pParse->nErr++;
return -1;
}
*pUnqual = pName2;
iDb = sqlite3FindDb(db, pName1);
if( iDb<0 ){
sqlite3ErrorMsg(pParse, "unknown database %T", pName1);
- pParse->nErr++;
return -1;
}
}else{
@@ -86988,7 +91730,7 @@ SQLITE_PRIVATE void sqlite3StartTable(
if( !noErr ){
sqlite3ErrorMsg(pParse, "table %T already exists", pName);
}else{
- assert( !db->init.busy );
+ assert( !db->init.busy || CORRUPT_DB );
sqlite3CodeVerifySchema(pParse, iDb);
}
goto begin_table_error;
@@ -87240,7 +91982,7 @@ SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn, u8 *pszEst){
** estimate is scaled so that the size of an integer is 1. */
if( pszEst ){
*pszEst = 1; /* default size is approx 4 bytes */
- if( aff<=SQLITE_AFF_NONE ){
+ if( aff<SQLITE_AFF_NUMERIC ){
if( zChar ){
while( zChar[0] ){
if( sqlite3Isdigit(zChar[0]) ){
@@ -87277,7 +92019,8 @@ SQLITE_PRIVATE void sqlite3AddColumnType(Parse *pParse, Token *pType){
p = pParse->pNewTable;
if( p==0 || NEVER(p->nCol<1) ) return;
pCol = &p->aCol[p->nCol-1];
- assert( pCol->zType==0 );
+ assert( pCol->zType==0 || CORRUPT_DB );
+ sqlite3DbFree(pParse->db, pCol->zType);
pCol->zType = sqlite3NameFromToken(pParse->db, pType);
pCol->affinity = sqlite3AffinityType(pCol->zType, &pCol->szEst);
}
@@ -87299,7 +92042,7 @@ SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse *pParse, ExprSpan *pSpan){
p = pParse->pNewTable;
if( p!=0 ){
pCol = &(p->aCol[p->nCol-1]);
- if( !sqlite3ExprIsConstantOrFunction(pSpan->pExpr) ){
+ if( !sqlite3ExprIsConstantOrFunction(pSpan->pExpr, db->init.busy) ){
sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant",
pCol->zName);
}else{
@@ -87611,8 +92354,8 @@ static char *createTableStmt(sqlite3 *db, Table *p){
zStmt[k++] = '(';
for(pCol=p->aCol, i=0; i<p->nCol; i++, pCol++){
static const char * const azType[] = {
- /* SQLITE_AFF_TEXT */ " TEXT",
/* SQLITE_AFF_NONE */ "",
+ /* SQLITE_AFF_TEXT */ " TEXT",
/* SQLITE_AFF_NUMERIC */ " NUM",
/* SQLITE_AFF_INTEGER */ " INT",
/* SQLITE_AFF_REAL */ " REAL"
@@ -87624,15 +92367,15 @@ static char *createTableStmt(sqlite3 *db, Table *p){
k += sqlite3Strlen30(&zStmt[k]);
zSep = zSep2;
identPut(zStmt, &k, pCol->zName);
- assert( pCol->affinity-SQLITE_AFF_TEXT >= 0 );
- assert( pCol->affinity-SQLITE_AFF_TEXT < ArraySize(azType) );
- testcase( pCol->affinity==SQLITE_AFF_TEXT );
+ assert( pCol->affinity-SQLITE_AFF_NONE >= 0 );
+ assert( pCol->affinity-SQLITE_AFF_NONE < ArraySize(azType) );
testcase( pCol->affinity==SQLITE_AFF_NONE );
+ testcase( pCol->affinity==SQLITE_AFF_TEXT );
testcase( pCol->affinity==SQLITE_AFF_NUMERIC );
testcase( pCol->affinity==SQLITE_AFF_INTEGER );
testcase( pCol->affinity==SQLITE_AFF_REAL );
- zType = azType[pCol->affinity - SQLITE_AFF_TEXT];
+ zType = azType[pCol->affinity - SQLITE_AFF_NONE];
len = sqlite3Strlen30(zType);
assert( pCol->affinity==SQLITE_AFF_NONE
|| pCol->affinity==sqlite3AffinityType(zType, 0) );
@@ -87716,7 +92459,7 @@ static int hasColumn(const i16 *aiCol, int nCol, int x){
** no rowid btree for a WITHOUT ROWID. Instead, the canonical
** data storage is a covering index btree.
** (2) Bypass the creation of the sqlite_master table entry
-** for the PRIMARY KEY as the the primary key index is now
+** for the PRIMARY KEY as the primary key index is now
** identified by the sqlite_master table entry of the table itself.
** (3) Set the Index.tnum of the PRIMARY KEY Index object in the
** schema to the rootpage from the main table.
@@ -87737,7 +92480,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
Vdbe *v = pParse->pVdbe;
/* Convert the OP_CreateTable opcode that would normally create the
- ** root-page for the table into a OP_CreateIndex opcode. The index
+ ** root-page for the table into an OP_CreateIndex opcode. The index
** created will become the PRIMARY KEY index.
*/
if( pParse->addrCrTab ){
@@ -87770,16 +92513,32 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
pTab->iPKey = -1;
}else{
pPk = sqlite3PrimaryKeyIndex(pTab);
+ /*
+ ** Remove all redundant columns from the PRIMARY KEY. For example, change
+ ** "PRIMARY KEY(a,b,a,b,c,b,c,d)" into just "PRIMARY KEY(a,b,c,d)". Later
+ ** code assumes the PRIMARY KEY contains no repeated columns.
+ */
+ for(i=j=1; i<pPk->nKeyCol; i++){
+ if( hasColumn(pPk->aiColumn, j, pPk->aiColumn[i]) ){
+ pPk->nColumn--;
+ }else{
+ pPk->aiColumn[j++] = pPk->aiColumn[i];
+ }
+ }
+ pPk->nKeyCol = j;
}
pPk->isCovering = 1;
assert( pPk!=0 );
nPk = pPk->nKeyCol;
- /* Make sure every column of the PRIMARY KEY is NOT NULL */
- for(i=0; i<nPk; i++){
- pTab->aCol[pPk->aiColumn[i]].notNull = 1;
+ /* Make sure every column of the PRIMARY KEY is NOT NULL. (Except,
+ ** do not enforce this for imposter tables.) */
+ if( !db->init.imposterTable ){
+ for(i=0; i<nPk; i++){
+ pTab->aCol[pPk->aiColumn[i]].notNull = 1;
+ }
+ pPk->uniqNotNull = 1;
}
- pPk->uniqNotNull = 1;
/* The root page of the PRIMARY KEY is the table root page */
pPk->tnum = pTab->tnum;
@@ -88038,8 +92797,7 @@ SQLITE_PRIVATE void sqlite3EndTable(
Table *pOld;
Schema *pSchema = p->pSchema;
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
- pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName,
- sqlite3Strlen30(p->zName),p);
+ pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName, p);
if( pOld ){
assert( p==pOld ); /* Malloc must have failed inside HashInsert() */
db->mallocFailed = 1;
@@ -88150,7 +92908,7 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
int nErr = 0; /* Number of errors encountered */
int n; /* Temporarily holds the number of cursors assigned */
sqlite3 *db = pParse->db; /* Database connection for malloc errors */
- int (*xAuth)(void*,int,const char*,const char*,const char*,const char*);
+ sqlite3_xauth xAuth; /* Saved xAuth pointer */
assert( pTable );
@@ -88496,6 +93254,7 @@ SQLITE_PRIVATE void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView,
}
assert( pParse->nErr==0 );
assert( pName->nSrc==1 );
+ if( sqlite3ReadSchema(pParse) ) goto exit_drop_table;
if( noErr ) db->suppressErr++;
pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]);
if( noErr ) db->suppressErr--;
@@ -88689,7 +93448,7 @@ SQLITE_PRIVATE void sqlite3CreateForeignKey(
assert( sqlite3SchemaMutexHeld(db, 0, p->pSchema) );
pNextTo = (FKey *)sqlite3HashInsert(&p->pSchema->fkeyHash,
- pFKey->zTo, sqlite3Strlen30(pFKey->zTo), (void *)pFKey
+ pFKey->zTo, (void *)pFKey
);
if( pNextTo==pFKey ){
db->mallocFailed = 1;
@@ -88752,7 +93511,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
int iPartIdxLabel; /* Jump to this label to skip a row */
Vdbe *v; /* Generate code into this virtual machine */
KeyInfo *pKey; /* KeyInfo for index */
- int regRecord; /* Register holding assemblied index record */
+ int regRecord; /* Register holding assembled index record */
sqlite3 *db = pParse->db; /* The database connection */
int iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);
@@ -88777,7 +93536,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
/* Open the sorter cursor if we are to use one. */
iSorter = pParse->nTab++;
- sqlite3VdbeAddOp4(v, OP_SorterOpen, iSorter, 0, 0, (char*)
+ sqlite3VdbeAddOp4(v, OP_SorterOpen, iSorter, 0, pIndex->nKeyCol, (char*)
sqlite3KeyInfoRef(pKey), P4_KEYINFO);
/* Open the table. Loop through all rows of the table, inserting index
@@ -88808,8 +93567,9 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
}else{
addr2 = sqlite3VdbeCurrentAddr(v);
}
- sqlite3VdbeAddOp2(v, OP_SorterData, iSorter, regRecord);
- sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 1);
+ sqlite3VdbeAddOp3(v, OP_SorterData, iSorter, regRecord, iIdx);
+ sqlite3VdbeAddOp3(v, OP_Last, iIdx, 0, -1);
+ sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 0);
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
sqlite3ReleaseTempReg(pParse, regRecord);
sqlite3VdbeAddOp2(v, OP_SorterNext, iSorter, addr2); VdbeCoverage(v);
@@ -88902,8 +93662,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
char *zExtra = 0; /* Extra space after the Index object */
Index *pPk = 0; /* PRIMARY KEY index for WITHOUT ROWID tables */
- assert( pParse->nErr==0 ); /* Never called with prior errors */
- if( db->mallocFailed || IN_DECLARE_VTAB ){
+ if( db->mallocFailed || IN_DECLARE_VTAB || pParse->nErr>0 ){
goto exit_create_index;
}
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
@@ -88965,6 +93724,10 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
assert( pTab!=0 );
assert( pParse->nErr==0 );
if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0
+ && db->init.busy==0
+#if SQLITE_USER_AUTHENTICATION
+ && sqlite3UserAuthTable(pTab->zName)==0
+#endif
&& sqlite3StrNICmp(&pTab->zName[7],"altertab_",9)!=0 ){
sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName);
goto exit_create_index;
@@ -89126,7 +93889,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
pParse->checkSchema = 1;
goto exit_create_index;
}
- assert( pTab->nCol<=0x7fff && j<=0x7fff );
+ assert( j<=0x7fff );
pIndex->aiColumn[i] = (i16)j;
if( pListItem->pExpr ){
int nColl;
@@ -89225,6 +93988,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
pIdx->onError = pIndex->onError;
}
}
+ pRet = pIdx;
goto exit_create_index;
}
}
@@ -89237,8 +94001,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
Index *p;
assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) );
p = sqlite3HashInsert(&pIndex->pSchema->idxHash,
- pIndex->zName, sqlite3Strlen30(pIndex->zName),
- pIndex);
+ pIndex->zName, pIndex);
if( p ){
assert( p==pIndex ); /* Malloc must have failed */
db->mallocFailed = 1;
@@ -89353,7 +94116,7 @@ exit_create_index:
** Fill the Index.aiRowEst[] array with default information - information
** to be used when we have not run the ANALYZE command.
**
-** aiRowEst[0] is suppose to contain the number of elements in the index.
+** aiRowEst[0] is supposed to contain the number of elements in the index.
** Since we do not know, guess 1 million. aiRowEst[1] is an estimate of the
** number of rows in the table that match any particular value of the
** first column of the index. aiRowEst[2] is an estimate of the number
@@ -89732,7 +94495,7 @@ SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
** if this is the first term of the FROM clause. pTable and pDatabase
** are the name of the table and database named in the FROM clause term.
** pDatabase is NULL if the database name qualifier is missing - the
-** usual case. If the term has a alias, then pAlias points to the
+** usual case. If the term has an alias, then pAlias points to the
** alias token. If the term is a subquery, then pSubquery is the
** SELECT statement that the subquery encodes. The pTable and
** pDatabase parameters are NULL for subqueries. The pOn and pUsing
@@ -89818,7 +94581,6 @@ SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pI
SQLITE_PRIVATE void sqlite3SrcListShiftJoinType(SrcList *p){
if( p ){
int i;
- assert( p->a || p->nSrc==0 );
for(i=p->nSrc-1; i>0; i--){
p->a[i].jointype = p->a[i-1].jointype;
}
@@ -90065,8 +94827,7 @@ SQLITE_PRIVATE void sqlite3UniqueConstraint(
StrAccum errMsg;
Table *pTab = pIdx->pTable;
- sqlite3StrAccumInit(&errMsg, 0, 0, 200);
- errMsg.db = pParse->db;
+ sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, 200);
for(j=0; j<pIdx->nKeyCol; j++){
char *zCol = pTab->aCol[pIdx->aiColumn[j]].zName;
if( j ) sqlite3StrAccumAppend(&errMsg, ", ", 2);
@@ -90244,40 +95005,31 @@ SQLITE_PRIVATE void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
** when it has finished using it.
*/
SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){
+ int i;
+ int nCol = pIdx->nColumn;
+ int nKey = pIdx->nKeyCol;
+ KeyInfo *pKey;
if( pParse->nErr ) return 0;
-#ifndef SQLITE_OMIT_SHARED_CACHE
- if( pIdx->pKeyInfo && pIdx->pKeyInfo->db!=pParse->db ){
- sqlite3KeyInfoUnref(pIdx->pKeyInfo);
- pIdx->pKeyInfo = 0;
+ if( pIdx->uniqNotNull ){
+ pKey = sqlite3KeyInfoAlloc(pParse->db, nKey, nCol-nKey);
+ }else{
+ pKey = sqlite3KeyInfoAlloc(pParse->db, nCol, 0);
}
-#endif
- if( pIdx->pKeyInfo==0 ){
- int i;
- int nCol = pIdx->nColumn;
- int nKey = pIdx->nKeyCol;
- KeyInfo *pKey;
- if( pIdx->uniqNotNull ){
- pKey = sqlite3KeyInfoAlloc(pParse->db, nKey, nCol-nKey);
- }else{
- pKey = sqlite3KeyInfoAlloc(pParse->db, nCol, 0);
+ if( pKey ){
+ assert( sqlite3KeyInfoIsWriteable(pKey) );
+ for(i=0; i<nCol; i++){
+ char *zColl = pIdx->azColl[i];
+ assert( zColl!=0 );
+ pKey->aColl[i] = strcmp(zColl,"BINARY")==0 ? 0 :
+ sqlite3LocateCollSeq(pParse, zColl);
+ pKey->aSortOrder[i] = pIdx->aSortOrder[i];
}
- if( pKey ){
- assert( sqlite3KeyInfoIsWriteable(pKey) );
- for(i=0; i<nCol; i++){
- char *zColl = pIdx->azColl[i];
- assert( zColl!=0 );
- pKey->aColl[i] = strcmp(zColl,"BINARY")==0 ? 0 :
- sqlite3LocateCollSeq(pParse, zColl);
- pKey->aSortOrder[i] = pIdx->aSortOrder[i];
- }
- if( pParse->nErr ){
- sqlite3KeyInfoUnref(pKey);
- }else{
- pIdx->pKeyInfo = pKey;
- }
+ if( pParse->nErr ){
+ sqlite3KeyInfoUnref(pKey);
+ pKey = 0;
}
}
- return sqlite3KeyInfoRef(pIdx->pKeyInfo);
+ return pKey;
}
#ifndef SQLITE_OMIT_CTE
@@ -90495,7 +95247,7 @@ SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){
**
** Each pointer stored in the sqlite3.aCollSeq hash table contains an
** array of three CollSeq structures. The first is the collation sequence
-** prefferred for UTF-8, the second UTF-16le, and the third UTF-16be.
+** preferred for UTF-8, the second UTF-16le, and the third UTF-16be.
**
** Stored immediately after the three collation sequences is a copy of
** the collation sequence name. A pointer to this string is stored in
@@ -90507,11 +95259,11 @@ static CollSeq *findCollSeqEntry(
int create /* Create a new entry if true */
){
CollSeq *pColl;
- int nName = sqlite3Strlen30(zName);
- pColl = sqlite3HashFind(&db->aCollSeq, zName, nName);
+ pColl = sqlite3HashFind(&db->aCollSeq, zName);
if( 0==pColl && create ){
- pColl = sqlite3DbMallocZero(db, 3*sizeof(*pColl) + nName + 1 );
+ int nName = sqlite3Strlen30(zName);
+ pColl = sqlite3DbMallocZero(db, 3*sizeof(*pColl) + nName + 1);
if( pColl ){
CollSeq *pDel = 0;
pColl[0].zName = (char*)&pColl[3];
@@ -90522,7 +95274,7 @@ static CollSeq *findCollSeqEntry(
pColl[2].enc = SQLITE_UTF16BE;
memcpy(pColl[0].zName, zName, nName);
pColl[0].zName[nName] = 0;
- pDel = sqlite3HashInsert(&db->aCollSeq, pColl[0].zName, nName, pColl);
+ pDel = sqlite3HashInsert(&db->aCollSeq, pColl[0].zName, pColl);
/* If a malloc() failure occurred in sqlite3HashInsert(), it will
** return the pColl pointer to be deleted (because it wasn't added
@@ -90922,7 +95674,7 @@ SQLITE_PRIVATE void sqlite3MaterializeView(
Parse *pParse, /* Parsing context */
Table *pView, /* View definition */
Expr *pWhere, /* Optional WHERE clause to be added */
- int iCur /* Cursor number for ephemerial table */
+ int iCur /* Cursor number for ephemeral table */
){
SelectDest dest;
Select *pSel;
@@ -91021,7 +95773,7 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere(
pInClause->x.pSelect = pSelect;
pInClause->flags |= EP_xIsSelect;
- sqlite3ExprSetHeight(pParse, pInClause);
+ sqlite3ExprSetHeightAndFlags(pParse, pInClause);
return pInClause;
/* something went wrong. clean up anything allocated. */
@@ -91058,8 +95810,8 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
WhereInfo *pWInfo; /* Information about the WHERE clause */
Index *pIdx; /* For looping over indices of the table */
int iTabCur; /* Cursor number for the table */
- int iDataCur; /* VDBE cursor for the canonical data source */
- int iIdxCur; /* Cursor number of the first index */
+ int iDataCur = 0; /* VDBE cursor for the canonical data source */
+ int iIdxCur = 0; /* Cursor number of the first index */
int nIdx; /* Number of indices */
sqlite3 *db; /* Main database structure */
AuthContext sContext; /* Authorization context */
@@ -91080,7 +95832,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
int addrBypass = 0; /* Address of jump over the delete logic */
int addrLoop = 0; /* Top of the delete loop */
int addrDelete = 0; /* Jump directly to the delete logic */
- int addrEphOpen = 0; /* Instruction to open the Ephermeral table */
+ int addrEphOpen = 0; /* Instruction to open the Ephemeral table */
#ifndef SQLITE_OMIT_TRIGGER
int isView; /* True if attempting to delete from a view */
@@ -91160,7 +95912,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
sqlite3BeginWriteOperation(pParse, 1, iDb);
/* If we are trying to delete from a view, realize that view into
- ** a ephemeral table.
+ ** an ephemeral table.
*/
#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
if( isView ){
@@ -91214,7 +95966,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
iRowSet = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet);
}else{
- /* For a WITHOUT ROWID table, create an ephermeral table used to
+ /* For a WITHOUT ROWID table, create an ephemeral table used to
** hold all primary keys for rows to be deleted. */
pPk = sqlite3PrimaryKeyIndex(pTab);
assert( pPk!=0 );
@@ -91298,10 +96050,11 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
** triggers.
*/
if( !isView ){
+ testcase( IsVirtual(pTab) );
sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, iTabCur, aToOpen,
&iDataCur, &iIdxCur);
- assert( pPk || iDataCur==iTabCur );
- assert( pPk || iIdxCur==iDataCur+1 );
+ assert( pPk || IsVirtual(pTab) || iDataCur==iTabCur );
+ assert( pPk || IsVirtual(pTab) || iIdxCur==iDataCur+1 );
}
/* Set up a loop over the rowids/primary-keys that were found in the
@@ -91309,9 +96062,10 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
*/
if( okOnePass ){
/* Just one row. Hence the top-of-loop is a no-op */
- assert( nKey==nPk ); /* OP_Found will use an unpacked key */
+ assert( nKey==nPk ); /* OP_Found will use an unpacked key */
+ assert( !IsVirtual(pTab) );
if( aToOpen[iDataCur-iTabCur] ){
- assert( pPk!=0 );
+ assert( pPk!=0 || pTab->pSelect!=0 );
sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, addrBypass, iKey, nKey);
VdbeCoverage(v);
}
@@ -91387,7 +96141,7 @@ delete_from_cleanup:
return;
}
/* Make sure "isView" and other macros defined above are undefined. Otherwise
-** thely may interfere with compilation of other functions in this file
+** they may interfere with compilation of other functions in this file
** (or in another file, if this file becomes part of the amalgamation). */
#ifdef isView
#undef isView
@@ -91681,7 +96435,7 @@ SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse *pParse, int iLabel){
** May you share freely, never taking more than you give.
**
*************************************************************************
-** This file contains the C-language implementions for many of the SQL
+** This file contains the C-language implementations for many of the SQL
** functions of SQLite. (Some function, and in particular the date and
** time functions, are implemented separately.)
*/
@@ -91692,7 +96446,12 @@ SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse *pParse, int iLabel){
** Return the collating function associated with a function.
*/
static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){
- return context->pColl;
+ VdbeOp *pOp;
+ assert( context->pVdbe!=0 );
+ pOp = &context->pVdbe->aOp[context->iOp-1];
+ assert( pOp->opcode==OP_CollSeq );
+ assert( pOp->p4type==P4_COLLSEQ );
+ return pOp->p4.pColl;
}
/*
@@ -91824,8 +96583,8 @@ static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
default: {
/* Because sqlite3_value_double() returns 0.0 if the argument is not
** something that can be converted into a number, we have:
- ** IMP: R-57326-31541 Abs(X) return 0.0 if X is a string or blob that
- ** cannot be converted to a numeric value.
+ ** IMP: R-01992-00519 Abs(X) returns 0.0 if X is a string or blob
+ ** that cannot be converted to a numeric value.
*/
double rVal = sqlite3_value_double(argv[0]);
if( rVal<0 ) rVal = -rVal;
@@ -91897,13 +96656,13 @@ static void printfFunc(
StrAccum str;
const char *zFormat;
int n;
+ sqlite3 *db = sqlite3_context_db_handle(context);
if( argc>=1 && (zFormat = (const char*)sqlite3_value_text(argv[0]))!=0 ){
x.nArg = argc-1;
x.nUsed = 0;
x.apArg = argv+1;
- sqlite3StrAccumInit(&str, 0, 0, SQLITE_MAX_LENGTH);
- str.db = sqlite3_context_db_handle(context);
+ sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]);
sqlite3XPrintf(&str, SQLITE_PRINTF_SQLFUNC, zFormat, &x);
n = str.nChar;
sqlite3_result_text(context, sqlite3StrAccumFinish(&str), n,
@@ -91958,6 +96717,14 @@ static void substrFunc(
}
}
}
+#ifdef SQLITE_SUBSTR_COMPATIBILITY
+ /* If SUBSTR_COMPATIBILITY is defined then substr(X,0,N) work the same as
+ ** as substr(X,1,N) - it returns the first N characters of X. This
+ ** is essentially a back-out of the bug-fix in check-in [5fc125d362df4b8]
+ ** from 2009-02-02 for compatibility of applications that exploited the
+ ** old buggy behavior. */
+ if( p1==0 ) p1 = 1; /* <rdar://problem/6778339> */
+#endif
if( argc==3 ){
p2 = sqlite3_value_int(argv[2]);
if( p2<0 ){
@@ -91995,13 +96762,14 @@ static void substrFunc(
for(z2=z; *z2 && p2; p2--){
SQLITE_SKIP_UTF8(z2);
}
- sqlite3_result_text(context, (char*)z, (int)(z2-z), SQLITE_TRANSIENT);
+ sqlite3_result_text64(context, (char*)z, z2-z, SQLITE_TRANSIENT,
+ SQLITE_UTF8);
}else{
if( p1+p2>len ){
p2 = len-p1;
if( p2<0 ) p2 = 0;
}
- sqlite3_result_blob(context, (char*)&z[p1], (int)p2, SQLITE_TRANSIENT);
+ sqlite3_result_blob64(context, (char*)&z[p1], (u64)p2, SQLITE_TRANSIENT);
}
}
@@ -92044,7 +96812,7 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
#endif
/*
-** Allocate nByte bytes of space using sqlite3_malloc(). If the
+** Allocate nByte bytes of space using sqlite3Malloc(). If the
** allocation fails, call sqlite3_result_error_nomem() to notify
** the database handle that malloc() has failed and return NULL.
** If nByte is larger than the maximum string or blob length, then
@@ -92060,7 +96828,7 @@ static void *contextMalloc(sqlite3_context *context, i64 nByte){
sqlite3_result_error_toobig(context);
z = 0;
}else{
- z = sqlite3Malloc((int)nByte);
+ z = sqlite3Malloc(nByte);
if( !z ){
sqlite3_result_error_nomem(context);
}
@@ -92236,10 +97004,12 @@ struct compareInfo {
** whereas only characters less than 0x80 do in ASCII.
*/
#if defined(SQLITE_EBCDIC)
-# define sqlite3Utf8Read(A) (*((*A)++))
-# define GlobUpperToLower(A) A = sqlite3UpperToLower[A]
+# define sqlite3Utf8Read(A) (*((*A)++))
+# define GlobUpperToLower(A) A = sqlite3UpperToLower[A]
+# define GlobUpperToLowerAscii(A) A = sqlite3UpperToLower[A]
#else
-# define GlobUpperToLower(A) if( !((A)&~0x7f) ){ A = sqlite3UpperToLower[A]; }
+# define GlobUpperToLower(A) if( A<=0x7f ){ A = sqlite3UpperToLower[A]; }
+# define GlobUpperToLowerAscii(A) A = sqlite3UpperToLower[A]
#endif
static const struct compareInfo globInfo = { '*', '?', '[', 0 };
@@ -92252,7 +97022,7 @@ static const struct compareInfo likeInfoAlt = { '%', '_', 0, 0 };
/*
** Compare two UTF-8 strings for equality where the first string can
-** potentially be a "glob" expression. Return true (1) if they
+** potentially be a "glob" or "like" expression. Return true (1) if they
** are the same and false (0) if they are different.
**
** Globbing rules:
@@ -92272,11 +97042,18 @@ static const struct compareInfo likeInfoAlt = { '%', '_', 0, 0 };
** "[a-z]" matches any single lower-case letter. To match a '-', make
** it the last character in the list.
**
-** This routine is usually quick, but can be N**2 in the worst case.
+** Like matching rules:
+**
+** '%' Matches any sequence of zero or more characters
+**
+*** '_' Matches any one character
**
-** Hints: to match '*' or '?', put them in "[]". Like this:
+** Ec Where E is the "esc" character and c is any other
+** character, including '%', '_', and esc, match exactly c.
**
-** abc[*]xyz Matches "abc*xyz" only
+** The comments through this routine usually assume glob matching.
+**
+** This routine is usually quick, but can be N**2 in the worst case.
*/
static int patternCompare(
const u8 *zPattern, /* The glob pattern */
@@ -92284,17 +97061,25 @@ static int patternCompare(
const struct compareInfo *pInfo, /* Information about how to do the compare */
u32 esc /* The escape character */
){
- u32 c, c2;
- int invert;
- int seen;
- u8 matchOne = pInfo->matchOne;
- u8 matchAll = pInfo->matchAll;
- u8 matchSet = pInfo->matchSet;
- u8 noCase = pInfo->noCase;
- int prevEscape = 0; /* True if the previous character was 'escape' */
+ u32 c, c2; /* Next pattern and input string chars */
+ u32 matchOne = pInfo->matchOne; /* "?" or "_" */
+ u32 matchAll = pInfo->matchAll; /* "*" or "%" */
+ u32 matchOther; /* "[" or the escape character */
+ u8 noCase = pInfo->noCase; /* True if uppercase==lowercase */
+ const u8 *zEscaped = 0; /* One past the last escaped input char */
+
+ /* The GLOB operator does not have an ESCAPE clause. And LIKE does not
+ ** have the matchSet operator. So we either have to look for one or
+ ** the other, never both. Hence the single variable matchOther is used
+ ** to store the one we have to look for.
+ */
+ matchOther = esc ? esc : pInfo->matchSet;
while( (c = sqlite3Utf8Read(&zPattern))!=0 ){
- if( c==matchAll && !prevEscape ){
+ if( c==matchAll ){ /* Match "*" */
+ /* Skip over multiple "*" characters in the pattern. If there
+ ** are also "?" characters, skip those as well, but consume a
+ ** single character of the input string for each "?" skipped */
while( (c=sqlite3Utf8Read(&zPattern)) == matchAll
|| c == matchOne ){
if( c==matchOne && sqlite3Utf8Read(&zString)==0 ){
@@ -92302,86 +97087,98 @@ static int patternCompare(
}
}
if( c==0 ){
- return 1;
- }else if( c==esc ){
- c = sqlite3Utf8Read(&zPattern);
- if( c==0 ){
- return 0;
- }
- }else if( c==matchSet ){
- assert( esc==0 ); /* This is GLOB, not LIKE */
- assert( matchSet<0x80 ); /* '[' is a single-byte character */
- while( *zString && patternCompare(&zPattern[-1],zString,pInfo,esc)==0 ){
- SQLITE_SKIP_UTF8(zString);
+ return 1; /* "*" at the end of the pattern matches */
+ }else if( c==matchOther ){
+ if( esc ){
+ c = sqlite3Utf8Read(&zPattern);
+ if( c==0 ) return 0;
+ }else{
+ /* "[...]" immediately follows the "*". We have to do a slow
+ ** recursive search in this case, but it is an unusual case. */
+ assert( matchOther<0x80 ); /* '[' is a single-byte character */
+ while( *zString
+ && patternCompare(&zPattern[-1],zString,pInfo,esc)==0 ){
+ SQLITE_SKIP_UTF8(zString);
+ }
+ return *zString!=0;
}
- return *zString!=0;
}
- while( (c2 = sqlite3Utf8Read(&zString))!=0 ){
+
+ /* At this point variable c contains the first character of the
+ ** pattern string past the "*". Search in the input string for the
+ ** first matching character and recursively contine the match from
+ ** that point.
+ **
+ ** For a case-insensitive search, set variable cx to be the same as
+ ** c but in the other case and search the input string for either
+ ** c or cx.
+ */
+ if( c<=0x80 ){
+ u32 cx;
if( noCase ){
- GlobUpperToLower(c2);
- GlobUpperToLower(c);
- while( c2 != 0 && c2 != c ){
- c2 = sqlite3Utf8Read(&zString);
- GlobUpperToLower(c2);
- }
+ cx = sqlite3Toupper(c);
+ c = sqlite3Tolower(c);
}else{
- while( c2 != 0 && c2 != c ){
- c2 = sqlite3Utf8Read(&zString);
- }
+ cx = c;
+ }
+ while( (c2 = *(zString++))!=0 ){
+ if( c2!=c && c2!=cx ) continue;
+ if( patternCompare(zPattern,zString,pInfo,esc) ) return 1;
+ }
+ }else{
+ while( (c2 = sqlite3Utf8Read(&zString))!=0 ){
+ if( c2!=c ) continue;
+ if( patternCompare(zPattern,zString,pInfo,esc) ) return 1;
}
- if( c2==0 ) return 0;
- if( patternCompare(zPattern,zString,pInfo,esc) ) return 1;
}
return 0;
- }else if( c==matchOne && !prevEscape ){
- if( sqlite3Utf8Read(&zString)==0 ){
- return 0;
- }
- }else if( c==matchSet ){
- u32 prior_c = 0;
- assert( esc==0 ); /* This only occurs for GLOB, not LIKE */
- seen = 0;
- invert = 0;
- c = sqlite3Utf8Read(&zString);
- if( c==0 ) return 0;
- c2 = sqlite3Utf8Read(&zPattern);
- if( c2=='^' ){
- invert = 1;
- c2 = sqlite3Utf8Read(&zPattern);
- }
- if( c2==']' ){
- if( c==']' ) seen = 1;
+ }
+ if( c==matchOther ){
+ if( esc ){
+ c = sqlite3Utf8Read(&zPattern);
+ if( c==0 ) return 0;
+ zEscaped = zPattern;
+ }else{
+ u32 prior_c = 0;
+ int seen = 0;
+ int invert = 0;
+ c = sqlite3Utf8Read(&zString);
+ if( c==0 ) return 0;
c2 = sqlite3Utf8Read(&zPattern);
- }
- while( c2 && c2!=']' ){
- if( c2=='-' && zPattern[0]!=']' && zPattern[0]!=0 && prior_c>0 ){
+ if( c2=='^' ){
+ invert = 1;
c2 = sqlite3Utf8Read(&zPattern);
- if( c>=prior_c && c<=c2 ) seen = 1;
- prior_c = 0;
- }else{
- if( c==c2 ){
- seen = 1;
+ }
+ if( c2==']' ){
+ if( c==']' ) seen = 1;
+ c2 = sqlite3Utf8Read(&zPattern);
+ }
+ while( c2 && c2!=']' ){
+ if( c2=='-' && zPattern[0]!=']' && zPattern[0]!=0 && prior_c>0 ){
+ c2 = sqlite3Utf8Read(&zPattern);
+ if( c>=prior_c && c<=c2 ) seen = 1;
+ prior_c = 0;
+ }else{
+ if( c==c2 ){
+ seen = 1;
+ }
+ prior_c = c2;
}
- prior_c = c2;
+ c2 = sqlite3Utf8Read(&zPattern);
}
- c2 = sqlite3Utf8Read(&zPattern);
- }
- if( c2==0 || (seen ^ invert)==0 ){
- return 0;
- }
- }else if( esc==c && !prevEscape ){
- prevEscape = 1;
- }else{
- c2 = sqlite3Utf8Read(&zString);
- if( noCase ){
- GlobUpperToLower(c);
- GlobUpperToLower(c2);
- }
- if( c!=c2 ){
- return 0;
+ if( c2==0 || (seen ^ invert)==0 ){
+ return 0;
+ }
+ continue;
}
- prevEscape = 0;
}
+ c2 = sqlite3Utf8Read(&zString);
+ if( c==c2 ) continue;
+ if( noCase && c<0x80 && c2<0x80 && sqlite3Tolower(c)==sqlite3Tolower(c2) ){
+ continue;
+ }
+ if( c==matchOne && zPattern!=zEscaped && c2!=0 ) continue;
+ return 0;
}
return *zString==0;
}
@@ -92389,7 +97186,7 @@ static int patternCompare(
/*
** The sqlite3_strglob() interface.
*/
-SQLITE_API int sqlite3_strglob(const char *zGlobPattern, const char *zString){
+SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlobPattern, const char *zString){
return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, 0)==0;
}
@@ -92684,7 +97481,7 @@ static void charFunc(
){
unsigned char *z, *zOut;
int i;
- zOut = z = sqlite3_malloc( argc*4+1 );
+ zOut = z = sqlite3_malloc64( argc*4+1 );
if( z==0 ){
sqlite3_result_error_nomem(context);
return;
@@ -92711,7 +97508,7 @@ static void charFunc(
*zOut++ = 0x80 + (u8)(c & 0x3F);
} \
}
- sqlite3_result_text(context, (char*)z, (int)(zOut-z), sqlite3_free);
+ sqlite3_result_text64(context, (char*)z, zOut-z, sqlite3_free, SQLITE_UTF8);
}
/*
@@ -92832,7 +97629,7 @@ static void replaceFunc(
return;
}
zOld = zOut;
- zOut = sqlite3_realloc(zOut, (int)nOut);
+ zOut = sqlite3_realloc64(zOut, (int)nOut);
if( zOut==0 ){
sqlite3_result_error_nomem(context);
sqlite3_free(zOld);
@@ -93161,6 +97958,7 @@ static void minmaxStep(
sqlite3SkipAccumulatorLoad(context);
}
}else{
+ pBest->db = sqlite3_context_db_handle(context);
sqlite3VdbeMemCopy(pBest, pArg);
}
}
@@ -93193,8 +97991,7 @@ static void groupConcatStep(
if( pAccum ){
sqlite3 *db = sqlite3_context_db_handle(context);
- int firstTerm = pAccum->useMalloc==0;
- pAccum->useMalloc = 2;
+ int firstTerm = pAccum->mxAlloc==0;
pAccum->mxAlloc = db->aLimit[SQLITE_LIMIT_LENGTH];
if( !firstTerm ){
if( argc==2 ){
@@ -93278,6 +98075,11 @@ SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive)
** then set aWc[0] through aWc[2] to the wildcard characters and
** return TRUE. If the function is not a LIKE-style function then
** return FALSE.
+**
+** *pIsNocase is set to true if uppercase and lowercase are equivalent for
+** the function (default for LIKE). If the function makes the distinction
+** between uppercase and lowercase (as does GLOB) then *pIsNocase is set to
+** false.
*/
SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
FuncDef *pDef;
@@ -93308,7 +98110,7 @@ SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocas
}
/*
-** All all of the FuncDef structures in the aBuiltinFunc[] array above
+** All of the FuncDef structures in the aBuiltinFunc[] array above
** to the global function hash table. This occurs at start-time (as
** a consequence of calling sqlite3_initialize()).
**
@@ -93332,10 +98134,12 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
FUNCTION(trim, 2, 3, 0, trimFunc ),
FUNCTION(min, -1, 0, 1, minmaxFunc ),
FUNCTION(min, 0, 0, 1, 0 ),
- AGGREGATE(min, 1, 0, 1, minmaxStep, minMaxFinalize ),
+ AGGREGATE2(min, 1, 0, 1, minmaxStep, minMaxFinalize,
+ SQLITE_FUNC_MINMAX ),
FUNCTION(max, -1, 1, 1, minmaxFunc ),
FUNCTION(max, 0, 1, 1, 0 ),
- AGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize ),
+ AGGREGATE2(max, 1, 1, 1, minmaxStep, minMaxFinalize,
+ SQLITE_FUNC_MINMAX ),
FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF),
FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH),
FUNCTION(instr, 2, 0, 0, instrFunc ),
@@ -93365,6 +98169,9 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
FUNCTION(sqlite_version, 0, 0, 0, versionFunc ),
FUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ),
FUNCTION(sqlite_log, 2, 0, 0, errlogFunc ),
+#if SQLITE_USER_AUTHENTICATION
+ FUNCTION(sqlite_crypt, 2, 0, 0, sqlite3CryptFunc ),
+#endif
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
FUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ),
FUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ),
@@ -93385,8 +98192,8 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
AGGREGATE(sum, 1, 0, 0, sumStep, sumFinalize ),
AGGREGATE(total, 1, 0, 0, sumStep, totalFinalize ),
AGGREGATE(avg, 1, 0, 0, sumStep, avgFinalize ),
- /* AGGREGATE(count, 0, 0, 0, countStep, countFinalize ), */
- {0,SQLITE_UTF8|SQLITE_FUNC_COUNT,0,0,0,countStep,countFinalize,"count",0,0},
+ AGGREGATE2(count, 0, 0, 0, countStep, countFinalize,
+ SQLITE_FUNC_COUNT ),
AGGREGATE(count, 1, 0, 0, countStep, countFinalize ),
AGGREGATE(group_concat, 1, 0, 0, groupConcatStep, groupConcatFinalize),
AGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize),
@@ -93593,7 +98400,7 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
**
** 4) No parent key columns were provided explicitly as part of the
** foreign key definition, and the PRIMARY KEY of the parent table
-** consists of a a different number of columns to the child key in
+** consists of a different number of columns to the child key in
** the child table.
**
** then non-zero is returned, and a "foreign key mismatch" error loaded
@@ -93857,7 +98664,7 @@ static void fkLookupParent(
OE_Abort, 0, P4_STATIC, P5_ConstraintFK);
}else{
if( nIncr>0 && pFKey->isDeferred==0 ){
- sqlite3ParseToplevel(pParse)->mayAbort = 1;
+ sqlite3MayAbort(pParse);
}
sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr);
}
@@ -93929,6 +98736,10 @@ static Expr *exprTableColumn(
** code for an SQL UPDATE operation, this function may be called twice -
** once to "delete" the old row and once to "insert" the new row.
**
+** Parameter nIncr is passed -1 when inserting a row (as this may decrease
+** the number of FK violations in the db) or +1 when deleting one (as this
+** may increase the number of FK constraint problems).
+**
** The code generated by this function scans through the rows in the child
** table that correspond to the parent table row being deleted or inserted.
** For each child row found, one of the following actions is taken:
@@ -94045,13 +98856,9 @@ static void fkScanChildren(
sqlite3ResolveExprNames(&sNameContext, pWhere);
/* Create VDBE to loop through the entries in pSrc that match the WHERE
- ** clause. If the constraint is not deferred, throw an exception for
- ** each row found. Otherwise, for deferred constraints, increment the
- ** deferred constraint counter by nIncr for each row selected. */
+ ** clause. For each row found, increment either the deferred or immediate
+ ** foreign key constraint counter. */
pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0);
- if( nIncr>0 && pFKey->isDeferred==0 ){
- sqlite3ParseToplevel(pParse)->mayAbort = 1;
- }
sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr);
if( pWInfo ){
sqlite3WhereEnd(pWInfo);
@@ -94079,8 +98886,7 @@ static void fkScanChildren(
** table).
*/
SQLITE_PRIVATE FKey *sqlite3FkReferences(Table *pTab){
- int nName = sqlite3Strlen30(pTab->zName);
- return (FKey *)sqlite3HashFind(&pTab->pSchema->fkeyHash, pTab->zName, nName);
+ return (FKey *)sqlite3HashFind(&pTab->pSchema->fkeyHash, pTab->zName);
}
/*
@@ -94232,6 +99038,24 @@ static int fkParentIsModified(
}
/*
+** Return true if the parser passed as the first argument is being
+** used to code a trigger that is really a "SET NULL" action belonging
+** to trigger pFKey.
+*/
+static int isSetNullAction(Parse *pParse, FKey *pFKey){
+ Parse *pTop = sqlite3ParseToplevel(pParse);
+ if( pTop->pTriggerPrg ){
+ Trigger *p = pTop->pTriggerPrg->pTrigger;
+ if( (p==pFKey->apTrigger[0] && pFKey->aAction[0]==OE_SetNull)
+ || (p==pFKey->apTrigger[1] && pFKey->aAction[1]==OE_SetNull)
+ ){
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
** This function is called when inserting, deleting or updating a row of
** table pTab to generate VDBE code to perform foreign key constraint
** processing for the operation.
@@ -94283,7 +99107,7 @@ SQLITE_PRIVATE void sqlite3FkCheck(
int *aiCol;
int iCol;
int i;
- int isIgnore = 0;
+ int bIgnore = 0;
if( aChange
&& sqlite3_stricmp(pTab->zName, pFKey->zTo)!=0
@@ -94342,7 +99166,7 @@ SQLITE_PRIVATE void sqlite3FkCheck(
int rcauth;
char *zCol = pTo->aCol[pIdx ? pIdx->aiColumn[i] : pTo->iPKey].zName;
rcauth = sqlite3AuthReadCol(pParse, pTo->zName, zCol, iDb);
- isIgnore = (rcauth==SQLITE_IGNORE);
+ bIgnore = (rcauth==SQLITE_IGNORE);
}
#endif
}
@@ -94357,12 +99181,18 @@ SQLITE_PRIVATE void sqlite3FkCheck(
/* A row is being removed from the child table. Search for the parent.
** If the parent does not exist, removing the child row resolves an
** outstanding foreign key constraint violation. */
- fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regOld, -1,isIgnore);
+ fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regOld, -1, bIgnore);
}
- if( regNew!=0 ){
+ if( regNew!=0 && !isSetNullAction(pParse, pFKey) ){
/* A row is being added to the child table. If a parent row cannot
- ** be found, adding the child row has violated the FK constraint. */
- fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regNew, +1,isIgnore);
+ ** be found, adding the child row has violated the FK constraint.
+ **
+ ** If this operation is being performed as part of a trigger program
+ ** that is actually a "SET NULL" action belonging to this very
+ ** foreign key, then omit this scan altogether. As all child key
+ ** values are guaranteed to be NULL, it is not possible for adding
+ ** this row to cause an FK violation. */
+ fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regNew, +1, bIgnore);
}
sqlite3DbFree(db, aiFree);
@@ -94383,8 +99213,8 @@ SQLITE_PRIVATE void sqlite3FkCheck(
&& !pParse->pToplevel && !pParse->isMultiWrite
){
assert( regOld==0 && regNew!=0 );
- /* Inserting a single row into a parent table cannot cause an immediate
- ** foreign key violation. So do nothing in this case. */
+ /* Inserting a single row into a parent table cannot cause (or fix)
+ ** an immediate foreign key violation. So do nothing in this case. */
continue;
}
@@ -94408,13 +99238,28 @@ SQLITE_PRIVATE void sqlite3FkCheck(
fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regNew, -1);
}
if( regOld!=0 ){
- /* If there is a RESTRICT action configured for the current operation
- ** on the parent table of this FK, then throw an exception
- ** immediately if the FK constraint is violated, even if this is a
- ** deferred trigger. That's what RESTRICT means. To defer checking
- ** the constraint, the FK should specify NO ACTION (represented
- ** using OE_None). NO ACTION is the default. */
+ int eAction = pFKey->aAction[aChange!=0];
fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regOld, 1);
+ /* If this is a deferred FK constraint, or a CASCADE or SET NULL
+ ** action applies, then any foreign key violations caused by
+ ** removing the parent key will be rectified by the action trigger.
+ ** So do not set the "may-abort" flag in this case.
+ **
+ ** Note 1: If the FK is declared "ON UPDATE CASCADE", then the
+ ** may-abort flag will eventually be set on this statement anyway
+ ** (when this function is called as part of processing the UPDATE
+ ** within the action trigger).
+ **
+ ** Note 2: At first glance it may seem like SQLite could simply omit
+ ** all OP_FkCounter related scans when either CASCADE or SET NULL
+ ** applies. The trouble starts if the CASCADE or SET NULL action
+ ** trigger causes other triggers or action rules attached to the
+ ** child table to fire. In these cases the fk constraint counters
+ ** might be set incorrectly if any OP_FkCounter related scans are
+ ** omitted. */
+ if( !pFKey->isDeferred && eAction!=OE_Cascade && eAction!=OE_SetNull ){
+ sqlite3MayAbort(pParse);
+ }
}
pItem->zName = 0;
sqlite3SrcListDelete(db, pSrc);
@@ -94566,7 +99411,8 @@ static Trigger *fkActionTrigger(
iFromCol = aiCol ? aiCol[i] : pFKey->aCol[0].iFrom;
assert( iFromCol>=0 );
- tToCol.z = pIdx ? pTab->aCol[pIdx->aiColumn[i]].zName : "oid";
+ assert( pIdx!=0 || (pTab->iPKey>=0 && pTab->iPKey<pTab->nCol) );
+ tToCol.z = pTab->aCol[pIdx ? pIdx->aiColumn[i] : pTab->iPKey].zName;
tFromCol.z = pFKey->pFrom->aCol[iFromCol].zName;
tToCol.n = sqlite3Strlen30(tToCol.z);
@@ -94578,10 +99424,10 @@ static Trigger *fkActionTrigger(
** parent table are used for the comparison. */
pEq = sqlite3PExpr(pParse, TK_EQ,
sqlite3PExpr(pParse, TK_DOT,
- sqlite3PExpr(pParse, TK_ID, 0, 0, &tOld),
- sqlite3PExpr(pParse, TK_ID, 0, 0, &tToCol)
+ sqlite3ExprAlloc(db, TK_ID, &tOld, 0),
+ sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)
, 0),
- sqlite3PExpr(pParse, TK_ID, 0, 0, &tFromCol)
+ sqlite3ExprAlloc(db, TK_ID, &tFromCol, 0)
, 0);
pWhere = sqlite3ExprAnd(db, pWhere, pEq);
@@ -94593,12 +99439,12 @@ static Trigger *fkActionTrigger(
if( pChanges ){
pEq = sqlite3PExpr(pParse, TK_IS,
sqlite3PExpr(pParse, TK_DOT,
- sqlite3PExpr(pParse, TK_ID, 0, 0, &tOld),
- sqlite3PExpr(pParse, TK_ID, 0, 0, &tToCol),
+ sqlite3ExprAlloc(db, TK_ID, &tOld, 0),
+ sqlite3ExprAlloc(db, TK_ID, &tToCol, 0),
0),
sqlite3PExpr(pParse, TK_DOT,
- sqlite3PExpr(pParse, TK_ID, 0, 0, &tNew),
- sqlite3PExpr(pParse, TK_ID, 0, 0, &tToCol),
+ sqlite3ExprAlloc(db, TK_ID, &tNew, 0),
+ sqlite3ExprAlloc(db, TK_ID, &tToCol, 0),
0),
0);
pWhen = sqlite3ExprAnd(db, pWhen, pEq);
@@ -94608,8 +99454,8 @@ static Trigger *fkActionTrigger(
Expr *pNew;
if( action==OE_Cascade ){
pNew = sqlite3PExpr(pParse, TK_DOT,
- sqlite3PExpr(pParse, TK_ID, 0, 0, &tNew),
- sqlite3PExpr(pParse, TK_ID, 0, 0, &tToCol)
+ sqlite3ExprAlloc(db, TK_ID, &tNew, 0),
+ sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)
, 0);
}else if( action==OE_SetDflt ){
Expr *pDflt = pFKey->pFrom->aCol[iFromCol].pDflt;
@@ -94656,13 +99502,12 @@ static Trigger *fkActionTrigger(
pTrigger = (Trigger *)sqlite3DbMallocZero(db,
sizeof(Trigger) + /* struct Trigger */
sizeof(TriggerStep) + /* Single step in trigger program */
- nFrom + 1 /* Space for pStep->target.z */
+ nFrom + 1 /* Space for pStep->zTarget */
);
if( pTrigger ){
pStep = pTrigger->step_list = (TriggerStep *)&pTrigger[1];
- pStep->target.z = (char *)&pStep[1];
- pStep->target.n = nFrom;
- memcpy((char *)pStep->target.z, zFrom, nFrom);
+ pStep->zTarget = (char *)&pStep[1];
+ memcpy((char *)pStep->zTarget, zFrom, nFrom);
pStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
pStep->pExprList = sqlite3ExprListDup(db, pList, EXPRDUP_REDUCE);
@@ -94758,7 +99603,7 @@ SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *db, Table *pTab){
}else{
void *p = (void *)pFKey->pNextTo;
const char *z = (p ? pFKey->pNextTo->zTo : pFKey->zTo);
- sqlite3HashInsert(&pTab->pSchema->fkeyHash, z, sqlite3Strlen30(z), p);
+ sqlite3HashInsert(&pTab->pSchema->fkeyHash, z, p);
}
if( pFKey->pNextTo ){
pFKey->pNextTo->pPrevTo = pFKey->pPrevTo;
@@ -94841,13 +99686,13 @@ SQLITE_PRIVATE void sqlite3OpenTable(
**
** Character Column affinity
** ------------------------------
-** 'a' TEXT
-** 'b' NONE
-** 'c' NUMERIC
-** 'd' INTEGER
-** 'e' REAL
+** 'A' NONE
+** 'B' TEXT
+** 'C' NUMERIC
+** 'D' INTEGER
+** 'F' REAL
**
-** An extra 'd' is appended to the end of the string to cover the
+** An extra 'D' is appended to the end of the string to cover the
** rowid that appears as the last column in every index.
**
** Memory for the buffer containing the column index affinity string
@@ -94896,11 +99741,11 @@ SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
**
** Character Column affinity
** ------------------------------
-** 'a' TEXT
-** 'b' NONE
-** 'c' NUMERIC
-** 'd' INTEGER
-** 'e' REAL
+** 'A' NONE
+** 'B' TEXT
+** 'C' NUMERIC
+** 'D' INTEGER
+** 'E' REAL
*/
SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
int i;
@@ -95127,20 +99972,23 @@ static int xferOptimization(
/*
** This routine is called to handle SQL of the following forms:
**
-** insert into TABLE (IDLIST) values(EXPRLIST)
+** insert into TABLE (IDLIST) values(EXPRLIST),(EXPRLIST),...
** insert into TABLE (IDLIST) select
+** insert into TABLE (IDLIST) default values
**
** The IDLIST following the table name is always optional. If omitted,
-** then a list of all columns for the table is substituted. The IDLIST
-** appears in the pColumn parameter. pColumn is NULL if IDLIST is omitted.
+** then a list of all (non-hidden) columns for the table is substituted.
+** The IDLIST appears in the pColumn parameter. pColumn is NULL if IDLIST
+** is omitted.
**
-** The pList parameter holds EXPRLIST in the first form of the INSERT
-** statement above, and pSelect is NULL. For the second form, pList is
-** NULL and pSelect is a pointer to the select statement used to generate
-** data for the insert.
+** For the pSelect parameter holds the values to be inserted for the
+** first two forms shown above. A VALUES clause is really just short-hand
+** for a SELECT statement that omits the FROM clause and everything else
+** that follows. If the pSelect parameter is NULL, that means that the
+** DEFAULT VALUES form of the INSERT statement is intended.
**
** The code generated follows one of four templates. For a simple
-** insert with data coming from a VALUES clause, the code executes
+** insert with data coming from a single-row VALUES clause, the code executes
** once straight down through. Pseudo-code follows (we call this
** the "1st template"):
**
@@ -95195,7 +100043,7 @@ static int xferOptimization(
** The 4th template is used if the insert statement takes its
** values from a SELECT but the data is being inserted into a table
** that is also read as part of the SELECT. In the third form,
-** we have to use a intermediate table to store the results of
+** we have to use an intermediate table to store the results of
** the select. The template is like this:
**
** X <- A
@@ -95247,7 +100095,7 @@ SQLITE_PRIVATE void sqlite3Insert(
u8 useTempTable = 0; /* Store SELECT results in intermediate table */
u8 appendFlag = 0; /* True if the insert is likely to be an append */
u8 withoutRowid; /* 0 for normal table. 1 for WITHOUT ROWID table */
- u8 bIdListInOrder = 1; /* True if IDLIST is in table order */
+ u8 bIdListInOrder; /* True if IDLIST is in table order */
ExprList *pList = 0; /* List of VALUES() to be inserted */
/* Register allocations */
@@ -95272,8 +100120,8 @@ SQLITE_PRIVATE void sqlite3Insert(
}
/* If the Select object is really just a simple VALUES() list with a
- ** single row values (the common case) then keep that one row of values
- ** and go ahead and discard the Select object
+ ** single row (the common case) then keep that one row of values
+ ** and discard the other (unused) parts of the pSelect object
*/
if( pSelect && (pSelect->selFlags & SF_Values)!=0 && pSelect->pPrior==0 ){
pList = pSelect->pEList;
@@ -95360,7 +100208,7 @@ SQLITE_PRIVATE void sqlite3Insert(
regAutoinc = autoIncBegin(pParse, iDb, pTab);
/* Allocate registers for holding the rowid of the new row,
- ** the content of the new row, and the assemblied row record.
+ ** the content of the new row, and the assembled row record.
*/
regRowid = regIns = pParse->nMem+1;
pParse->nMem += pTab->nCol + 1;
@@ -95381,6 +100229,7 @@ SQLITE_PRIVATE void sqlite3Insert(
** is appears in the original table. (The index of the INTEGER
** PRIMARY KEY in the original table is pTab->iPKey.)
*/
+ bIdListInOrder = (pTab->tabFlags & TF_OOOHidden)==0;
if( pColumn ){
for(i=0; i<pColumn->nId; i++){
pColumn->a[i].idx = -1;
@@ -95416,7 +100265,8 @@ SQLITE_PRIVATE void sqlite3Insert(
** co-routine is the common header to the 3rd and 4th templates.
*/
if( pSelect ){
- /* Data is coming from a SELECT. Generate a co-routine to run the SELECT */
+ /* Data is coming from a SELECT or from a multi-row VALUES clause.
+ ** Generate a co-routine to run the SELECT. */
int regYield; /* Register holding co-routine entry-point */
int addrTop; /* Top of the co-routine */
int rc; /* Result code */
@@ -95429,8 +100279,7 @@ SQLITE_PRIVATE void sqlite3Insert(
dest.nSdst = pTab->nCol;
rc = sqlite3Select(pParse, pSelect, &dest);
regFromSelect = dest.iSdst;
- assert( pParse->nErr==0 || rc );
- if( rc || db->mallocFailed ) goto insert_cleanup;
+ if( rc || db->mallocFailed || pParse->nErr ) goto insert_cleanup;
sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield);
sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */
assert( pSelect->pEList );
@@ -95478,8 +100327,8 @@ SQLITE_PRIVATE void sqlite3Insert(
sqlite3ReleaseTempReg(pParse, regTempRowid);
}
}else{
- /* This is the case if the data for the INSERT is coming from a VALUES
- ** clause
+ /* This is the case if the data for the INSERT is coming from a
+ ** single-row VALUES clause
*/
NameContext sNC;
memset(&sNC, 0, sizeof(sNC));
@@ -95812,7 +100661,7 @@ insert_cleanup:
}
/* Make sure "isView" and other macros defined above are undefined. Otherwise
-** thely may interfere with compilation of other functions in this file
+** they may interfere with compilation of other functions in this file
** (or in another file, if this file becomes part of the amalgamation). */
#ifdef isView
#undef isView
@@ -95928,7 +100777,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
int ix; /* Index loop counter */
int nCol; /* Number of columns */
int onError; /* Conflict resolution strategy */
- int j1; /* Addresss of jump instruction */
+ int j1; /* Address of jump instruction */
int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */
int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */
int ipkTop = 0; /* Top of the rowid change constraint check */
@@ -96332,7 +101181,7 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion(
Index *pIdx; /* An index being inserted or updated */
u8 pik_flags; /* flag values passed to the btree insert */
int regData; /* Content registers (after the rowid) */
- int regRec; /* Register holding assemblied record for the table */
+ int regRec; /* Register holding assembled record for the table */
int i; /* Loop counter */
u8 bAffinityDone = 0; /* True if OP_Affinity has been run already */
@@ -96397,6 +101246,9 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion(
** For a WITHOUT ROWID table, *piDataCur will be somewhere in the range
** of *piIdxCurs, depending on where the PRIMARY KEY index appears on the
** pTab->pIndex list.
+**
+** If pTab is a virtual table, then this routine is a no-op and the
+** *piDataCur and *piIdxCur values are left uninitialized.
*/
SQLITE_PRIVATE int sqlite3OpenTableAndIndices(
Parse *pParse, /* Parsing context */
@@ -96415,9 +101267,9 @@ SQLITE_PRIVATE int sqlite3OpenTableAndIndices(
assert( op==OP_OpenRead || op==OP_OpenWrite );
if( IsVirtual(pTab) ){
- assert( aToOpen==0 );
- *piDataCur = 0;
- *piIdxCur = 1;
+ /* This routine is a no-op for virtual tables. Leave the output
+ ** variables *piDataCur and *piIdxCur uninitialized so that valgrind
+ ** can detect if they are used by mistake in the caller. */
return 0;
}
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
@@ -96454,7 +101306,7 @@ SQLITE_PRIVATE int sqlite3OpenTableAndIndices(
** The following global variable is incremented whenever the
** transfer optimization is used. This is used for testing
** purposes only - to make sure the transfer optimization really
-** is happening when it is suppose to.
+** is happening when it is supposed to.
*/
SQLITE_API int sqlite3_xferopt_count;
#endif /* SQLITE_TEST */
@@ -96521,7 +101373,7 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){
** INSERT INTO tab1 SELECT * FROM tab2;
**
** The xfer optimization transfers raw records from tab2 over to tab1.
-** Columns are not decoded and reassemblied, which greatly improves
+** Columns are not decoded and reassembled, which greatly improves
** performance. Raw index records are transferred in the same way.
**
** The xfer optimization is only attempted if tab1 and tab2 are compatible.
@@ -96547,6 +101399,7 @@ static int xferOptimization(
int onError, /* How to handle constraint errors */
int iDbDest /* The database of pDest */
){
+ sqlite3 *db = pParse->db;
ExprList *pEList; /* The result set of the SELECT */
Table *pSrc; /* The table in the FROM clause of SELECT */
Index *pSrcIdx, *pDestIdx; /* Source and destination indices */
@@ -96694,11 +101547,11 @@ static int xferOptimization(
** the extra complication to make this rule less restrictive is probably
** not worth the effort. Ticket [6284df89debdfa61db8073e062908af0c9b6118e]
*/
- if( (pParse->db->flags & SQLITE_ForeignKeys)!=0 && pDest->pFKey!=0 ){
+ if( (db->flags & SQLITE_ForeignKeys)!=0 && pDest->pFKey!=0 ){
return 0;
}
#endif
- if( (pParse->db->flags & SQLITE_CountRows)!=0 ){
+ if( (db->flags & SQLITE_CountRows)!=0 ){
return 0; /* xfer opt does not play well with PRAGMA count_changes */
}
@@ -96709,7 +101562,7 @@ static int xferOptimization(
#ifdef SQLITE_TEST
sqlite3_xferopt_count++;
#endif
- iDbSrc = sqlite3SchemaToIndex(pParse->db, pSrc->pSchema);
+ iDbSrc = sqlite3SchemaToIndex(db, pSrc->pSchema);
v = sqlite3GetVdbe(pParse);
sqlite3CodeVerifySchema(pParse, iDbSrc);
iSrc = pParse->nTab++;
@@ -96719,14 +101572,18 @@ static int xferOptimization(
regRowid = sqlite3GetTempReg(pParse);
sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite);
assert( HasRowid(pDest) || destHasUniqueIdx );
- if( (pDest->iPKey<0 && pDest->pIndex!=0) /* (1) */
+ if( (db->flags & SQLITE_Vacuum)==0 && (
+ (pDest->iPKey<0 && pDest->pIndex!=0) /* (1) */
|| destHasUniqueIdx /* (2) */
|| (onError!=OE_Abort && onError!=OE_Rollback) /* (3) */
- ){
+ )){
/* In some circumstances, we are able to run the xfer optimization
- ** only if the destination table is initially empty. This code makes
- ** that determination. Conditions under which the destination must
- ** be empty:
+ ** only if the destination table is initially empty. Unless the
+ ** SQLITE_Vacuum flag is set, this block generates code to make
+ ** that determination. If SQLITE_Vacuum is set, then the destination
+ ** table is always empty.
+ **
+ ** Conditions under which the destination must be empty:
**
** (1) There is no INTEGER PRIMARY KEY but there are indices.
** (If the destination is not initially empty, the rowid fields
@@ -96769,6 +101626,7 @@ static int xferOptimization(
sqlite3TableLock(pParse, iDbSrc, pSrc->tnum, 0, pSrc->zName);
}
for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
+ u8 useSeekResult = 0;
for(pSrcIdx=pSrc->pIndex; ALWAYS(pSrcIdx); pSrcIdx=pSrcIdx->pNext){
if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break;
}
@@ -96782,7 +101640,33 @@ static int xferOptimization(
VdbeComment((v, "%s", pDestIdx->zName));
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_RowKey, iSrc, regData);
+ if( db->flags & SQLITE_Vacuum ){
+ /* This INSERT command is part of a VACUUM operation, which guarantees
+ ** that the destination table is empty. If all indexed columns use
+ ** collation sequence BINARY, then it can also be assumed that the
+ ** index will be populated by inserting keys in strictly sorted
+ ** order. In this case, instead of seeking within the b-tree as part
+ ** of every OP_IdxInsert opcode, an OP_Last is added before the
+ ** OP_IdxInsert to seek to the point within the b-tree where each key
+ ** should be inserted. This is faster.
+ **
+ ** If any of the indexed columns use a collation sequence other than
+ ** BINARY, this optimization is disabled. This is because the user
+ ** might change the definition of a collation sequence and then run
+ ** a VACUUM command. In that case keys may not be written in strictly
+ ** sorted order. */
+ for(i=0; i<pSrcIdx->nColumn; i++){
+ char *zColl = pSrcIdx->azColl[i];
+ assert( zColl!=0 );
+ if( sqlite3_stricmp("BINARY", zColl) ) break;
+ }
+ if( i==pSrcIdx->nColumn ){
+ useSeekResult = OPFLAG_USESEEKRESULT;
+ sqlite3VdbeAddOp3(v, OP_Last, iDest, 0, -1);
+ }
+ }
sqlite3VdbeAddOp3(v, OP_IdxInsert, iDest, regData, 1);
+ sqlite3VdbeChangeP5(v, useSeekResult);
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1); VdbeCoverage(v);
sqlite3VdbeJumpHere(v, addr1);
sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
@@ -96832,7 +101716,7 @@ static int xferOptimization(
** argument to xCallback(). If xCallback=NULL then no callback
** is invoked, even for queries.
*/
-SQLITE_API int sqlite3_exec(
+SQLITE_API int SQLITE_STDCALL sqlite3_exec(
sqlite3 *db, /* The database on which the SQL executes */
const char *zSql, /* The SQL to be executed */
sqlite3_callback xCallback, /* Invoke this callback routine */
@@ -96849,7 +101733,7 @@ SQLITE_API int sqlite3_exec(
if( zSql==0 ) zSql = "";
sqlite3_mutex_enter(db->mutex);
- sqlite3Error(db, SQLITE_OK, 0);
+ sqlite3Error(db, SQLITE_OK);
while( rc==SQLITE_OK && zSql[0] ){
int nCol;
char **azVals = 0;
@@ -96907,7 +101791,7 @@ SQLITE_API int sqlite3_exec(
rc = SQLITE_ABORT;
sqlite3VdbeFinalize((Vdbe *)pStmt);
pStmt = 0;
- sqlite3Error(db, SQLITE_ABORT, 0);
+ sqlite3Error(db, SQLITE_ABORT);
goto exec_out;
}
}
@@ -96930,14 +101814,14 @@ exec_out:
sqlite3DbFree(db, azCols);
rc = sqlite3ApiExit(db, rc);
- if( rc!=SQLITE_OK && ALWAYS(rc==sqlite3_errcode(db)) && pzErrMsg ){
+ if( rc!=SQLITE_OK && pzErrMsg ){
int nErrMsg = 1 + sqlite3Strlen30(sqlite3_errmsg(db));
*pzErrMsg = sqlite3Malloc(nErrMsg);
if( *pzErrMsg ){
memcpy(*pzErrMsg, sqlite3_errmsg(db), nErrMsg);
}else{
rc = SQLITE_NOMEM;
- sqlite3Error(db, SQLITE_NOMEM, 0);
+ sqlite3Error(db, SQLITE_NOMEM);
}
}else if( pzErrMsg ){
*pzErrMsg = 0;
@@ -96999,7 +101883,7 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
** WARNING: In order to maintain backwards compatibility, add new
** interfaces to the end of this structure only. If you insert new
** interfaces in the middle of this structure, then older different
-** versions of SQLite will not be able to load each others' shared
+** versions of SQLite will not be able to load each other's shared
** libraries!
*/
struct sqlite3_api_routines {
@@ -97221,11 +102105,28 @@ struct sqlite3_api_routines {
const char *(*uri_parameter)(const char*,const char*);
char *(*vsnprintf)(int,char*,const char*,va_list);
int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
+ /* Version 3.8.7 and later */
+ int (*auto_extension)(void(*)(void));
+ int (*bind_blob64)(sqlite3_stmt*,int,const void*,sqlite3_uint64,
+ void(*)(void*));
+ int (*bind_text64)(sqlite3_stmt*,int,const char*,sqlite3_uint64,
+ void(*)(void*),unsigned char);
+ int (*cancel_auto_extension)(void(*)(void));
+ int (*load_extension)(sqlite3*,const char*,const char*,char**);
+ void *(*malloc64)(sqlite3_uint64);
+ sqlite3_uint64 (*msize)(void*);
+ void *(*realloc64)(void*,sqlite3_uint64);
+ void (*reset_auto_extension)(void);
+ void (*result_blob64)(sqlite3_context*,const void*,sqlite3_uint64,
+ void(*)(void*));
+ void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64,
+ void(*)(void*), unsigned char);
+ int (*strglob)(const char*,const char*);
};
/*
** The following macros redefine the API routines so that they are
-** redirected throught the global sqlite3_api structure.
+** redirected through the global sqlite3_api structure.
**
** This header file is also used by the loadext.c source file
** (part of the main SQLite library - not an extension) so that
@@ -97438,6 +102339,19 @@ struct sqlite3_api_routines {
#define sqlite3_uri_parameter sqlite3_api->uri_parameter
#define sqlite3_uri_vsnprintf sqlite3_api->vsnprintf
#define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2
+/* Version 3.8.7 and later */
+#define sqlite3_auto_extension sqlite3_api->auto_extension
+#define sqlite3_bind_blob64 sqlite3_api->bind_blob64
+#define sqlite3_bind_text64 sqlite3_api->bind_text64
+#define sqlite3_cancel_auto_extension sqlite3_api->cancel_auto_extension
+#define sqlite3_load_extension sqlite3_api->load_extension
+#define sqlite3_malloc64 sqlite3_api->malloc64
+#define sqlite3_msize sqlite3_api->msize
+#define sqlite3_realloc64 sqlite3_api->realloc64
+#define sqlite3_reset_auto_extension sqlite3_api->reset_auto_extension
+#define sqlite3_result_blob64 sqlite3_api->result_blob64
+#define sqlite3_result_text64 sqlite3_api->result_text64
+#define sqlite3_strglob sqlite3_api->strglob
#endif /* SQLITE_CORE */
#ifndef SQLITE_CORE
@@ -97475,7 +102389,6 @@ struct sqlite3_api_routines {
# define sqlite3_column_table_name16 0
# define sqlite3_column_origin_name 0
# define sqlite3_column_origin_name16 0
-# define sqlite3_table_column_metadata 0
#endif
#ifdef SQLITE_OMIT_AUTHORIZATION
@@ -97831,7 +102744,20 @@ static const sqlite3_api_routines sqlite3Apis = {
sqlite3_uri_int64,
sqlite3_uri_parameter,
sqlite3_vsnprintf,
- sqlite3_wal_checkpoint_v2
+ sqlite3_wal_checkpoint_v2,
+ /* Version 3.8.7 and later */
+ sqlite3_auto_extension,
+ sqlite3_bind_blob64,
+ sqlite3_bind_text64,
+ sqlite3_cancel_auto_extension,
+ sqlite3_load_extension,
+ sqlite3_malloc64,
+ sqlite3_msize,
+ sqlite3_realloc64,
+ sqlite3_reset_auto_extension,
+ sqlite3_result_blob64,
+ sqlite3_result_text64,
+ sqlite3_strglob
};
/*
@@ -97859,7 +102785,7 @@ static int sqlite3LoadExtension(
const char *zEntry;
char *zAltEntry = 0;
void **aHandle;
- int nMsg = 300 + sqlite3Strlen30(zFile);
+ u64 nMsg = 300 + sqlite3Strlen30(zFile);
int ii;
/* Shared library endings to try if zFile cannot be loaded as written */
@@ -97902,7 +102828,7 @@ static int sqlite3LoadExtension(
#endif
if( handle==0 ){
if( pzErrMsg ){
- *pzErrMsg = zErrmsg = sqlite3_malloc(nMsg);
+ *pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg);
if( zErrmsg ){
sqlite3_snprintf(nMsg, zErrmsg,
"unable to open shared library [%s]", zFile);
@@ -97928,7 +102854,7 @@ static int sqlite3LoadExtension(
if( xInit==0 && zProc==0 ){
int iFile, iEntry, c;
int ncFile = sqlite3Strlen30(zFile);
- zAltEntry = sqlite3_malloc(ncFile+30);
+ zAltEntry = sqlite3_malloc64(ncFile+30);
if( zAltEntry==0 ){
sqlite3OsDlClose(pVfs, handle);
return SQLITE_NOMEM;
@@ -97950,7 +102876,7 @@ static int sqlite3LoadExtension(
if( xInit==0 ){
if( pzErrMsg ){
nMsg += sqlite3Strlen30(zEntry);
- *pzErrMsg = zErrmsg = sqlite3_malloc(nMsg);
+ *pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg);
if( zErrmsg ){
sqlite3_snprintf(nMsg, zErrmsg,
"no entry point [%s] in shared library [%s]", zEntry, zFile);
@@ -97985,7 +102911,7 @@ static int sqlite3LoadExtension(
db->aExtension[db->nExtension++] = handle;
return SQLITE_OK;
}
-SQLITE_API int sqlite3_load_extension(
+SQLITE_API int SQLITE_STDCALL sqlite3_load_extension(
sqlite3 *db, /* Load the extension into this database connection */
const char *zFile, /* Name of the shared library containing extension */
const char *zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */
@@ -98016,7 +102942,7 @@ SQLITE_PRIVATE void sqlite3CloseExtensions(sqlite3 *db){
** Enable or disable extension loading. Extension loading is disabled by
** default so as not to open security holes in older applications.
*/
-SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff){
+SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int onoff){
sqlite3_mutex_enter(db->mutex);
if( onoff ){
db->flags |= SQLITE_LoadExtension;
@@ -98049,7 +102975,7 @@ static const sqlite3_api_routines sqlite3Apis = { 0 };
*/
typedef struct sqlite3AutoExtList sqlite3AutoExtList;
static SQLITE_WSD struct sqlite3AutoExtList {
- int nExt; /* Number of entries in aExt[] */
+ u32 nExt; /* Number of entries in aExt[] */
void (**aExt)(void); /* Pointers to the extension init functions */
} sqlite3Autoext = { 0, 0 };
@@ -98073,7 +102999,7 @@ static SQLITE_WSD struct sqlite3AutoExtList {
** Register a statically linked extension that is automatically
** loaded by every new database connection.
*/
-SQLITE_API int sqlite3_auto_extension(void (*xInit)(void)){
+SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xInit)(void)){
int rc = SQLITE_OK;
#ifndef SQLITE_OMIT_AUTOINIT
rc = sqlite3_initialize();
@@ -98082,7 +103008,7 @@ SQLITE_API int sqlite3_auto_extension(void (*xInit)(void)){
}else
#endif
{
- int i;
+ u32 i;
#if SQLITE_THREADSAFE
sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
#endif
@@ -98092,9 +103018,9 @@ SQLITE_API int sqlite3_auto_extension(void (*xInit)(void)){
if( wsdAutoext.aExt[i]==xInit ) break;
}
if( i==wsdAutoext.nExt ){
- int nByte = (wsdAutoext.nExt+1)*sizeof(wsdAutoext.aExt[0]);
+ u64 nByte = (wsdAutoext.nExt+1)*sizeof(wsdAutoext.aExt[0]);
void (**aNew)(void);
- aNew = sqlite3_realloc(wsdAutoext.aExt, nByte);
+ aNew = sqlite3_realloc64(wsdAutoext.aExt, nByte);
if( aNew==0 ){
rc = SQLITE_NOMEM;
}else{
@@ -98118,7 +103044,7 @@ SQLITE_API int sqlite3_auto_extension(void (*xInit)(void)){
** Return 1 if xInit was found on the list and removed. Return 0 if xInit
** was not on the list.
*/
-SQLITE_API int sqlite3_cancel_auto_extension(void (*xInit)(void)){
+SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xInit)(void)){
#if SQLITE_THREADSAFE
sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
#endif
@@ -98126,7 +103052,7 @@ SQLITE_API int sqlite3_cancel_auto_extension(void (*xInit)(void)){
int n = 0;
wsdAutoextInit;
sqlite3_mutex_enter(mutex);
- for(i=wsdAutoext.nExt-1; i>=0; i--){
+ for(i=(int)wsdAutoext.nExt-1; i>=0; i--){
if( wsdAutoext.aExt[i]==xInit ){
wsdAutoext.nExt--;
wsdAutoext.aExt[i] = wsdAutoext.aExt[wsdAutoext.nExt];
@@ -98141,7 +103067,7 @@ SQLITE_API int sqlite3_cancel_auto_extension(void (*xInit)(void)){
/*
** Reset the automatic extension loading mechanism.
*/
-SQLITE_API void sqlite3_reset_auto_extension(void){
+SQLITE_API void SQLITE_STDCALL sqlite3_reset_auto_extension(void){
#ifndef SQLITE_OMIT_AUTOINIT
if( sqlite3_initialize()==SQLITE_OK )
#endif
@@ -98164,7 +103090,7 @@ SQLITE_API void sqlite3_reset_auto_extension(void){
** If anything goes wrong, set an error in the database connection.
*/
SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){
- int i;
+ u32 i;
int go = 1;
int rc;
int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
@@ -98190,7 +103116,7 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){
sqlite3_mutex_leave(mutex);
zErrmsg = 0;
if( xInit && (rc = xInit(db, &zErrmsg, &sqlite3Apis))!=0 ){
- sqlite3Error(db, rc,
+ sqlite3ErrorWithMsg(db, rc,
"automatic extension loading failed: %s", zErrmsg);
go = 0;
}
@@ -98223,11 +103149,18 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){
#endif
/***************************************************************************
-** The next block of code, including the PragTyp_XXXX macro definitions and
-** the aPragmaName[] object is composed of generated code. DO NOT EDIT.
-**
-** To add new pragmas, edit the code in ../tool/mkpragmatab.tcl and rerun
-** that script. Then copy/paste the output in place of the following:
+** The "pragma.h" include file is an automatically generated file that
+** that includes the PragType_XXXX macro definitions and the aPragmaName[]
+** object. This ensures that the aPragmaName[] table is arranged in
+** lexicographical order to facility a binary search of the pragma name.
+** Do not edit pragma.h directly. Edit and rerun the script in at
+** ../tool/mkpragmatab.tcl. */
+/************** Include pragma.h in the middle of pragma.c *******************/
+/************** Begin file pragma.h ******************************************/
+/* DO NOT EDIT!
+** This file is automatically generated by the script at
+** ../tool/mkpragmatab.tcl. To update the set of pragmas, edit
+** that script and rerun it.
*/
#define PragTyp_HEADER_VALUE 0
#define PragTyp_AUTO_VACUUM 1
@@ -98262,15 +103195,17 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){
#define PragTyp_TABLE_INFO 30
#define PragTyp_TEMP_STORE 31
#define PragTyp_TEMP_STORE_DIRECTORY 32
-#define PragTyp_WAL_AUTOCHECKPOINT 33
-#define PragTyp_WAL_CHECKPOINT 34
-#define PragTyp_ACTIVATE_EXTENSIONS 35
-#define PragTyp_HEXKEY 36
-#define PragTyp_KEY 37
-#define PragTyp_REKEY 38
-#define PragTyp_LOCK_STATUS 39
-#define PragTyp_PARSER_TRACE 40
+#define PragTyp_THREADS 33
+#define PragTyp_WAL_AUTOCHECKPOINT 34
+#define PragTyp_WAL_CHECKPOINT 35
+#define PragTyp_ACTIVATE_EXTENSIONS 36
+#define PragTyp_HEXKEY 37
+#define PragTyp_KEY 38
+#define PragTyp_REKEY 39
+#define PragTyp_LOCK_STATUS 40
+#define PragTyp_PARSER_TRACE 41
#define PragFlag_NeedSchema 0x01
+#define PragFlag_ReadOnly 0x02
static const struct sPragmaNames {
const char *const zName; /* Name of pragma */
u8 ePragTyp; /* PragTyp_XXX value */
@@ -98287,7 +103222,7 @@ static const struct sPragmaNames {
{ /* zName: */ "application_id",
/* ePragTyp: */ PragTyp_HEADER_VALUE,
/* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ /* iArg: */ BTREE_APPLICATION_ID },
#endif
#if !defined(SQLITE_OMIT_AUTOVACUUM)
{ /* zName: */ "auto_vacuum",
@@ -98353,6 +103288,12 @@ static const struct sPragmaNames {
/* ePragFlag: */ 0,
/* iArg: */ 0 },
#endif
+#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
+ { /* zName: */ "data_version",
+ /* ePragTyp: */ PragTyp_HEADER_VALUE,
+ /* ePragFlag: */ PragFlag_ReadOnly,
+ /* iArg: */ BTREE_DATA_VERSION },
+#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
{ /* zName: */ "database_list",
/* ePragTyp: */ PragTyp_DATABASE_LIST,
@@ -98408,8 +103349,8 @@ static const struct sPragmaNames {
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
{ /* zName: */ "freelist_count",
/* ePragTyp: */ PragTyp_HEADER_VALUE,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ /* ePragFlag: */ PragFlag_ReadOnly,
+ /* iArg: */ BTREE_FREE_PAGE_COUNT },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
{ /* zName: */ "full_column_names",
@@ -98454,6 +103395,10 @@ static const struct sPragmaNames {
/* ePragTyp: */ PragTyp_INDEX_LIST,
/* ePragFlag: */ PragFlag_NeedSchema,
/* iArg: */ 0 },
+ { /* zName: */ "index_xinfo",
+ /* ePragTyp: */ PragTyp_INDEX_INFO,
+ /* ePragFlag: */ PragFlag_NeedSchema,
+ /* iArg: */ 1 },
#endif
#if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
{ /* zName: */ "integrity_check",
@@ -98561,7 +103506,7 @@ static const struct sPragmaNames {
{ /* zName: */ "schema_version",
/* ePragTyp: */ PragTyp_HEADER_VALUE,
/* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ /* iArg: */ BTREE_SCHEMA_VERSION },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
{ /* zName: */ "secure_delete",
@@ -98619,11 +103564,15 @@ static const struct sPragmaNames {
/* ePragFlag: */ 0,
/* iArg: */ 0 },
#endif
+ { /* zName: */ "threads",
+ /* ePragTyp: */ PragTyp_THREADS,
+ /* ePragFlag: */ 0,
+ /* iArg: */ 0 },
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
{ /* zName: */ "user_version",
/* ePragTyp: */ PragTyp_HEADER_VALUE,
/* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ /* iArg: */ BTREE_USER_VERSION },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
#if defined(SQLITE_DEBUG)
@@ -98666,9 +103615,10 @@ static const struct sPragmaNames {
/* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode },
#endif
};
-/* Number of pragmas: 56 on by default, 69 total. */
-/* End of the automatically generated pragma table.
-***************************************************************************/
+/* Number of pragmas: 59 on by default, 72 total. */
+
+/************** End of pragma.h **********************************************/
+/************** Continuing where we left off in pragma.c *********************/
/*
** Interpret the given string as a safety level. Return 0 for OFF,
@@ -98804,15 +103754,15 @@ static int changeTempStorage(Parse *pParse, const char *zStorageType){
*/
static void returnSingleInt(Parse *pParse, const char *zLabel, i64 value){
Vdbe *v = sqlite3GetVdbe(pParse);
- int mem = ++pParse->nMem;
+ int nMem = ++pParse->nMem;
i64 *pI64 = sqlite3DbMallocRaw(pParse->db, sizeof(value));
if( pI64 ){
memcpy(pI64, &value, sizeof(value));
}
- sqlite3VdbeAddOp4(v, OP_Int64, 0, mem, 0, (char*)pI64, P4_INT64);
+ sqlite3VdbeAddOp4(v, OP_Int64, 0, nMem, 0, (char*)pI64, P4_INT64);
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLabel, SQLITE_STATIC);
- sqlite3VdbeAddOp2(v, OP_ResultRow, mem, 1);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, nMem, 1);
}
@@ -98934,11 +103884,12 @@ SQLITE_PRIVATE void sqlite3Pragma(
Token *pId; /* Pointer to <id> token */
char *aFcntl[4]; /* Argument to SQLITE_FCNTL_PRAGMA */
int iDb; /* Database index for <database> */
- int lwr, upr, mid; /* Binary search bounds */
+ int lwr, upr, mid = 0; /* Binary search bounds */
int rc; /* return value form SQLITE_FCNTL_PRAGMA */
sqlite3 *db = pParse->db; /* The database connection */
Db *pDb; /* The specific database being pragmaed */
Vdbe *v = sqlite3GetVdbe(pParse); /* Prepared statement */
+ const struct sPragmaNames *pPragma;
if( v==0 ) return;
sqlite3VdbeRunOnlyOnce(v);
@@ -98974,6 +103925,17 @@ SQLITE_PRIVATE void sqlite3Pragma(
/* Send an SQLITE_FCNTL_PRAGMA file-control to the underlying VFS
** connection. If it returns SQLITE_OK, then assume that the VFS
** handled the pragma and generate a no-op prepared statement.
+ **
+ ** IMPLEMENTATION-OF: R-12238-55120 Whenever a PRAGMA statement is parsed,
+ ** an SQLITE_FCNTL_PRAGMA file control is sent to the open sqlite3_file
+ ** object corresponding to the database file to which the pragma
+ ** statement refers.
+ **
+ ** IMPLEMENTATION-OF: R-29875-31678 The argument to the SQLITE_FCNTL_PRAGMA
+ ** file control is an array of pointers to strings (char**) in which the
+ ** second element of the array is the name of the pragma and the third
+ ** element is the argument to the pragma or NULL if the pragma has no
+ ** argument.
*/
aFcntl[0] = 0;
aFcntl[1] = zLeft;
@@ -98983,11 +103945,11 @@ SQLITE_PRIVATE void sqlite3Pragma(
rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_PRAGMA, (void*)aFcntl);
if( rc==SQLITE_OK ){
if( aFcntl[0] ){
- int mem = ++pParse->nMem;
- sqlite3VdbeAddOp4(v, OP_String8, 0, mem, 0, aFcntl[0], 0);
+ int nMem = ++pParse->nMem;
+ sqlite3VdbeAddOp4(v, OP_String8, 0, nMem, 0, aFcntl[0], 0);
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "result", SQLITE_STATIC);
- sqlite3VdbeAddOp2(v, OP_ResultRow, mem, 1);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, nMem, 1);
sqlite3_free(aFcntl[0]);
}
goto pragma_out;
@@ -99016,14 +103978,15 @@ SQLITE_PRIVATE void sqlite3Pragma(
}
}
if( lwr>upr ) goto pragma_out;
+ pPragma = &aPragmaNames[mid];
/* Make sure the database schema is loaded if the pragma requires that */
- if( (aPragmaNames[mid].mPragFlag & PragFlag_NeedSchema)!=0 ){
+ if( (pPragma->mPragFlag & PragFlag_NeedSchema)!=0 ){
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
}
/* Jump to the appropriate pragma handler */
- switch( aPragmaNames[mid].ePragTyp ){
+ switch( pPragma->ePragTyp ){
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
/*
@@ -99591,7 +104554,9 @@ SQLITE_PRIVATE void sqlite3Pragma(
sqlite3ErrorMsg(pParse,
"Safety level may not be changed inside a transaction");
}else{
- pDb->safety_level = getSafetyLevel(zRight,0,1)+1;
+ int iLevel = (getSafetyLevel(zRight,0,1)+1) & PAGER_SYNCHRONOUS_MASK;
+ if( iLevel==0 ) iLevel = 1;
+ pDb->safety_level = iLevel;
setAllPagerFlags(db);
}
}
@@ -99602,15 +104567,20 @@ SQLITE_PRIVATE void sqlite3Pragma(
#ifndef SQLITE_OMIT_FLAG_PRAGMAS
case PragTyp_FLAG: {
if( zRight==0 ){
- returnSingleInt(pParse, aPragmaNames[mid].zName,
- (db->flags & aPragmaNames[mid].iArg)!=0 );
+ returnSingleInt(pParse, pPragma->zName, (db->flags & pPragma->iArg)!=0 );
}else{
- int mask = aPragmaNames[mid].iArg; /* Mask of bits to set or clear. */
+ int mask = pPragma->iArg; /* Mask of bits to set or clear. */
if( db->autoCommit==0 ){
/* Foreign key support may not be enabled or disabled while not
** in auto-commit mode. */
mask &= ~(SQLITE_ForeignKeys);
}
+#if SQLITE_USER_AUTHENTICATION
+ if( db->auth.authLevel==UAUTH_User ){
+ /* Do not allow non-admin users to modify the schema arbitrarily */
+ mask &= ~(SQLITE_WriteSchema);
+ }
+#endif
if( sqlite3GetBoolean(zRight, 0) ){
db->flags |= mask;
@@ -99729,7 +104699,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
}else if( pPk==0 ){
k = 1;
}else{
- for(k=1; ALWAYS(k<=pTab->nCol) && pPk->aiColumn[k-1]!=i; k++){}
+ for(k=1; k<=pTab->nCol && pPk->aiColumn[k-1]!=i; k++){}
}
sqlite3VdbeAddOp2(v, OP_Integer, k, 6);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6);
@@ -99776,20 +104746,42 @@ SQLITE_PRIVATE void sqlite3Pragma(
pIdx = sqlite3FindIndex(db, zRight, zDb);
if( pIdx ){
int i;
+ int mx;
+ if( pPragma->iArg ){
+ /* PRAGMA index_xinfo (newer version with more rows and columns) */
+ mx = pIdx->nColumn;
+ pParse->nMem = 6;
+ }else{
+ /* PRAGMA index_info (legacy version) */
+ mx = pIdx->nKeyCol;
+ pParse->nMem = 3;
+ }
pTab = pIdx->pTable;
- sqlite3VdbeSetNumCols(v, 3);
- pParse->nMem = 3;
+ sqlite3VdbeSetNumCols(v, pParse->nMem);
sqlite3CodeVerifySchema(pParse, iDb);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seqno", SQLITE_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "cid", SQLITE_STATIC);
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "name", SQLITE_STATIC);
- for(i=0; i<pIdx->nKeyCol; i++){
+ if( pPragma->iArg ){
+ sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "desc", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "coll", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "key", SQLITE_STATIC);
+ }
+ for(i=0; i<mx; i++){
i16 cnum = pIdx->aiColumn[i];
sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
sqlite3VdbeAddOp2(v, OP_Integer, cnum, 2);
- assert( pTab->nCol>cnum );
- sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pTab->aCol[cnum].zName, 0);
- sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
+ if( cnum<0 ){
+ sqlite3VdbeAddOp2(v, OP_Null, 0, 3);
+ }else{
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pTab->aCol[cnum].zName, 0);
+ }
+ if( pPragma->iArg ){
+ sqlite3VdbeAddOp2(v, OP_Integer, pIdx->aSortOrder[i], 4);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, pIdx->azColl[i], 0);
+ sqlite3VdbeAddOp2(v, OP_Integer, i<pIdx->nKeyCol, 6);
+ }
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, pParse->nMem);
}
}
}
@@ -99802,17 +104794,22 @@ SQLITE_PRIVATE void sqlite3Pragma(
pTab = sqlite3FindTable(db, zRight, zDb);
if( pTab ){
v = sqlite3GetVdbe(pParse);
- sqlite3VdbeSetNumCols(v, 3);
- pParse->nMem = 3;
+ sqlite3VdbeSetNumCols(v, 5);
+ pParse->nMem = 5;
sqlite3CodeVerifySchema(pParse, iDb);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", SQLITE_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "origin", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "partial", SQLITE_STATIC);
for(pIdx=pTab->pIndex, i=0; pIdx; pIdx=pIdx->pNext, i++){
+ const char *azOrigin[] = { "c", "u", "pk" };
sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0);
sqlite3VdbeAddOp2(v, OP_Integer, IsUniqueIndex(pIdx), 3);
- sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, azOrigin[pIdx->idxType], 0);
+ sqlite3VdbeAddOp2(v, OP_Integer, pIdx->pPartIdxWhere!=0, 5);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5);
}
}
}
@@ -100336,7 +105333,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
){
for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){
- ENC(pParse->db) = pEnc->enc ? pEnc->enc : SQLITE_UTF16NATIVE;
+ SCHEMA_ENC(db) = ENC(db) =
+ pEnc->enc ? pEnc->enc : SQLITE_UTF16NATIVE;
break;
}
}
@@ -100381,24 +105379,9 @@ SQLITE_PRIVATE void sqlite3Pragma(
** applications for any purpose.
*/
case PragTyp_HEADER_VALUE: {
- int iCookie; /* Cookie index. 1 for schema-cookie, 6 for user-cookie. */
+ int iCookie = pPragma->iArg; /* Which cookie to read or write */
sqlite3VdbeUsesBtree(v, iDb);
- switch( zLeft[0] ){
- case 'a': case 'A':
- iCookie = BTREE_APPLICATION_ID;
- break;
- case 'f': case 'F':
- iCookie = BTREE_FREE_PAGE_COUNT;
- break;
- case 's': case 'S':
- iCookie = BTREE_SCHEMA_VERSION;
- break;
- default:
- iCookie = BTREE_USER_VERSION;
- break;
- }
-
- if( zRight && iCookie!=BTREE_FREE_PAGE_COUNT ){
+ if( zRight && (pPragma->mPragFlag & PragFlag_ReadOnly)==0 ){
/* Write the specified cookie value */
static const VdbeOpList setCookie[] = {
{ OP_Transaction, 0, 1, 0}, /* 0 */
@@ -100451,7 +105434,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
#ifndef SQLITE_OMIT_WAL
/*
- ** PRAGMA [database.]wal_checkpoint = passive|full|restart
+ ** PRAGMA [database.]wal_checkpoint = passive|full|restart|truncate
**
** Checkpoint the database.
*/
@@ -100463,6 +105446,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
eMode = SQLITE_CHECKPOINT_FULL;
}else if( sqlite3StrICmp(zRight, "restart")==0 ){
eMode = SQLITE_CHECKPOINT_RESTART;
+ }else if( sqlite3StrICmp(zRight, "truncate")==0 ){
+ eMode = SQLITE_CHECKPOINT_TRUNCATE;
}
}
sqlite3VdbeSetNumCols(v, 3);
@@ -100498,8 +105483,9 @@ SQLITE_PRIVATE void sqlite3Pragma(
/*
** PRAGMA shrink_memory
**
- ** This pragma attempts to free as much memory as possible from the
- ** current database connection.
+ ** IMPLEMENTATION-OF: R-23445-46109 This pragma causes the database
+ ** connection on which it is invoked to free up as much memory as it
+ ** can, by calling sqlite3_db_release_memory().
*/
case PragTyp_SHRINK_MEMORY: {
sqlite3_db_release_memory(db);
@@ -100516,7 +105502,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
** disables the timeout.
*/
/*case PragTyp_BUSY_TIMEOUT*/ default: {
- assert( aPragmaNames[mid].ePragTyp==PragTyp_BUSY_TIMEOUT );
+ assert( pPragma->ePragTyp==PragTyp_BUSY_TIMEOUT );
if( zRight ){
sqlite3_busy_timeout(db, sqlite3Atoi(zRight));
}
@@ -100528,8 +105514,12 @@ SQLITE_PRIVATE void sqlite3Pragma(
** PRAGMA soft_heap_limit
** PRAGMA soft_heap_limit = N
**
- ** Call sqlite3_soft_heap_limit64(N). Return the result. If N is omitted,
- ** use -1.
+ ** IMPLEMENTATION-OF: R-26343-45930 This pragma invokes the
+ ** sqlite3_soft_heap_limit64() interface with the argument N, if N is
+ ** specified and is a non-negative integer.
+ ** IMPLEMENTATION-OF: R-64451-07163 The soft_heap_limit pragma always
+ ** returns the same integer that would be returned by the
+ ** sqlite3_soft_heap_limit64(-1) C-language function.
*/
case PragTyp_SOFT_HEAP_LIMIT: {
sqlite3_int64 N;
@@ -100540,6 +105530,26 @@ SQLITE_PRIVATE void sqlite3Pragma(
break;
}
+ /*
+ ** PRAGMA threads
+ ** PRAGMA threads = N
+ **
+ ** Configure the maximum number of worker threads. Return the new
+ ** maximum, which might be less than requested.
+ */
+ case PragTyp_THREADS: {
+ sqlite3_int64 N;
+ if( zRight
+ && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK
+ && N>=0
+ ){
+ sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, (int)(N&0x7fffffff));
+ }
+ returnSingleInt(pParse, "threads",
+ sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, -1));
+ break;
+ }
+
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
/*
** Report the current state of file logs for all databases
@@ -100695,7 +105705,7 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char
if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */
if( argv[1]==0 ){
corruptSchema(pData, argv[0], 0);
- }else if( argv[2] && argv[2][0] ){
+ }else if( sqlite3_strnicmp(argv[2],"create ",7)==0 ){
/* Call the parser to process a CREATE TABLE, INDEX or VIEW.
** But because db->init.busy is set to 1, no VDBE code is generated
** or executed. All the parser does is build the internal data
@@ -100726,8 +105736,8 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char
}
}
sqlite3_finalize(pStmt);
- }else if( argv[0]==0 ){
- corruptSchema(pData, 0, 0);
+ }else if( argv[0]==0 || (argv[2]!=0 && argv[2][0]!=0) ){
+ corruptSchema(pData, argv[0], 0);
}else{
/* If the SQL column is blank it means this is an index that
** was created to be the PRIMARY KEY or to fulfill a UNIQUE
@@ -100956,7 +105966,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
db->aDb[iDb].zName, zMasterName);
#ifndef SQLITE_OMIT_AUTHORIZATION
{
- int (*xAuth)(void*,int,const char*,const char*,const char*,const char*);
+ sqlite3_xauth xAuth;
xAuth = db->xAuth;
db->xAuth = 0;
#endif
@@ -101022,8 +106032,11 @@ SQLITE_PRIVATE int sqlite3Init(sqlite3 *db, char **pzErrMsg){
int commit_internal = !(db->flags&SQLITE_InternChanges);
assert( sqlite3_mutex_held(db->mutex) );
+ assert( sqlite3BtreeHoldsMutex(db->aDb[0].pBt) );
+ assert( db->init.busy==0 );
rc = SQLITE_OK;
db->init.busy = 1;
+ ENC(db) = SCHEMA_ENC(db);
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue;
rc = sqlite3InitOne(db, i, pzErrMsg);
@@ -101037,8 +106050,8 @@ SQLITE_PRIVATE int sqlite3Init(sqlite3 *db, char **pzErrMsg){
** schema may contain references to objects in other databases.
*/
#ifndef SQLITE_OMIT_TEMPDB
- if( rc==SQLITE_OK && ALWAYS(db->nDb>1)
- && !DbHasProperty(db, 1, DB_SchemaLoaded) ){
+ assert( db->nDb>1 );
+ if( rc==SQLITE_OK && !DbHasProperty(db, 1, DB_SchemaLoaded) ){
rc = sqlite3InitOne(db, 1, pzErrMsg);
if( rc ){
sqlite3ResetOneSchema(db, 1);
@@ -101221,7 +106234,7 @@ static int sqlite3Prepare(
rc = sqlite3BtreeSchemaLocked(pBt);
if( rc ){
const char *zDb = db->aDb[i].zName;
- sqlite3Error(db, rc, "database schema is locked: %s", zDb);
+ sqlite3ErrorWithMsg(db, rc, "database schema is locked: %s", zDb);
testcase( db->flags & SQLITE_ReadUncommitted );
goto end_prepare;
}
@@ -101238,7 +106251,7 @@ static int sqlite3Prepare(
testcase( nBytes==mxLen );
testcase( nBytes==mxLen+1 );
if( nBytes>mxLen ){
- sqlite3Error(db, SQLITE_TOOBIG, "statement too long");
+ sqlite3ErrorWithMsg(db, SQLITE_TOOBIG, "statement too long");
rc = sqlite3ApiExit(db, SQLITE_TOOBIG);
goto end_prepare;
}
@@ -101305,10 +106318,10 @@ static int sqlite3Prepare(
}
if( zErrMsg ){
- sqlite3Error(db, rc, "%s", zErrMsg);
+ sqlite3ErrorWithMsg(db, rc, "%s", zErrMsg);
sqlite3DbFree(db, zErrMsg);
}else{
- sqlite3Error(db, rc, 0);
+ sqlite3Error(db, rc);
}
/* Delete any TriggerPrg structures allocated while parsing this statement. */
@@ -101336,9 +106349,12 @@ static int sqlite3LockAndPrepare(
const char **pzTail /* OUT: End of parsed string */
){
int rc;
- assert( ppStmt!=0 );
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( ppStmt==0 ) return SQLITE_MISUSE_BKPT;
+#endif
*ppStmt = 0;
- if( !sqlite3SafetyCheckOk(db) ){
+ if( !sqlite3SafetyCheckOk(db)||zSql==0 ){
return SQLITE_MISUSE_BKPT;
}
sqlite3_mutex_enter(db->mutex);
@@ -101399,7 +106415,7 @@ SQLITE_PRIVATE int sqlite3Reprepare(Vdbe *p){
** and the statement is automatically recompiled if an schema change
** occurs.
*/
-SQLITE_API int sqlite3_prepare(
+SQLITE_API int SQLITE_STDCALL sqlite3_prepare(
sqlite3 *db, /* Database handle. */
const char *zSql, /* UTF-8 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */
@@ -101411,7 +106427,7 @@ SQLITE_API int sqlite3_prepare(
assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */
return rc;
}
-SQLITE_API int sqlite3_prepare_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_prepare_v2(
sqlite3 *db, /* Database handle. */
const char *zSql, /* UTF-8 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */
@@ -101445,9 +106461,11 @@ static int sqlite3Prepare16(
const char *zTail8 = 0;
int rc = SQLITE_OK;
- assert( ppStmt );
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( ppStmt==0 ) return SQLITE_MISUSE_BKPT;
+#endif
*ppStmt = 0;
- if( !sqlite3SafetyCheckOk(db) ){
+ if( !sqlite3SafetyCheckOk(db)||zSql==0 ){
return SQLITE_MISUSE_BKPT;
}
if( nBytes>=0 ){
@@ -101485,7 +106503,7 @@ static int sqlite3Prepare16(
** and the statement is automatically recompiled if an schema change
** occurs.
*/
-SQLITE_API int sqlite3_prepare16(
+SQLITE_API int SQLITE_STDCALL sqlite3_prepare16(
sqlite3 *db, /* Database handle. */
const void *zSql, /* UTF-16 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */
@@ -101497,7 +106515,7 @@ SQLITE_API int sqlite3_prepare16(
assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */
return rc;
}
-SQLITE_API int sqlite3_prepare16_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_prepare16_v2(
sqlite3 *db, /* Database handle. */
const void *zSql, /* UTF-16 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */
@@ -101530,6 +106548,20 @@ SQLITE_API int sqlite3_prepare16_v2(
*/
/*
+** Trace output macros
+*/
+#if SELECTTRACE_ENABLED
+/***/ int sqlite3SelectTrace = 0;
+# define SELECTTRACE(K,P,S,X) \
+ if(sqlite3SelectTrace&(K)) \
+ sqlite3DebugPrintf("%*s%s.%p: ",(P)->nSelectIndent*2-2,"",(S)->zSelName,(S)),\
+ sqlite3DebugPrintf X
+#else
+# define SELECTTRACE(K,P,S,X)
+#endif
+
+
+/*
** An instance of the following object is used to record information about
** how to process the DISTINCT keyword, to simplify passing that information
** into the selectInnerLoop() routine.
@@ -101559,20 +106591,25 @@ struct SortCtx {
#define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */
/*
-** Delete all the content of a Select structure but do not deallocate
-** the select structure itself.
+** Delete all the content of a Select structure. Deallocate the structure
+** itself only if bFree is true.
*/
-static void clearSelect(sqlite3 *db, Select *p){
- sqlite3ExprListDelete(db, p->pEList);
- sqlite3SrcListDelete(db, p->pSrc);
- sqlite3ExprDelete(db, p->pWhere);
- sqlite3ExprListDelete(db, p->pGroupBy);
- sqlite3ExprDelete(db, p->pHaving);
- sqlite3ExprListDelete(db, p->pOrderBy);
- sqlite3SelectDelete(db, p->pPrior);
- sqlite3ExprDelete(db, p->pLimit);
- sqlite3ExprDelete(db, p->pOffset);
- sqlite3WithDelete(db, p->pWith);
+static void clearSelect(sqlite3 *db, Select *p, int bFree){
+ while( p ){
+ Select *pPrior = p->pPrior;
+ sqlite3ExprListDelete(db, p->pEList);
+ sqlite3SrcListDelete(db, p->pSrc);
+ sqlite3ExprDelete(db, p->pWhere);
+ sqlite3ExprListDelete(db, p->pGroupBy);
+ sqlite3ExprDelete(db, p->pHaving);
+ sqlite3ExprListDelete(db, p->pOrderBy);
+ sqlite3ExprDelete(db, p->pLimit);
+ sqlite3ExprDelete(db, p->pOffset);
+ sqlite3WithDelete(db, p->pWith);
+ if( bFree ) sqlite3DbFree(db, p);
+ p = pPrior;
+ bFree = 1;
+ }
}
/*
@@ -101607,7 +106644,6 @@ SQLITE_PRIVATE Select *sqlite3SelectNew(
Select standin;
sqlite3 *db = pParse->db;
pNew = sqlite3DbMallocZero(db, sizeof(*pNew) );
- assert( db->mallocFailed || !pOffset || pLimit ); /* OFFSET implies LIMIT */
if( pNew==0 ){
assert( db->mallocFailed );
pNew = &standin;
@@ -101627,12 +106663,11 @@ SQLITE_PRIVATE Select *sqlite3SelectNew(
pNew->op = TK_SELECT;
pNew->pLimit = pLimit;
pNew->pOffset = pOffset;
- assert( pOffset==0 || pLimit!=0 );
+ assert( pOffset==0 || pLimit!=0 || pParse->nErr>0 || db->mallocFailed!=0 );
pNew->addrOpenEphm[0] = -1;
pNew->addrOpenEphm[1] = -1;
if( db->mallocFailed ) {
- clearSelect(db, pNew);
- if( pNew!=&standin ) sqlite3DbFree(db, pNew);
+ clearSelect(db, pNew, pNew!=&standin);
pNew = 0;
}else{
assert( pNew->pSrc!=0 || pParse->nErr>0 );
@@ -101641,14 +106676,23 @@ SQLITE_PRIVATE Select *sqlite3SelectNew(
return pNew;
}
+#if SELECTTRACE_ENABLED
+/*
+** Set the name of a Select object
+*/
+SQLITE_PRIVATE void sqlite3SelectSetName(Select *p, const char *zName){
+ if( p && zName ){
+ sqlite3_snprintf(sizeof(p->zSelName), p->zSelName, "%s", zName);
+ }
+}
+#endif
+
+
/*
** Delete the given Select structure and all of its substructures.
*/
SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3 *db, Select *p){
- if( p ){
- clearSelect(db, p);
- sqlite3DbFree(db, p);
- }
+ clearSelect(db, p, 1);
}
/*
@@ -101970,28 +107014,43 @@ static KeyInfo *keyInfoFromExprList(
);
/*
-** Insert code into "v" that will push the record in register regData
-** into the sorter.
+** Generate code that will push the record in registers regData
+** through regData+nData-1 onto the sorter.
*/
static void pushOntoSorter(
Parse *pParse, /* Parser context */
SortCtx *pSort, /* Information about the ORDER BY clause */
Select *pSelect, /* The whole SELECT statement */
- int regData /* Register holding data to be sorted */
+ int regData, /* First register holding data to be sorted */
+ int nData, /* Number of elements in the data array */
+ int nPrefixReg /* No. of reg prior to regData available for use */
){
- Vdbe *v = pParse->pVdbe;
- int nExpr = pSort->pOrderBy->nExpr;
- int regRecord = ++pParse->nMem;
- int regBase = pParse->nMem+1;
- int nOBSat = pSort->nOBSat;
- int op;
+ Vdbe *v = pParse->pVdbe; /* Stmt under construction */
+ int bSeq = ((pSort->sortFlags & SORTFLAG_UseSorter)==0);
+ int nExpr = pSort->pOrderBy->nExpr; /* No. of ORDER BY terms */
+ int nBase = nExpr + bSeq + nData; /* Fields in sorter record */
+ int regBase; /* Regs for sorter record */
+ int regRecord = ++pParse->nMem; /* Assembled sorter record */
+ int nOBSat = pSort->nOBSat; /* ORDER BY terms to skip */
+ int op; /* Opcode to add sorter record to sorter */
- pParse->nMem += nExpr+2; /* nExpr+2 registers allocated at regBase */
- sqlite3ExprCacheClear(pParse);
- sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, 0);
- sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr);
- sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+1, 1);
- sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nExpr+2-nOBSat,regRecord);
+ assert( bSeq==0 || bSeq==1 );
+ if( nPrefixReg ){
+ assert( nPrefixReg==nExpr+bSeq );
+ regBase = regData - nExpr - bSeq;
+ }else{
+ regBase = pParse->nMem + 1;
+ pParse->nMem += nBase;
+ }
+ sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, SQLITE_ECEL_DUP);
+ if( bSeq ){
+ sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr);
+ }
+ if( nPrefixReg==0 ){
+ sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+bSeq, nData);
+ }
+
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nBase-nOBSat, regRecord);
if( nOBSat>0 ){
int regPrevKey; /* The first nOBSat columns of the previous row */
int addrFirst; /* Address of the OP_IfNot opcode */
@@ -102002,16 +107061,23 @@ static void pushOntoSorter(
regPrevKey = pParse->nMem+1;
pParse->nMem += pSort->nOBSat;
- nKey = nExpr - pSort->nOBSat + 1;
- addrFirst = sqlite3VdbeAddOp1(v, OP_IfNot, regBase+nExpr); VdbeCoverage(v);
+ nKey = nExpr - pSort->nOBSat + bSeq;
+ if( bSeq ){
+ addrFirst = sqlite3VdbeAddOp1(v, OP_IfNot, regBase+nExpr);
+ }else{
+ addrFirst = sqlite3VdbeAddOp1(v, OP_SequenceTest, pSort->iECursor);
+ }
+ VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_Compare, regPrevKey, regBase, pSort->nOBSat);
pOp = sqlite3VdbeGetOp(v, pSort->addrSortIndex);
if( pParse->db->mallocFailed ) return;
- pOp->p2 = nKey + 1;
+ pOp->p2 = nKey + nData;
pKI = pOp->p4.pKeyInfo;
memset(pKI->aSortOrder, 0, pKI->nField); /* Makes OP_Jump below testable */
sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO);
- pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat, 1);
+ testcase( pKI->nXField>2 );
+ pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat,
+ pKI->nXField-1);
addrJmp = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v);
pSort->labelBkOut = sqlite3VdbeMakeLabel(v);
@@ -102019,7 +107085,7 @@ static void pushOntoSorter(
sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
sqlite3VdbeAddOp1(v, OP_ResetSorter, pSort->iECursor);
sqlite3VdbeJumpHere(v, addrFirst);
- sqlite3VdbeAddOp3(v, OP_Move, regBase, regPrevKey, pSort->nOBSat);
+ sqlite3ExprCodeMove(pParse, regBase, regPrevKey, pSort->nOBSat);
sqlite3VdbeJumpHere(v, addrJmp);
}
if( pSort->sortFlags & SORTFLAG_UseSorter ){
@@ -102029,20 +107095,17 @@ static void pushOntoSorter(
}
sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord);
if( pSelect->iLimit ){
- int addr1, addr2;
+ int addr;
int iLimit;
if( pSelect->iOffset ){
iLimit = pSelect->iOffset+1;
}else{
iLimit = pSelect->iLimit;
}
- addr1 = sqlite3VdbeAddOp1(v, OP_IfZero, iLimit); VdbeCoverage(v);
- sqlite3VdbeAddOp2(v, OP_AddImm, iLimit, -1);
- addr2 = sqlite3VdbeAddOp0(v, OP_Goto);
- sqlite3VdbeJumpHere(v, addr1);
+ addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, -1); VdbeCoverage(v);
sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor);
sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor);
- sqlite3VdbeJumpHere(v, addr2);
+ sqlite3VdbeJumpHere(v, addr);
}
}
@@ -102141,6 +107204,7 @@ static void selectInnerLoop(
int eDest = pDest->eDest; /* How to dispose of results */
int iParm = pDest->iSDParm; /* First argument to disposal method */
int nResultCol; /* Number of result columns */
+ int nPrefixReg = 0; /* Number of extra registers before regResult */
assert( v );
assert( pEList!=0 );
@@ -102156,6 +107220,11 @@ static void selectInnerLoop(
nResultCol = pEList->nExpr;
if( pDest->iSdst==0 ){
+ if( pSort ){
+ nPrefixReg = pSort->pOrderBy->nExpr;
+ if( !(pSort->sortFlags & SORTFLAG_UseSorter) ) nPrefixReg++;
+ pParse->nMem += nPrefixReg;
+ }
pDest->iSdst = pParse->nMem+1;
pParse->nMem += nResultCol;
}else if( pDest->iSdst+nResultCol > pParse->nMem ){
@@ -102272,10 +107341,10 @@ static void selectInnerLoop(
case SRT_DistFifo:
case SRT_Table:
case SRT_EphemTab: {
- int r1 = sqlite3GetTempReg(pParse);
+ int r1 = sqlite3GetTempRange(pParse, nPrefixReg+1);
testcase( eDest==SRT_Table );
testcase( eDest==SRT_EphemTab );
- sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1);
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1+nPrefixReg);
#ifndef SQLITE_OMIT_CTE
if( eDest==SRT_DistFifo ){
/* If the destination is DistFifo, then cursor (iParm+1) is open
@@ -102290,7 +107359,7 @@ static void selectInnerLoop(
}
#endif
if( pSort ){
- pushOntoSorter(pParse, pSort, p, r1);
+ pushOntoSorter(pParse, pSort, p, r1+nPrefixReg, 1, nPrefixReg);
}else{
int r2 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2);
@@ -102298,7 +107367,7 @@ static void selectInnerLoop(
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
sqlite3ReleaseTempReg(pParse, r2);
}
- sqlite3ReleaseTempReg(pParse, r1);
+ sqlite3ReleaseTempRange(pParse, r1, nPrefixReg+1);
break;
}
@@ -102316,7 +107385,7 @@ static void selectInnerLoop(
** ORDER BY in this case since the order of entries in the set
** does not matter. But there might be a LIMIT clause, in which
** case the order does matter */
- pushOntoSorter(pParse, pSort, p, regResult);
+ pushOntoSorter(pParse, pSort, p, regResult, 1, nPrefixReg);
}else{
int r1 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult,1,r1, &pDest->affSdst, 1);
@@ -102342,9 +107411,9 @@ static void selectInnerLoop(
case SRT_Mem: {
assert( nResultCol==1 );
if( pSort ){
- pushOntoSorter(pParse, pSort, p, regResult);
+ pushOntoSorter(pParse, pSort, p, regResult, 1, nPrefixReg);
}else{
- sqlite3ExprCodeMove(pParse, regResult, iParm, 1);
+ assert( regResult==iParm );
/* The LIMIT clause will jump out of the loop for us */
}
break;
@@ -102356,10 +107425,7 @@ static void selectInnerLoop(
testcase( eDest==SRT_Coroutine );
testcase( eDest==SRT_Output );
if( pSort ){
- int r1 = sqlite3GetTempReg(pParse);
- sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1);
- pushOntoSorter(pParse, pSort, p, r1);
- sqlite3ReleaseTempReg(pParse, r1);
+ pushOntoSorter(pParse, pSort, p, regResult, nResultCol, nPrefixReg);
}else if( eDest==SRT_Coroutine ){
sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm);
}else{
@@ -102436,7 +107502,7 @@ static void selectInnerLoop(
** the output for us.
*/
if( pSort==0 && p->iLimit ){
- sqlite3VdbeAddOp3(v, OP_IfZero, p->iLimit, iBreak, -1); VdbeCoverage(v);
+ sqlite3VdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, iBreak); VdbeCoverage(v);
}
}
@@ -102502,7 +107568,7 @@ SQLITE_PRIVATE int sqlite3KeyInfoIsWriteable(KeyInfo *p){ return p->nRef==1; }
** then the KeyInfo structure is appropriate for initializing a virtual
** index to implement a DISTINCT test.
**
-** Space to hold the KeyInfo structure is obtain from malloc. The calling
+** Space to hold the KeyInfo structure is obtained from malloc. The calling
** function is responsible for seeing that this structure is eventually
** freed.
*/
@@ -102519,7 +107585,7 @@ static KeyInfo *keyInfoFromExprList(
int i;
nExpr = pList->nExpr;
- pInfo = sqlite3KeyInfoAlloc(db, nExpr+nExtra-iStart, 1);
+ pInfo = sqlite3KeyInfoAlloc(db, nExpr-iStart, nExtra+1);
if( pInfo ){
assert( sqlite3KeyInfoIsWriteable(pInfo) );
for(i=iStart, pItem=pList->a+iStart; i<nExpr; i++, pItem++){
@@ -102639,46 +107705,58 @@ static void generateSortTail(
int addr;
int addrOnce = 0;
int iTab;
- int pseudoTab = 0;
ExprList *pOrderBy = pSort->pOrderBy;
int eDest = pDest->eDest;
int iParm = pDest->iSDParm;
int regRow;
int regRowid;
int nKey;
+ int iSortTab; /* Sorter cursor to read from */
+ int nSortData; /* Trailing values to read from sorter */
+ int i;
+ int bSeq; /* True if sorter record includes seq. no. */
+#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
+ struct ExprList_item *aOutEx = p->pEList->a;
+#endif
if( pSort->labelBkOut ){
sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrBreak);
sqlite3VdbeResolveLabel(v, pSort->labelBkOut);
- addrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v);
}
iTab = pSort->iECursor;
- regRow = sqlite3GetTempReg(pParse);
if( eDest==SRT_Output || eDest==SRT_Coroutine ){
- pseudoTab = pParse->nTab++;
- sqlite3VdbeAddOp3(v, OP_OpenPseudo, pseudoTab, regRow, nColumn);
regRowid = 0;
+ regRow = pDest->iSdst;
+ nSortData = nColumn;
}else{
regRowid = sqlite3GetTempReg(pParse);
+ regRow = sqlite3GetTempReg(pParse);
+ nSortData = 1;
}
nKey = pOrderBy->nExpr - pSort->nOBSat;
if( pSort->sortFlags & SORTFLAG_UseSorter ){
int regSortOut = ++pParse->nMem;
- int ptab2 = pParse->nTab++;
- sqlite3VdbeAddOp3(v, OP_OpenPseudo, ptab2, regSortOut, nKey+2);
+ iSortTab = pParse->nTab++;
+ if( pSort->labelBkOut ){
+ addrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v);
+ }
+ sqlite3VdbeAddOp3(v, OP_OpenPseudo, iSortTab, regSortOut, nKey+1+nSortData);
if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak);
VdbeCoverage(v);
codeOffset(v, p->iOffset, addrContinue);
- sqlite3VdbeAddOp2(v, OP_SorterData, iTab, regSortOut);
- sqlite3VdbeAddOp3(v, OP_Column, ptab2, nKey+1, regRow);
- sqlite3VdbeChangeP5(v, OPFLAG_CLEARCACHE);
+ sqlite3VdbeAddOp3(v, OP_SorterData, iTab, regSortOut, iSortTab);
+ bSeq = 0;
}else{
- if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); VdbeCoverage(v);
codeOffset(v, p->iOffset, addrContinue);
- sqlite3VdbeAddOp3(v, OP_Column, iTab, nKey+1, regRow);
+ iSortTab = iTab;
+ bSeq = 1;
+ }
+ for(i=0; i<nSortData; i++){
+ sqlite3VdbeAddOp3(v, OP_Column, iSortTab, nKey+bSeq+i, regRow+i);
+ VdbeComment((v, "%s", aOutEx[i].zName ? aOutEx[i].zName : aOutEx[i].zSpan));
}
switch( eDest ){
case SRT_Table:
@@ -102707,17 +107785,9 @@ static void generateSortTail(
}
#endif
default: {
- int i;
assert( eDest==SRT_Output || eDest==SRT_Coroutine );
testcase( eDest==SRT_Output );
testcase( eDest==SRT_Coroutine );
- for(i=0; i<nColumn; i++){
- assert( regRow!=pDest->iSdst+i );
- sqlite3VdbeAddOp3(v, OP_Column, pseudoTab, i, pDest->iSdst+i);
- if( i==0 ){
- sqlite3VdbeChangeP5(v, OPFLAG_CLEARCACHE);
- }
- }
if( eDest==SRT_Output ){
sqlite3VdbeAddOp2(v, OP_ResultRow, pDest->iSdst, nColumn);
sqlite3ExprCacheAffinityChange(pParse, pDest->iSdst, nColumn);
@@ -102727,9 +107797,10 @@ static void generateSortTail(
break;
}
}
- sqlite3ReleaseTempReg(pParse, regRow);
- sqlite3ReleaseTempReg(pParse, regRowid);
-
+ if( regRowid ){
+ sqlite3ReleaseTempReg(pParse, regRow);
+ sqlite3ReleaseTempReg(pParse, regRowid);
+ }
/* The bottom of the loop
*/
sqlite3VdbeResolveLabel(v, addrContinue);
@@ -102842,7 +107913,7 @@ static const char *columnTypeImpl(
** of the SELECT statement. Return the declaration type and origin
** data for the result-set column of the sub-select.
*/
- if( iCol>=0 && ALWAYS(iCol<pS->pEList->nExpr) ){
+ if( iCol>=0 && iCol<pS->pEList->nExpr ){
/* If iCol is less than zero, then the expression requests the
** rowid of the sub-select or view. This expression is legal (see
** test case misc2.2.2) - it always evaluates to NULL.
@@ -103024,7 +108095,7 @@ static void generateColumnNames(
}
/*
-** Given a an expression list (which is really the list of expressions
+** Given an expression list (which is really the list of expressions
** that form the result set of a SELECT statement) compute appropriate
** column names for a table that would hold the expression list.
**
@@ -103097,7 +108168,7 @@ static int selectColumnsFromExprList(
}
/* Make sure the column name is unique. If the name is not unique,
- ** append a integer to the name so that it becomes unique.
+ ** append an integer to the name so that it becomes unique.
*/
nName = sqlite3Strlen30(zName);
for(j=cnt=0; j<i; j++){
@@ -103162,12 +108233,14 @@ static void selectAddColumnTypeAndCollation(
a = pSelect->pEList->a;
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
p = a[i].pExpr;
- pCol->zType = sqlite3DbStrDup(db, columnType(&sNC, p,0,0,0, &pCol->szEst));
+ if( pCol->zType==0 ){
+ pCol->zType = sqlite3DbStrDup(db, columnType(&sNC, p,0,0,0, &pCol->szEst));
+ }
szAll += pCol->szEst;
pCol->affinity = sqlite3ExprAffinity(p);
if( pCol->affinity==0 ) pCol->affinity = SQLITE_AFF_NONE;
pColl = sqlite3ExprCollSeq(pParse, p);
- if( pColl ){
+ if( pColl && pCol->zColl==0 ){
pCol->zColl = sqlite3DbStrDup(db, pColl->zName);
}
}
@@ -103284,7 +108357,7 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
sqlite3ExprCode(pParse, p->pLimit, iLimit);
sqlite3VdbeAddOp1(v, OP_MustBeInt, iLimit); VdbeCoverage(v);
VdbeComment((v, "LIMIT counter"));
- sqlite3VdbeAddOp2(v, OP_IfZero, iLimit, iBreak); VdbeCoverage(v);
+ sqlite3VdbeAddOp2(v, OP_IfNot, iLimit, iBreak); VdbeCoverage(v);
}
if( p->pOffset ){
p->iOffset = iOffset = ++pParse->nMem;
@@ -103503,7 +108576,7 @@ static void generateWithRecursiveQuery(
selectInnerLoop(pParse, p, p->pEList, iCurrent,
0, 0, pDest, addrCont, addrBreak);
if( regLimit ){
- sqlite3VdbeAddOp3(v, OP_IfZero, regLimit, addrBreak, -1);
+ sqlite3VdbeAddOp2(v, OP_DecrJumpZero, regLimit, addrBreak);
VdbeCoverage(v);
}
sqlite3VdbeResolveLabel(v, addrCont);
@@ -103536,6 +108609,65 @@ static int multiSelectOrderBy(
SelectDest *pDest /* What to do with query results */
);
+/*
+** Error message for when two or more terms of a compound select have different
+** size result sets.
+*/
+static void selectWrongNumTermsError(Parse *pParse, Select *p){
+ if( p->selFlags & SF_Values ){
+ sqlite3ErrorMsg(pParse, "all VALUES must have the same number of terms");
+ }else{
+ sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s"
+ " do not have the same number of result columns", selectOpName(p->op));
+ }
+}
+
+/*
+** Handle the special case of a compound-select that originates from a
+** VALUES clause. By handling this as a special case, we avoid deep
+** recursion, and thus do not need to enforce the SQLITE_LIMIT_COMPOUND_SELECT
+** on a VALUES clause.
+**
+** Because the Select object originates from a VALUES clause:
+** (1) It has no LIMIT or OFFSET
+** (2) All terms are UNION ALL
+** (3) There is no ORDER BY clause
+*/
+static int multiSelectValues(
+ Parse *pParse, /* Parsing context */
+ Select *p, /* The right-most of SELECTs to be coded */
+ SelectDest *pDest /* What to do with query results */
+){
+ Select *pPrior;
+ int nExpr = p->pEList->nExpr;
+ int nRow = 1;
+ int rc = 0;
+ assert( p->selFlags & SF_MultiValue );
+ do{
+ assert( p->selFlags & SF_Values );
+ assert( p->op==TK_ALL || (p->op==TK_SELECT && p->pPrior==0) );
+ assert( p->pLimit==0 );
+ assert( p->pOffset==0 );
+ if( p->pEList->nExpr!=nExpr ){
+ selectWrongNumTermsError(pParse, p);
+ return 1;
+ }
+ if( p->pPrior==0 ) break;
+ assert( p->pPrior->pNext==p );
+ p = p->pPrior;
+ nRow++;
+ }while(1);
+ while( p ){
+ pPrior = p->pPrior;
+ p->pPrior = 0;
+ rc = sqlite3Select(pParse, p, pDest);
+ p->pPrior = pPrior;
+ if( rc ) break;
+ p->nSelectRow = nRow;
+ p = p->pNext;
+ }
+ return rc;
+}
/*
** This routine is called to process a compound query form from
@@ -103617,17 +108749,19 @@ static int multiSelect(
dest.eDest = SRT_Table;
}
+ /* Special handling for a compound-select that originates as a VALUES clause.
+ */
+ if( p->selFlags & SF_MultiValue ){
+ rc = multiSelectValues(pParse, p, &dest);
+ goto multi_select_end;
+ }
+
/* Make sure all SELECTs in the statement have the same number of elements
** in their result sets.
*/
assert( p->pEList && pPrior->pEList );
if( p->pEList->nExpr!=pPrior->pEList->nExpr ){
- if( p->selFlags & SF_Values ){
- sqlite3ErrorMsg(pParse, "all VALUES must have the same number of terms");
- }else{
- sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s"
- " do not have the same number of result columns", selectOpName(p->op));
- }
+ selectWrongNumTermsError(pParse, p);
rc = 1;
goto multi_select_end;
}
@@ -103666,7 +108800,7 @@ static int multiSelect(
p->iLimit = pPrior->iLimit;
p->iOffset = pPrior->iOffset;
if( p->iLimit ){
- addr = sqlite3VdbeAddOp1(v, OP_IfZero, p->iLimit); VdbeCoverage(v);
+ addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v);
VdbeComment((v, "Jump ahead if LIMIT reached"));
}
explainSetInteger(iSub2, pParse->iNextSelectId);
@@ -104002,7 +109136,7 @@ static int generateOutputSubroutine(
*/
case SRT_Set: {
int r1;
- assert( pIn->nSdst==1 );
+ assert( pIn->nSdst==1 || pParse->nErr>0 );
pDest->affSdst =
sqlite3CompareAffinity(p->pEList->a[0].pExpr, pDest->affSdst);
r1 = sqlite3GetTempReg(pParse);
@@ -104028,7 +109162,7 @@ static int generateOutputSubroutine(
** of the scan loop.
*/
case SRT_Mem: {
- assert( pIn->nSdst==1 );
+ assert( pIn->nSdst==1 || pParse->nErr>0 ); testcase( pIn->nSdst!=1 );
sqlite3ExprCodeMove(pParse, pIn->iSdst, pDest->iSDParm, 1);
/* The LIMIT clause will jump out of the loop for us */
break;
@@ -104043,7 +109177,7 @@ static int generateOutputSubroutine(
pDest->iSdst = sqlite3GetTempRange(pParse, pIn->nSdst);
pDest->nSdst = pIn->nSdst;
}
- sqlite3ExprCodeMove(pParse, pIn->iSdst, pDest->iSdst, pDest->nSdst);
+ sqlite3ExprCodeMove(pParse, pIn->iSdst, pDest->iSdst, pIn->nSdst);
sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm);
break;
}
@@ -104067,7 +109201,7 @@ static int generateOutputSubroutine(
/* Jump to the end of the loop if the LIMIT is reached.
*/
if( p->iLimit ){
- sqlite3VdbeAddOp3(v, OP_IfZero, p->iLimit, iBreak, -1); VdbeCoverage(v);
+ sqlite3VdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, iBreak); VdbeCoverage(v);
}
/* Generate the subroutine return
@@ -104259,8 +109393,10 @@ static int multiSelectOrderBy(
if( aPermute ){
struct ExprList_item *pItem;
for(i=0, pItem=pOrderBy->a; i<nOrderBy; i++, pItem++){
- assert( pItem->u.x.iOrderByCol>0
- && pItem->u.x.iOrderByCol<=p->pEList->nExpr );
+ assert( pItem->u.x.iOrderByCol>0 );
+ /* assert( pItem->u.x.iOrderByCol<=p->pEList->nExpr ) is also true
+ ** but only for well-formed SELECT statements. */
+ testcase( pItem->u.x.iOrderByCol > p->pEList->nExpr );
aPermute[i] = pItem->u.x.iOrderByCol - 1;
}
pKeyMerge = multiSelectOrderByKeyInfo(pParse, p, 1);
@@ -104470,7 +109606,7 @@ static int multiSelectOrderBy(
/*** TBD: Insert subroutine calls to close cursors on incomplete
**** subqueries ****/
explainComposite(pParse, p->op, iSub1, iSub2, 0);
- return SQLITE_OK;
+ return pParse->nErr!=0;
}
#endif
@@ -104581,7 +109717,7 @@ static void substSelect(
**
** SELECT x+y AS a FROM t1 WHERE z<100 AND a>5
**
-** The code generated for this simpification gives the same result
+** The code generated for this simplification gives the same result
** but only has to scan the data once. And because indices might
** exist on the table t1, a complete scan of the data might be
** avoided.
@@ -104590,7 +109726,10 @@ static void substSelect(
**
** (1) The subquery and the outer query do not both use aggregates.
**
-** (2) The subquery is not an aggregate or the outer query is not a join.
+** (2) The subquery is not an aggregate or (2a) the outer query is not a join
+** and (2b) the outer query does not use subqueries other than the one
+** FROM-clause subquery that is a candidate for flattening. (2b is
+** due to ticket [2f7170d73bf9abf80] from 2015-02-09.)
**
** (3) The subquery is not the right operand of a left outer join
** (Originally ticket #306. Strengthened by ticket #3300)
@@ -104614,8 +109753,10 @@ static void substSelect(
** (9) The subquery does not use LIMIT or the outer query does not use
** aggregates.
**
-** (10) The subquery does not use aggregates or the outer query does not
-** use LIMIT.
+** (**) Restriction (10) was removed from the code on 2005-02-05 but we
+** accidently carried the comment forward until 2014-09-15. Original
+** text: "The subquery does not use aggregates or the outer query does not
+** use LIMIT."
**
** (11) The subquery and the outer query do not both have ORDER BY clauses.
**
@@ -104678,6 +109819,11 @@ static void substSelect(
** parent to a compound query confuses the code that handles
** recursive queries in multiSelect().
**
+** (24) The subquery is not an aggregate that uses the built-in min() or
+** or max() functions. (Without this restriction, a query like:
+** "SELECT x FROM (SELECT max(y), x FROM t1)" would not necessarily
+** return the value X for which Y was maximal.)
+**
**
** In this routine, the "p" parameter is a pointer to the outer query.
** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query
@@ -104720,12 +109866,21 @@ static int flattenSubquery(
iParent = pSubitem->iCursor;
pSub = pSubitem->pSelect;
assert( pSub!=0 );
- if( isAgg && subqueryIsAgg ) return 0; /* Restriction (1) */
- if( subqueryIsAgg && pSrc->nSrc>1 ) return 0; /* Restriction (2) */
+ if( subqueryIsAgg ){
+ if( isAgg ) return 0; /* Restriction (1) */
+ if( pSrc->nSrc>1 ) return 0; /* Restriction (2a) */
+ if( (p->pWhere && ExprHasProperty(p->pWhere,EP_Subquery))
+ || (sqlite3ExprListFlags(p->pEList) & EP_Subquery)!=0
+ || (sqlite3ExprListFlags(p->pOrderBy) & EP_Subquery)!=0
+ ){
+ return 0; /* Restriction (2b) */
+ }
+ }
+
pSubSrc = pSub->pSrc;
assert( pSubSrc );
/* Prior to version 3.1.2, when LIMIT and OFFSET had to be simple constants,
- ** not arbitrary expresssions, we allowed some combining of LIMIT and OFFSET
+ ** not arbitrary expressions, we allowed some combining of LIMIT and OFFSET
** because they could be computed at compile-time. But when LIMIT and OFFSET
** became arbitrary expressions, we were forced to add restrictions (13)
** and (14). */
@@ -104750,8 +109905,14 @@ static int flattenSubquery(
if( pSub->pLimit && (p->selFlags & SF_Distinct)!=0 ){
return 0; /* Restriction (21) */
}
- if( pSub->selFlags & SF_Recursive ) return 0; /* Restriction (22) */
- if( (p->selFlags & SF_Recursive) && pSub->pPrior ) return 0; /* (23) */
+ testcase( pSub->selFlags & SF_Recursive );
+ testcase( pSub->selFlags & SF_MinMaxAgg );
+ if( pSub->selFlags & (SF_Recursive|SF_MinMaxAgg) ){
+ return 0; /* Restrictions (22) and (24) */
+ }
+ if( (p->selFlags & SF_Recursive) && pSub->pPrior ){
+ return 0; /* Restriction (23) */
+ }
/* OBSOLETE COMMENT 1:
** Restriction 3: If the subquery is a join, make sure the subquery is
@@ -104825,6 +109986,8 @@ static int flattenSubquery(
}
/***** If we reach this point, flattening is permitted. *****/
+ SELECTTRACE(1,pParse,p,("flatten %s.%p from term %d\n",
+ pSub->zSelName, pSub, iFrom));
/* Authorize the subquery */
pParse->zAuthContext = pSubitem->zName;
@@ -104877,6 +110040,7 @@ static int flattenSubquery(
p->pLimit = 0;
p->pOffset = 0;
pNew = sqlite3SelectDup(db, p, 0);
+ sqlite3SelectSetName(pNew, pSub->zSelName);
p->pOffset = pOffset;
p->pLimit = pLimit;
p->pOrderBy = pOrderBy;
@@ -104889,6 +110053,9 @@ static int flattenSubquery(
if( pPrior ) pPrior->pNext = pNew;
pNew->pNext = p;
p->pPrior = pNew;
+ SELECTTRACE(2,pParse,p,
+ ("compound-subquery flattener creates %s.%p as peer\n",
+ pNew->zSelName, pNew));
}
if( db->mallocFailed ) return 1;
}
@@ -105018,8 +110185,23 @@ static int flattenSubquery(
pParent->pHaving = substExpr(db, pParent->pHaving, iParent, pSub->pEList);
}
if( pSub->pOrderBy ){
+ /* At this point, any non-zero iOrderByCol values indicate that the
+ ** ORDER BY column expression is identical to the iOrderByCol'th
+ ** expression returned by SELECT statement pSub. Since these values
+ ** do not necessarily correspond to columns in SELECT statement pParent,
+ ** zero them before transfering the ORDER BY clause.
+ **
+ ** Not doing this may cause an error if a subsequent call to this
+ ** function attempts to flatten a compound sub-query into pParent
+ ** (the only way this can happen is if the compound sub-query is
+ ** currently part of pSub->pSrc). See ticket [d11a6e908f]. */
+ ExprList *pOrderBy = pSub->pOrderBy;
+ for(i=0; i<pOrderBy->nExpr; i++){
+ pOrderBy->a[i].u.x.iOrderByCol = 0;
+ }
assert( pParent->pOrderBy==0 );
- pParent->pOrderBy = pSub->pOrderBy;
+ assert( pSub->pPrior==0 );
+ pParent->pOrderBy = pOrderBy;
pSub->pOrderBy = 0;
}else if( pParent->pOrderBy ){
substExprList(db, pParent->pOrderBy, iParent, pSub->pEList);
@@ -105065,6 +110247,13 @@ static int flattenSubquery(
*/
sqlite3SelectDelete(db, pSub1);
+#if SELECTTRACE_ENABLED
+ if( sqlite3SelectTrace & 0x100 ){
+ sqlite3DebugPrintf("After flattening:\n");
+ sqlite3TreeViewSelect(0, p, 0);
+ }
+#endif
+
return 1;
}
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
@@ -105111,7 +110300,7 @@ static u8 minMaxQuery(AggInfo *pAggInfo, ExprList **ppMinMax){
/*
** The select statement passed as the first argument is an aggregate query.
-** The second argment is the associated aggregate-info object. This
+** The second argument is the associated aggregate-info object. This
** function tests if the SELECT is of the form:
**
** SELECT count(*) FROM <tbl>
@@ -105229,7 +110418,10 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
pNew->pOrderBy = 0;
p->pPrior = 0;
p->pNext = 0;
+ p->pWith = 0;
p->selFlags &= ~SF_Compound;
+ assert( (p->selFlags & SF_Converted)==0 );
+ p->selFlags |= SF_Converted;
assert( pNew->pPrior!=0 );
pNew->pPrior->pNext = pNew;
pNew->pLimit = 0;
@@ -105381,7 +110573,7 @@ static int withExpand(
for(pLeft=pSel; pLeft->pPrior; pLeft=pLeft->pPrior);
pEList = pLeft->pEList;
if( pCte->pCols ){
- if( pEList->nExpr!=pCte->pCols->nExpr ){
+ if( pEList && pEList->nExpr!=pCte->pCols->nExpr ){
sqlite3ErrorMsg(pParse, "table %s has %d values for %d columns",
pCte->zName, pEList->nExpr, pCte->pCols->nExpr
);
@@ -105441,10 +110633,10 @@ static void selectPopWith(Walker *pWalker, Select *p){
** fill pTabList->a[].pSelect with a copy of the SELECT statement
** that implements the view. A copy is made of the view's SELECT
** statement so that we can freely modify or delete that statement
-** without worrying about messing up the presistent representation
+** without worrying about messing up the persistent representation
** of the view.
**
-** (3) Add terms to the WHERE clause to accomodate the NATURAL keyword
+** (3) Add terms to the WHERE clause to accommodate the NATURAL keyword
** on joins and the ON and USING clause of joins.
**
** (4) Scan the list of columns in the result set (pEList) looking
@@ -105472,7 +110664,9 @@ static int selectExpander(Walker *pWalker, Select *p){
}
pTabList = p->pSrc;
pEList = p->pEList;
- sqlite3WithPush(pParse, findRightmost(p)->pWith, 0);
+ if( pWalker->xSelectCallback2==selectPopWith ){
+ sqlite3WithPush(pParse, findRightmost(p)->pWith, 0);
+ }
/* Make sure cursor numbers have been assigned to all entries in
** the FROM clause of the SELECT statement.
@@ -105506,7 +110700,7 @@ static int selectExpander(Walker *pWalker, Select *p){
/* A sub-query in the FROM clause of a SELECT */
assert( pSel!=0 );
assert( pFrom->pTab==0 );
- sqlite3WalkSelect(pWalker, pSel);
+ if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort;
pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
if( pTab==0 ) return WRC_Abort;
pTab->nRef = 1;
@@ -105535,6 +110729,7 @@ static int selectExpander(Walker *pWalker, Select *p){
if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort;
assert( pFrom->pSelect==0 );
pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0);
+ sqlite3SelectSetName(pFrom->pSelect, pTab->zName);
sqlite3WalkSelect(pWalker, pFrom->pSelect);
}
#endif
@@ -105762,7 +110957,9 @@ static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){
sqlite3WalkSelect(&w, pSelect);
}
w.xSelectCallback = selectExpander;
- w.xSelectCallback2 = selectPopWith;
+ if( (pSelect->selFlags & SF_MultiValue)==0 ){
+ w.xSelectCallback2 = selectPopWith;
+ }
sqlite3WalkSelect(&w, pSelect);
}
@@ -105946,7 +111143,8 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
}
if( pF->iDistinct>=0 ){
addrNext = sqlite3VdbeMakeLabel(v);
- assert( nArg==1 );
+ testcase( nArg==0 ); /* Error condition */
+ testcase( nArg>1 ); /* Also an error */
codeDistinct(pParse, pF->iDistinct, addrNext, 1, regAgg);
}
if( pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){
@@ -106069,6 +111267,13 @@ SQLITE_PRIVATE int sqlite3Select(
}
if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
memset(&sAggInfo, 0, sizeof(sAggInfo));
+#if SELECTTRACE_ENABLED
+ pParse->nSelectIndent++;
+ SELECTTRACE(1,pParse,p, ("begin processing:\n"));
+ if( sqlite3SelectTrace & 0x100 ){
+ sqlite3TreeViewSelect(0, p, 0);
+ }
+#endif
assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistFifo );
assert( p->pOrderBy==0 || pDest->eDest!=SRT_Fifo );
@@ -106095,6 +111300,13 @@ SQLITE_PRIVATE int sqlite3Select(
}
isAgg = (p->selFlags & SF_Aggregate)!=0;
assert( pEList!=0 );
+#if SELECTTRACE_ENABLED
+ if( sqlite3SelectTrace & 0x100 ){
+ SELECTTRACE(0x100,pParse,p, ("after name resolution:\n"));
+ sqlite3TreeViewSelect(0, p, 0);
+ }
+#endif
+
/* Begin generating code.
*/
@@ -106225,6 +111437,10 @@ SQLITE_PRIVATE int sqlite3Select(
if( p->pPrior ){
rc = multiSelect(pParse, p, pDest);
explainSetInteger(pParse->iSelectId, iRestoreSelectId);
+#if SELECTTRACE_ENABLED
+ SELECTTRACE(1,pParse,p,("end compound-select processing\n"));
+ pParse->nSelectIndent--;
+#endif
return rc;
}
#endif
@@ -106237,7 +111453,7 @@ SQLITE_PRIVATE int sqlite3Select(
**
** is transformed to:
**
- ** SELECT xyz FROM ... GROUP BY xyz
+ ** SELECT xyz FROM ... GROUP BY xyz ORDER BY xyz
**
** The second form is preferred as a single index (or temp-table) may be
** used for both the ORDER BY and DISTINCT processing. As originally
@@ -106250,7 +111466,6 @@ SQLITE_PRIVATE int sqlite3Select(
p->selFlags &= ~SF_Distinct;
p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0);
pGroupBy = p->pGroupBy;
- sSort.pOrderBy = 0;
/* Notice that even thought SF_Distinct has been cleared from p->selFlags,
** the sDistinct.isTnct is still set. Hence, isTnct represents the
** original setting of the SF_Distinct flag, not the current setting */
@@ -106266,12 +111481,13 @@ SQLITE_PRIVATE int sqlite3Select(
*/
if( sSort.pOrderBy ){
KeyInfo *pKeyInfo;
- pKeyInfo = keyInfoFromExprList(pParse, sSort.pOrderBy, 0, 0);
+ pKeyInfo = keyInfoFromExprList(pParse, sSort.pOrderBy, 0, pEList->nExpr);
sSort.iECursor = pParse->nTab++;
sSort.addrSortIndex =
sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
- sSort.iECursor, sSort.pOrderBy->nExpr+2, 0,
- (char*)pKeyInfo, P4_KEYINFO);
+ sSort.iECursor, sSort.pOrderBy->nExpr+1+pEList->nExpr, 0,
+ (char*)pKeyInfo, P4_KEYINFO
+ );
}else{
sSort.addrSortIndex = -1;
}
@@ -106402,7 +111618,7 @@ SQLITE_PRIVATE int sqlite3Select(
sNC.pSrcList = pTabList;
sNC.pAggInfo = &sAggInfo;
sAggInfo.mnReg = pParse->nMem+1;
- sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr+1 : 0;
+ sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0;
sAggInfo.pGroupBy = pGroupBy;
sqlite3ExprAnalyzeAggList(&sNC, pEList);
sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy);
@@ -106439,7 +111655,7 @@ SQLITE_PRIVATE int sqlite3Select(
** will be converted into a Noop.
*/
sAggInfo.sortingIdx = pParse->nTab++;
- pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0, 0);
+ pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0, sAggInfo.nColumn);
addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen,
sAggInfo.sortingIdx, sAggInfo.nSortingColumn,
0, (char*)pKeyInfo, P4_KEYINFO);
@@ -106495,8 +111711,8 @@ SQLITE_PRIVATE int sqlite3Select(
groupBySort = 1;
nGroupBy = pGroupBy->nExpr;
- nCol = nGroupBy + 1;
- j = nGroupBy+1;
+ nCol = nGroupBy;
+ j = nGroupBy;
for(i=0; i<sAggInfo.nColumn; i++){
if( sAggInfo.aCol[i].iSorterColumn>=j ){
nCol++;
@@ -106506,8 +111722,7 @@ SQLITE_PRIVATE int sqlite3Select(
regBase = sqlite3GetTempRange(pParse, nCol);
sqlite3ExprCacheClear(pParse);
sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0);
- sqlite3VdbeAddOp2(v, OP_Sequence, sAggInfo.sortingIdx,regBase+nGroupBy);
- j = nGroupBy+1;
+ j = nGroupBy;
for(i=0; i<sAggInfo.nColumn; i++){
struct AggInfo_col *pCol = &sAggInfo.aCol[i];
if( pCol->iSorterColumn>=j ){
@@ -106560,12 +111775,11 @@ SQLITE_PRIVATE int sqlite3Select(
addrTopOfLoop = sqlite3VdbeCurrentAddr(v);
sqlite3ExprCacheClear(pParse);
if( groupBySort ){
- sqlite3VdbeAddOp2(v, OP_SorterData, sAggInfo.sortingIdx, sortOut);
+ sqlite3VdbeAddOp3(v, OP_SorterData, sAggInfo.sortingIdx, sortOut,sortPTab);
}
for(j=0; j<pGroupBy->nExpr; j++){
if( groupBySort ){
sqlite3VdbeAddOp3(v, OP_Column, sortPTab, j, iBMem+j);
- if( j==0 ) sqlite3VdbeChangeP5(v, OPFLAG_CLEARCACHE);
}else{
sAggInfo.directMode = 1;
sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr, iBMem+j);
@@ -106805,10 +112019,9 @@ SQLITE_PRIVATE int sqlite3Select(
*/
sqlite3VdbeResolveLabel(v, iEnd);
- /* The SELECT was successfully coded. Set the return code to 0
- ** to indicate no errors.
- */
- rc = 0;
+ /* The SELECT has been coded. If there is an error in the Parse structure,
+ ** set the return code to 1. Otherwise 0. */
+ rc = (pParse->nErr>0);
/* Control jumps to here if an error is encountered above, or upon
** successful coding of the SELECT.
@@ -106824,103 +112037,106 @@ select_end:
sqlite3DbFree(db, sAggInfo.aCol);
sqlite3DbFree(db, sAggInfo.aFunc);
+#if SELECTTRACE_ENABLED
+ SELECTTRACE(1,pParse,p,("end processing\n"));
+ pParse->nSelectIndent--;
+#endif
return rc;
}
-#if defined(SQLITE_ENABLE_TREE_EXPLAIN)
+#ifdef SQLITE_DEBUG
/*
** Generate a human-readable description of a the Select object.
*/
-static void explainOneSelect(Vdbe *pVdbe, Select *p){
- sqlite3ExplainPrintf(pVdbe, "SELECT ");
- if( p->selFlags & (SF_Distinct|SF_Aggregate) ){
- if( p->selFlags & SF_Distinct ){
- sqlite3ExplainPrintf(pVdbe, "DISTINCT ");
- }
- if( p->selFlags & SF_Aggregate ){
- sqlite3ExplainPrintf(pVdbe, "agg_flag ");
- }
- sqlite3ExplainNL(pVdbe);
- sqlite3ExplainPrintf(pVdbe, " ");
- }
- sqlite3ExplainExprList(pVdbe, p->pEList);
- sqlite3ExplainNL(pVdbe);
+SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
+ int n = 0;
+ pView = sqlite3TreeViewPush(pView, moreToFollow);
+ sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p)",
+ ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""),
+ ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p
+ );
+ if( p->pSrc && p->pSrc->nSrc ) n++;
+ if( p->pWhere ) n++;
+ if( p->pGroupBy ) n++;
+ if( p->pHaving ) n++;
+ if( p->pOrderBy ) n++;
+ if( p->pLimit ) n++;
+ if( p->pOffset ) n++;
+ if( p->pPrior ) n++;
+ sqlite3TreeViewExprList(pView, p->pEList, (n--)>0, "result-set");
if( p->pSrc && p->pSrc->nSrc ){
int i;
- sqlite3ExplainPrintf(pVdbe, "FROM ");
- sqlite3ExplainPush(pVdbe);
+ pView = sqlite3TreeViewPush(pView, (n--)>0);
+ sqlite3TreeViewLine(pView, "FROM");
for(i=0; i<p->pSrc->nSrc; i++){
struct SrcList_item *pItem = &p->pSrc->a[i];
- sqlite3ExplainPrintf(pVdbe, "{%d,*} = ", pItem->iCursor);
- if( pItem->pSelect ){
- sqlite3ExplainSelect(pVdbe, pItem->pSelect);
- if( pItem->pTab ){
- sqlite3ExplainPrintf(pVdbe, " (tabname=%s)", pItem->pTab->zName);
- }
+ StrAccum x;
+ char zLine[100];
+ sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
+ sqlite3XPrintf(&x, 0, "{%d,*}", pItem->iCursor);
+ if( pItem->zDatabase ){
+ sqlite3XPrintf(&x, 0, " %s.%s", pItem->zDatabase, pItem->zName);
}else if( pItem->zName ){
- sqlite3ExplainPrintf(pVdbe, "%s", pItem->zName);
+ sqlite3XPrintf(&x, 0, " %s", pItem->zName);
+ }
+ if( pItem->pTab ){
+ sqlite3XPrintf(&x, 0, " tabname=%Q", pItem->pTab->zName);
}
if( pItem->zAlias ){
- sqlite3ExplainPrintf(pVdbe, " (AS %s)", pItem->zAlias);
+ sqlite3XPrintf(&x, 0, " (AS %s)", pItem->zAlias);
}
if( pItem->jointype & JT_LEFT ){
- sqlite3ExplainPrintf(pVdbe, " LEFT-JOIN");
+ sqlite3XPrintf(&x, 0, " LEFT-JOIN");
}
- sqlite3ExplainNL(pVdbe);
+ sqlite3StrAccumFinish(&x);
+ sqlite3TreeViewItem(pView, zLine, i<p->pSrc->nSrc-1);
+ if( pItem->pSelect ){
+ sqlite3TreeViewSelect(pView, pItem->pSelect, 0);
+ }
+ sqlite3TreeViewPop(pView);
}
- sqlite3ExplainPop(pVdbe);
+ sqlite3TreeViewPop(pView);
}
if( p->pWhere ){
- sqlite3ExplainPrintf(pVdbe, "WHERE ");
- sqlite3ExplainExpr(pVdbe, p->pWhere);
- sqlite3ExplainNL(pVdbe);
+ sqlite3TreeViewItem(pView, "WHERE", (n--)>0);
+ sqlite3TreeViewExpr(pView, p->pWhere, 0);
+ sqlite3TreeViewPop(pView);
}
if( p->pGroupBy ){
- sqlite3ExplainPrintf(pVdbe, "GROUPBY ");
- sqlite3ExplainExprList(pVdbe, p->pGroupBy);
- sqlite3ExplainNL(pVdbe);
+ sqlite3TreeViewExprList(pView, p->pGroupBy, (n--)>0, "GROUPBY");
}
if( p->pHaving ){
- sqlite3ExplainPrintf(pVdbe, "HAVING ");
- sqlite3ExplainExpr(pVdbe, p->pHaving);
- sqlite3ExplainNL(pVdbe);
+ sqlite3TreeViewItem(pView, "HAVING", (n--)>0);
+ sqlite3TreeViewExpr(pView, p->pHaving, 0);
+ sqlite3TreeViewPop(pView);
}
if( p->pOrderBy ){
- sqlite3ExplainPrintf(pVdbe, "ORDERBY ");
- sqlite3ExplainExprList(pVdbe, p->pOrderBy);
- sqlite3ExplainNL(pVdbe);
+ sqlite3TreeViewExprList(pView, p->pOrderBy, (n--)>0, "ORDERBY");
}
if( p->pLimit ){
- sqlite3ExplainPrintf(pVdbe, "LIMIT ");
- sqlite3ExplainExpr(pVdbe, p->pLimit);
- sqlite3ExplainNL(pVdbe);
+ sqlite3TreeViewItem(pView, "LIMIT", (n--)>0);
+ sqlite3TreeViewExpr(pView, p->pLimit, 0);
+ sqlite3TreeViewPop(pView);
}
if( p->pOffset ){
- sqlite3ExplainPrintf(pVdbe, "OFFSET ");
- sqlite3ExplainExpr(pVdbe, p->pOffset);
- sqlite3ExplainNL(pVdbe);
+ sqlite3TreeViewItem(pView, "OFFSET", (n--)>0);
+ sqlite3TreeViewExpr(pView, p->pOffset, 0);
+ sqlite3TreeViewPop(pView);
}
-}
-SQLITE_PRIVATE void sqlite3ExplainSelect(Vdbe *pVdbe, Select *p){
- if( p==0 ){
- sqlite3ExplainPrintf(pVdbe, "(null-select)");
- return;
- }
- sqlite3ExplainPush(pVdbe);
- while( p ){
- explainOneSelect(pVdbe, p);
- p = p->pNext;
- if( p==0 ) break;
- sqlite3ExplainNL(pVdbe);
- sqlite3ExplainPrintf(pVdbe, "%s\n", selectOpName(p->op));
+ if( p->pPrior ){
+ const char *zOp = "UNION";
+ switch( p->op ){
+ case TK_ALL: zOp = "UNION ALL"; break;
+ case TK_INTERSECT: zOp = "INTERSECT"; break;
+ case TK_EXCEPT: zOp = "EXCEPT"; break;
+ }
+ sqlite3TreeViewItem(pView, zOp, (n--)>0);
+ sqlite3TreeViewSelect(pView, p->pPrior, 0);
+ sqlite3TreeViewPop(pView);
}
- sqlite3ExplainPrintf(pVdbe, "END");
- sqlite3ExplainPop(pVdbe);
+ sqlite3TreeViewPop(pView);
}
-
-/* End of the structure debug printing code
-*****************************************************************************/
-#endif /* defined(SQLITE_ENABLE_TREE_EXPLAIN) */
+#endif /* SQLITE_DEBUG */
/************** End of select.c **********************************************/
/************** Begin file table.c *******************************************/
@@ -106954,10 +112170,10 @@ SQLITE_PRIVATE void sqlite3ExplainSelect(Vdbe *pVdbe, Select *p){
typedef struct TabResult {
char **azResult; /* Accumulated output */
char *zErrMsg; /* Error message text, if an error occurs */
- int nAlloc; /* Slots allocated for azResult[] */
- int nRow; /* Number of rows in the result */
- int nColumn; /* Number of columns in the result */
- int nData; /* Slots used in azResult[]. (nRow+1)*nColumn */
+ u32 nAlloc; /* Slots allocated for azResult[] */
+ u32 nRow; /* Number of rows in the result */
+ u32 nColumn; /* Number of columns in the result */
+ u32 nData; /* Slots used in azResult[]. (nRow+1)*nColumn */
int rc; /* Return code from sqlite3_exec() */
} TabResult;
@@ -106983,7 +112199,7 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
if( p->nData + need > p->nAlloc ){
char **azNew;
p->nAlloc = p->nAlloc*2 + need;
- azNew = sqlite3_realloc( p->azResult, sizeof(char*)*p->nAlloc );
+ azNew = sqlite3_realloc64( p->azResult, sizeof(char*)*p->nAlloc );
if( azNew==0 ) goto malloc_failed;
p->azResult = azNew;
}
@@ -106998,7 +112214,7 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
if( z==0 ) goto malloc_failed;
p->azResult[p->nData++] = z;
}
- }else if( p->nColumn!=nCol ){
+ }else if( (int)p->nColumn!=nCol ){
sqlite3_free(p->zErrMsg);
p->zErrMsg = sqlite3_mprintf(
"sqlite3_get_table() called with two or more incompatible queries"
@@ -107015,7 +112231,7 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
z = 0;
}else{
int n = sqlite3Strlen30(argv[i])+1;
- z = sqlite3_malloc( n );
+ z = sqlite3_malloc64( n );
if( z==0 ) goto malloc_failed;
memcpy(z, argv[i], n);
}
@@ -107040,7 +112256,7 @@ malloc_failed:
** Instead, the entire table should be passed to sqlite3_free_table() when
** the calling procedure is finished using it.
*/
-SQLITE_API int sqlite3_get_table(
+SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
sqlite3 *db, /* The database on which the SQL executes */
const char *zSql, /* The SQL to be executed */
char ***pazResult, /* Write the result table here */
@@ -107051,6 +112267,9 @@ SQLITE_API int sqlite3_get_table(
int rc;
TabResult res;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) || pazResult==0 ) return SQLITE_MISUSE_BKPT;
+#endif
*pazResult = 0;
if( pnColumn ) *pnColumn = 0;
if( pnRow ) *pnRow = 0;
@@ -107061,7 +112280,7 @@ SQLITE_API int sqlite3_get_table(
res.nData = 1;
res.nAlloc = 20;
res.rc = SQLITE_OK;
- res.azResult = sqlite3_malloc(sizeof(char*)*res.nAlloc );
+ res.azResult = sqlite3_malloc64(sizeof(char*)*res.nAlloc );
if( res.azResult==0 ){
db->errCode = SQLITE_NOMEM;
return SQLITE_NOMEM;
@@ -107089,7 +112308,7 @@ SQLITE_API int sqlite3_get_table(
}
if( res.nAlloc>res.nData ){
char **azNew;
- azNew = sqlite3_realloc( res.azResult, sizeof(char*)*res.nData );
+ azNew = sqlite3_realloc64( res.azResult, sizeof(char*)*res.nData );
if( azNew==0 ){
sqlite3_free_table(&res.azResult[1]);
db->errCode = SQLITE_NOMEM;
@@ -107106,8 +112325,8 @@ SQLITE_API int sqlite3_get_table(
/*
** This routine frees the space the sqlite3_get_table() malloced.
*/
-SQLITE_API void sqlite3_free_table(
- char **azResult /* Result returned from from sqlite3_get_table() */
+SQLITE_API void SQLITE_STDCALL sqlite3_free_table(
+ char **azResult /* Result returned from sqlite3_get_table() */
){
if( azResult ){
int i, n;
@@ -107251,7 +112470,7 @@ SQLITE_PRIVATE void sqlite3BeginTrigger(
** ^^^^^^^^
**
** To maintain backwards compatibility, ignore the database
- ** name on pTableName if we are reparsing our of SQLITE_MASTER.
+ ** name on pTableName if we are reparsing out of SQLITE_MASTER.
*/
if( db->init.busy && iDb!=1 ){
sqlite3DbFree(db, pTableName->a[0].zDatabase);
@@ -107304,8 +112523,7 @@ SQLITE_PRIVATE void sqlite3BeginTrigger(
goto trigger_cleanup;
}
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
- if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash),
- zName, sqlite3Strlen30(zName)) ){
+ if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash),zName) ){
if( !noErr ){
sqlite3ErrorMsg(pParse, "trigger %T already exists", pName);
}else{
@@ -107318,7 +112536,6 @@ SQLITE_PRIVATE void sqlite3BeginTrigger(
/* Do not create a trigger on a system table */
if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 ){
sqlite3ErrorMsg(pParse, "cannot create trigger on system table");
- pParse->nErr++;
goto trigger_cleanup;
}
@@ -107448,13 +112665,12 @@ SQLITE_PRIVATE void sqlite3FinishTrigger(
Trigger *pLink = pTrig;
Hash *pHash = &db->aDb[iDb].pSchema->trigHash;
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
- pTrig = sqlite3HashInsert(pHash, zName, sqlite3Strlen30(zName), pTrig);
+ pTrig = sqlite3HashInsert(pHash, zName, pTrig);
if( pTrig ){
db->mallocFailed = 1;
}else if( pLink->pSchema==pLink->pTabSchema ){
Table *pTab;
- int n = sqlite3Strlen30(pLink->table);
- pTab = sqlite3HashFind(&pLink->pTabSchema->tblHash, pLink->table, n);
+ pTab = sqlite3HashFind(&pLink->pTabSchema->tblHash, pLink->table);
assert( pTab!=0 );
pLink->pNext = pTab->pTrigger;
pTab->pTrigger = pLink;
@@ -107499,12 +112715,12 @@ static TriggerStep *triggerStepAllocate(
){
TriggerStep *pTriggerStep;
- pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep) + pName->n);
+ pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep) + pName->n + 1);
if( pTriggerStep ){
char *z = (char*)&pTriggerStep[1];
memcpy(z, pName->z, pName->n);
- pTriggerStep->target.z = z;
- pTriggerStep->target.n = pName->n;
+ sqlite3Dequote(z);
+ pTriggerStep->zTarget = z;
pTriggerStep->op = op;
}
return pTriggerStep;
@@ -107613,7 +112829,6 @@ SQLITE_PRIVATE void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr)
int i;
const char *zDb;
const char *zName;
- int nName;
sqlite3 *db = pParse->db;
if( db->mallocFailed ) goto drop_trigger_cleanup;
@@ -107624,13 +112839,12 @@ SQLITE_PRIVATE void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr)
assert( pName->nSrc==1 );
zDb = pName->a[0].zDatabase;
zName = pName->a[0].zName;
- nName = sqlite3Strlen30(zName);
assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) );
for(i=OMIT_TEMPDB; i<db->nDb; i++){
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
if( zDb && sqlite3StrICmp(db->aDb[j].zName, zDb) ) continue;
assert( sqlite3SchemaMutexHeld(db, j, 0) );
- pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName, nName);
+ pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName);
if( pTrigger ) break;
}
if( !pTrigger ){
@@ -107653,8 +112867,7 @@ drop_trigger_cleanup:
** is set on.
*/
static Table *tableOfTrigger(Trigger *pTrigger){
- int n = sqlite3Strlen30(pTrigger->table);
- return sqlite3HashFind(&pTrigger->pTabSchema->tblHash, pTrigger->table, n);
+ return sqlite3HashFind(&pTrigger->pTabSchema->tblHash, pTrigger->table);
}
@@ -107726,7 +112939,7 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const ch
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
pHash = &(db->aDb[iDb].pSchema->trigHash);
- pTrigger = sqlite3HashInsert(pHash, zName, sqlite3Strlen30(zName), 0);
+ pTrigger = sqlite3HashInsert(pHash, zName, 0);
if( ALWAYS(pTrigger) ){
if( pTrigger->pSchema==pTrigger->pTabSchema ){
Table *pTab = tableOfTrigger(pTrigger);
@@ -107790,7 +113003,7 @@ SQLITE_PRIVATE Trigger *sqlite3TriggersExist(
}
/*
-** Convert the pStep->target token into a SrcList and return a pointer
+** Convert the pStep->zTarget string into a SrcList and return a pointer
** to that SrcList.
**
** This routine adds a specific database name, if needed, to the target when
@@ -107803,17 +113016,17 @@ static SrcList *targetSrcList(
Parse *pParse, /* The parsing context */
TriggerStep *pStep /* The trigger containing the target token */
){
+ sqlite3 *db = pParse->db;
int iDb; /* Index of the database to use */
SrcList *pSrc; /* SrcList to be returned */
- pSrc = sqlite3SrcListAppend(pParse->db, 0, &pStep->target, 0);
+ pSrc = sqlite3SrcListAppend(db, 0, 0, 0);
if( pSrc ){
assert( pSrc->nSrc>0 );
- assert( pSrc->a!=0 );
- iDb = sqlite3SchemaToIndex(pParse->db, pStep->pTrig->pSchema);
+ pSrc->a[pSrc->nSrc-1].zName = sqlite3DbStrDup(db, pStep->zTarget);
+ iDb = sqlite3SchemaToIndex(db, pStep->pTrig->pSchema);
if( iDb==0 || iDb>=2 ){
- sqlite3 *db = pParse->db;
- assert( iDb<pParse->db->nDb );
+ assert( iDb<db->nDb );
pSrc->a[pSrc->nSrc-1].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zName);
}
}
@@ -107925,6 +113138,7 @@ static void transferParseError(Parse *pTo, Parse *pFrom){
if( pTo->nErr==0 ){
pTo->zErrMsg = pFrom->zErrMsg;
pTo->nErr = pFrom->nErr;
+ pTo->rc = pFrom->rc;
}else{
sqlite3DbFree(pFrom->db, pFrom->zErrMsg);
}
@@ -108577,7 +113791,7 @@ SQLITE_PRIVATE void sqlite3Update(
}
/* If we are trying to update a view, realize that view into
- ** a ephemeral table.
+ ** an ephemeral table.
*/
#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
if( isView ){
@@ -108681,8 +113895,8 @@ SQLITE_PRIVATE void sqlite3Update(
/* Top of the update loop */
if( okOnePass ){
- if( aToOpen[iDataCur-iBaseCur] ){
- assert( pPk!=0 );
+ if( aToOpen[iDataCur-iBaseCur] && !isView ){
+ assert( pPk );
sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey, nKey);
VdbeCoverageNeverTaken(v);
}
@@ -108738,7 +113952,7 @@ SQLITE_PRIVATE void sqlite3Update(
}
/* Populate the array of registers beginning at regNew with the new
- ** row data. This array is used to check constaints, create the new
+ ** row data. This array is used to check constants, create the new
** table and index records, and as the values for any new.* references
** made by triggers.
**
@@ -108918,7 +114132,7 @@ update_cleanup:
return;
}
/* Make sure "isView" and other macros defined above are undefined. Otherwise
-** thely may interfere with compilation of other functions in this file
+** they may interfere with compilation of other functions in this file
** (or in another file, if this file becomes part of the amalgamation). */
#ifdef isView
#undef isView
@@ -108931,7 +114145,7 @@ update_cleanup:
/*
** Generate code for an UPDATE of a virtual table.
**
-** The strategy is that we create an ephemerial table that contains
+** The strategy is that we create an ephemeral table that contains
** for each row to be changed:
**
** (A) The original rowid of that row.
@@ -108939,7 +114153,7 @@ update_cleanup:
** (C) The content of every column in the row.
**
** Then we loop over this ephemeral table and for each row in
-** the ephermeral table call VUpdate.
+** the ephemeral table call VUpdate.
**
** When finished, drop the ephemeral table.
**
@@ -109112,14 +114326,14 @@ static int execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
** step (3) requires additional temporary disk space approximately equal
** to the size of the original database for the rollback journal.
** Hence, temporary disk space that is approximately 2x the size of the
-** orginal database is required. Every page of the database is written
+** original database is required. Every page of the database is written
** approximately 3 times: Once for step (2) and twice for step (3).
** Two writes per page are required in step (3) because the original
** database content must be written into the rollback journal prior to
** overwriting the database with the vacuumed content.
**
** Only 1x temporary space and only 1x writes would be required if
-** the copy of step (3) were replace by deleting the original database
+** the copy of step (3) were replaced by deleting the original database
** and renaming the transient database as the original. But that will
** not work if other processes are attached to the original database.
** And a power loss in between deleting the original and renaming the
@@ -109209,7 +114423,7 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
** cause problems for the call to BtreeSetPageSize() below. */
sqlite3BtreeCommit(pTemp);
- nRes = sqlite3BtreeGetReserve(pMain);
+ nRes = sqlite3BtreeGetOptimalReserve(pMain);
/* A VACUUM cannot change the pagesize of an encrypted database. */
#ifdef SQLITE_HAS_CODEC
@@ -109275,6 +114489,8 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
** an "INSERT INTO vacuum_db.xxx SELECT * FROM main.xxx;" to copy
** the contents to the temporary database.
*/
+ assert( (db->flags & SQLITE_Vacuum)==0 );
+ db->flags |= SQLITE_Vacuum;
rc = execExecSql(db, pzErrMsg,
"SELECT 'INSERT INTO vacuum_db.' || quote(name) "
"|| ' SELECT * FROM main.' || quote(name) || ';'"
@@ -109282,6 +114498,8 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
"WHERE type = 'table' AND name!='sqlite_sequence' "
" AND coalesce(rootpage,1)>0"
);
+ assert( (db->flags & SQLITE_Vacuum)!=0 );
+ db->flags &= ~SQLITE_Vacuum;
if( rc!=SQLITE_OK ) goto end_of_vacuum;
/* Copy over the sequence table
@@ -109420,6 +114638,8 @@ end_of_vacuum:
struct VtabCtx {
VTable *pVTable; /* The virtual table being constructed */
Table *pTab; /* The Table object to which the virtual table belongs */
+ VtabCtx *pPrior; /* Parent context (if any) */
+ int bDeclared; /* True after sqlite3_declare_vtab() is called */
};
/*
@@ -109439,7 +114659,7 @@ static int createModule(
sqlite3_mutex_enter(db->mutex);
nName = sqlite3Strlen30(zName);
- if( sqlite3HashFind(&db->aModule, zName, nName) ){
+ if( sqlite3HashFind(&db->aModule, zName) ){
rc = SQLITE_MISUSE_BKPT;
}else{
Module *pMod;
@@ -109452,7 +114672,7 @@ static int createModule(
pMod->pModule = pModule;
pMod->pAux = pAux;
pMod->xDestroy = xDestroy;
- pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,nName,(void*)pMod);
+ pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod);
assert( pDel==0 || pDel==pMod );
if( pDel ){
db->mallocFailed = 1;
@@ -109471,25 +114691,31 @@ static int createModule(
/*
** External API function used to create a new virtual-table module.
*/
-SQLITE_API int sqlite3_create_module(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_module(
sqlite3 *db, /* Database in which module is registered */
const char *zName, /* Name assigned to this module */
const sqlite3_module *pModule, /* The definition of the module */
void *pAux /* Context pointer for xCreate/xConnect */
){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT;
+#endif
return createModule(db, zName, pModule, pAux, 0);
}
/*
** External API function used to create a new virtual-table module.
*/
-SQLITE_API int sqlite3_create_module_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_module_v2(
sqlite3 *db, /* Database in which module is registered */
const char *zName, /* Name assigned to this module */
const sqlite3_module *pModule, /* The definition of the module */
void *pAux, /* Context pointer for xCreate/xConnect */
void (*xDestroy)(void *) /* Module destructor function */
){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT;
+#endif
return createModule(db, zName, pModule, pAux, xDestroy);
}
@@ -109722,7 +114948,12 @@ SQLITE_PRIVATE void sqlite3VtabBeginParse(
addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName));
addModuleArgument(db, pTable, 0);
addModuleArgument(db, pTable, sqlite3DbStrDup(db, pTable->zName));
- pParse->sNameToken.n = (int)(&pModuleName->z[pModuleName->n] - pName1->z);
+ assert( (pParse->sNameToken.z==pName2->z && pName2->z!=0)
+ || (pParse->sNameToken.z==pName1->z && pName2->z==0)
+ );
+ pParse->sNameToken.n = (int)(
+ &pModuleName->z[pModuleName->n] - pParse->sNameToken.z
+ );
#ifndef SQLITE_OMIT_AUTHORIZATION
/* Creating a virtual table invokes the authorization callback twice.
@@ -109774,6 +115005,7 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
char *zStmt;
char *zWhere;
int iDb;
+ int iReg;
Vdbe *v;
/* Compute the complete text of the CREATE VIRTUAL TABLE statement */
@@ -109808,8 +115040,10 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
sqlite3VdbeAddOp2(v, OP_Expire, 0, 0);
zWhere = sqlite3MPrintf(db, "name='%q' AND type='table'", pTab->zName);
sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere);
- sqlite3VdbeAddOp4(v, OP_VCreate, iDb, 0, 0,
- pTab->zName, sqlite3Strlen30(pTab->zName) + 1);
+
+ iReg = ++pParse->nMem;
+ sqlite3VdbeAddOp4(v, OP_String8, 0, iReg, 0, pTab->zName, 0);
+ sqlite3VdbeAddOp2(v, OP_VCreate, iDb, iReg);
}
/* If we are rereading the sqlite_master table create the in-memory
@@ -109821,9 +115055,8 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
Table *pOld;
Schema *pSchema = pTab->pSchema;
const char *zName = pTab->zName;
- int nName = sqlite3Strlen30(zName);
assert( sqlite3SchemaMutexHeld(db, 0, pSchema) );
- pOld = sqlite3HashInsert(&pSchema->tblHash, zName, nName, pTab);
+ pOld = sqlite3HashInsert(&pSchema->tblHash, zName, pTab);
if( pOld ){
db->mallocFailed = 1;
assert( pTab==pOld ); /* Malloc must have failed inside HashInsert() */
@@ -109853,7 +115086,7 @@ SQLITE_PRIVATE void sqlite3VtabArgExtend(Parse *pParse, Token *p){
pArg->z = p->z;
pArg->n = p->n;
}else{
- assert(pArg->z < p->z);
+ assert(pArg->z <= p->z);
pArg->n = (int)(&p->z[p->n] - pArg->z);
}
}
@@ -109870,15 +115103,27 @@ static int vtabCallConstructor(
int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**),
char **pzErr
){
- VtabCtx sCtx, *pPriorCtx;
+ VtabCtx sCtx;
VTable *pVTable;
int rc;
const char *const*azArg = (const char *const*)pTab->azModuleArg;
int nArg = pTab->nModuleArg;
char *zErr = 0;
- char *zModuleName = sqlite3MPrintf(db, "%s", pTab->zName);
+ char *zModuleName;
int iDb;
+ VtabCtx *pCtx;
+
+ /* Check that the virtual-table is not already being initialized */
+ for(pCtx=db->pVtabCtx; pCtx; pCtx=pCtx->pPrior){
+ if( pCtx->pTab==pTab ){
+ *pzErr = sqlite3MPrintf(db,
+ "vtable constructor called recursively: %s", pTab->zName
+ );
+ return SQLITE_LOCKED;
+ }
+ }
+ zModuleName = sqlite3MPrintf(db, "%s", pTab->zName);
if( !zModuleName ){
return SQLITE_NOMEM;
}
@@ -109899,11 +115144,13 @@ static int vtabCallConstructor(
assert( xConstruct );
sCtx.pTab = pTab;
sCtx.pVTable = pVTable;
- pPriorCtx = db->pVtabCtx;
+ sCtx.pPrior = db->pVtabCtx;
+ sCtx.bDeclared = 0;
db->pVtabCtx = &sCtx;
rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr);
- db->pVtabCtx = pPriorCtx;
+ db->pVtabCtx = sCtx.pPrior;
if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
+ assert( sCtx.pTab==pTab );
if( SQLITE_OK!=rc ){
if( zErr==0 ){
@@ -109916,15 +115163,17 @@ static int vtabCallConstructor(
}else if( ALWAYS(pVTable->pVtab) ){
/* Justification of ALWAYS(): A correct vtab constructor must allocate
** the sqlite3_vtab object if successful. */
+ memset(pVTable->pVtab, 0, sizeof(pVTable->pVtab[0]));
pVTable->pVtab->pModule = pMod->pModule;
pVTable->nRef = 1;
- if( sCtx.pTab ){
+ if( sCtx.bDeclared==0 ){
const char *zFormat = "vtable constructor did not declare schema: %s";
*pzErr = sqlite3MPrintf(db, zFormat, pTab->zName);
sqlite3VtabUnlock(pVTable);
rc = SQLITE_ERROR;
}else{
int iCol;
+ u8 oooHidden = 0;
/* If everything went according to plan, link the new VTable structure
** into the linked list headed by pTab->pVTable. Then loop through the
** columns of the table to see if any of them contain the token "hidden".
@@ -109937,7 +115186,10 @@ static int vtabCallConstructor(
char *zType = pTab->aCol[iCol].zType;
int nType;
int i = 0;
- if( !zType ) continue;
+ if( !zType ){
+ pTab->tabFlags |= oooHidden;
+ continue;
+ }
nType = sqlite3Strlen30(zType);
if( sqlite3StrNICmp("hidden", zType, 6)||(zType[6] && zType[6]!=' ') ){
for(i=0; i<nType; i++){
@@ -109960,6 +115212,9 @@ static int vtabCallConstructor(
zType[i-1] = '\0';
}
pTab->aCol[iCol].colFlags |= COLFLAG_HIDDEN;
+ oooHidden = TF_OOOHidden;
+ }else{
+ pTab->tabFlags |= oooHidden;
}
}
}
@@ -109989,7 +115244,7 @@ SQLITE_PRIVATE int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
/* Locate the required virtual table module */
zMod = pTab->azModuleArg[0];
- pMod = (Module*)sqlite3HashFind(&db->aModule, zMod, sqlite3Strlen30(zMod));
+ pMod = (Module*)sqlite3HashFind(&db->aModule, zMod);
if( !pMod ){
const char *zModule = pTab->azModuleArg[0];
@@ -110057,7 +115312,7 @@ SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab,
/* Locate the required virtual table module */
zMod = pTab->azModuleArg[0];
- pMod = (Module*)sqlite3HashFind(&db->aModule, zMod, sqlite3Strlen30(zMod));
+ pMod = (Module*)sqlite3HashFind(&db->aModule, zMod);
/* If the module has been registered and includes a Create method,
** invoke it now. If the module has not been registered, return an
@@ -110087,19 +115342,26 @@ SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab,
** valid to call this function from within the xCreate() or xConnect() of a
** virtual table module.
*/
-SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
+SQLITE_API int SQLITE_STDCALL sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
+ VtabCtx *pCtx;
Parse *pParse;
-
int rc = SQLITE_OK;
Table *pTab;
char *zErr = 0;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) || zCreateTable==0 ){
+ return SQLITE_MISUSE_BKPT;
+ }
+#endif
sqlite3_mutex_enter(db->mutex);
- if( !db->pVtabCtx || !(pTab = db->pVtabCtx->pTab) ){
- sqlite3Error(db, SQLITE_MISUSE, 0);
+ pCtx = db->pVtabCtx;
+ if( !pCtx || pCtx->bDeclared ){
+ sqlite3Error(db, SQLITE_MISUSE);
sqlite3_mutex_leave(db->mutex);
return SQLITE_MISUSE_BKPT;
}
+ pTab = pCtx->pTab;
assert( (pTab->tabFlags & TF_Virtual)!=0 );
pParse = sqlite3StackAllocZero(db, sizeof(*pParse));
@@ -110122,9 +115384,9 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
pParse->pNewTable->nCol = 0;
pParse->pNewTable->aCol = 0;
}
- db->pVtabCtx->pTab = 0;
+ pCtx->bDeclared = 1;
}else{
- sqlite3Error(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr);
+ sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr);
sqlite3DbFree(db, zErr);
rc = SQLITE_ERROR;
}
@@ -110157,11 +115419,15 @@ SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab
pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName);
if( ALWAYS(pTab!=0 && pTab->pVTable!=0) ){
- VTable *p = vtabDisconnectAll(db, pTab);
-
- assert( rc==SQLITE_OK );
+ VTable *p;
+ for(p=pTab->pVTable; p; p=p->pNext){
+ assert( p->pVtab );
+ if( p->pVtab->nRef>0 ){
+ return SQLITE_LOCKED;
+ }
+ }
+ p = vtabDisconnectAll(db, pTab);
rc = p->pMod->pModule->xDestroy(p->pVtab);
-
/* Remove the sqlite3_vtab* from the aVTrans[] array, if applicable */
if( rc==SQLITE_OK ){
assert( pTab->pVTable==p && p->pNext==0 );
@@ -110312,7 +115578,7 @@ SQLITE_PRIVATE int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){
int rc = SQLITE_OK;
assert( op==SAVEPOINT_RELEASE||op==SAVEPOINT_ROLLBACK||op==SAVEPOINT_BEGIN );
- assert( iSavepoint>=0 );
+ assert( iSavepoint>=-1 );
if( db->aVTrans ){
int i;
for(i=0; rc==SQLITE_OK && i<db->nVTrans; i++){
@@ -110430,7 +115696,7 @@ SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){
if( pTab==pToplevel->apVtabLock[i] ) return;
}
n = (pToplevel->nVtabLock+1)*sizeof(pToplevel->apVtabLock[0]);
- apVtabLock = sqlite3_realloc(pToplevel->apVtabLock, n);
+ apVtabLock = sqlite3_realloc64(pToplevel->apVtabLock, n);
if( apVtabLock ){
pToplevel->apVtabLock = apVtabLock;
pToplevel->apVtabLock[pToplevel->nVtabLock++] = pTab;
@@ -110446,10 +115712,13 @@ SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){
** The results of this routine are undefined unless it is called from
** within an xUpdate method.
*/
-SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *db){
+SQLITE_API int SQLITE_STDCALL sqlite3_vtab_on_conflict(sqlite3 *db){
static const unsigned char aMap[] = {
SQLITE_ROLLBACK, SQLITE_ABORT, SQLITE_FAIL, SQLITE_IGNORE, SQLITE_REPLACE
};
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
assert( OE_Rollback==1 && OE_Abort==2 && OE_Fail==3 );
assert( OE_Ignore==4 && OE_Replace==5 );
assert( db->vtabOnConflict>=1 && db->vtabOnConflict<=5 );
@@ -110461,12 +115730,14 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *db){
** the SQLite core with additional information about the behavior
** of the virtual table being implemented.
*/
-SQLITE_API int sqlite3_vtab_config(sqlite3 *db, int op, ...){
+SQLITE_API int SQLITE_CDECL sqlite3_vtab_config(sqlite3 *db, int op, ...){
va_list ap;
int rc = SQLITE_OK;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
sqlite3_mutex_enter(db->mutex);
-
va_start(ap, op);
switch( op ){
case SQLITE_VTAB_CONSTRAINT_SUPPORT: {
@@ -110485,7 +115756,7 @@ SQLITE_API int sqlite3_vtab_config(sqlite3 *db, int op, ...){
}
va_end(ap);
- if( rc!=SQLITE_OK ) sqlite3Error(db, rc, 0);
+ if( rc!=SQLITE_OK ) sqlite3Error(db, rc);
sqlite3_mutex_leave(db->mutex);
return rc;
}
@@ -110585,6 +115856,8 @@ struct WhereLevel {
int addrCont; /* Jump here to continue with the next loop cycle */
int addrFirst; /* First instruction of interior of the loop */
int addrBody; /* Beginning of the body of this loop */
+ int iLikeRepCntr; /* LIKE range processing counter register */
+ int addrLikeRep; /* LIKE range processing address */
u8 iFrom; /* Which entry in the FROM clause */
u8 op, p3, p5; /* Opcode, P3 & P5 of the opcode that ends the loop */
int p1, p2; /* Operands of the opcode used to ends the loop */
@@ -110601,6 +115874,9 @@ struct WhereLevel {
} u;
struct WhereLoop *pWLoop; /* The selected WhereLoop object */
Bitmask notReady; /* FROM entries not usable at this level */
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ int addrVisit; /* Address at which row is visited */
+#endif
};
/*
@@ -110631,7 +115907,6 @@ struct WhereLoop {
union {
struct { /* Information for internal btree tables */
u16 nEq; /* Number of equality constraints */
- u16 nSkip; /* Number of initial index columns to skip */
Index *pIndex; /* Index used, or NULL */
} btree;
struct { /* Information for virtual tables */
@@ -110644,12 +115919,13 @@ struct WhereLoop {
} u;
u32 wsFlags; /* WHERE_* flags describing the plan */
u16 nLTerm; /* Number of entries in aLTerm[] */
+ u16 nSkip; /* Number of NULL aLTerm[] entries */
/**** whereLoopXfer() copies fields above ***********************/
# define WHERE_LOOP_XFER_SZ offsetof(WhereLoop,nLSlot)
u16 nLSlot; /* Number of slots allocated for aLTerm[] */
WhereTerm **aLTerm; /* WhereTerms used */
WhereLoop *pNextLoop; /* Next WhereLoop object in the WhereClause */
- WhereTerm *aLTermSpace[4]; /* Initial aLTerm[] space */
+ WhereTerm *aLTermSpace[3]; /* Initial aLTerm[] space */
};
/* This object holds the prerequisites and the cost of running a
@@ -110692,7 +115968,7 @@ static int whereLoopResize(sqlite3*, WhereLoop*, int);
** 1. Then using those as a basis to compute the N best WherePath objects
** of length 2. And so forth until the length of WherePaths equals the
** number of nodes in the FROM clause. The best (lowest cost) WherePath
-** at the end is the choosen query plan.
+** at the end is the chosen query plan.
*/
struct WherePath {
Bitmask maskLoop; /* Bitmask of all WhereLoop objects in this path */
@@ -110766,7 +116042,7 @@ struct WhereTerm {
} u;
LogEst truthProb; /* Probability of truth for this expression */
u16 eOperator; /* A WO_xx value describing <op> */
- u8 wtFlags; /* TERM_xxx bit flags. See below */
+ u16 wtFlags; /* TERM_xxx bit flags. See below */
u8 nChild; /* Number of children that must disable us */
WhereClause *pWC; /* The clause this term is part of */
Bitmask prereqRight; /* Bitmask of tables used by pExpr->pRight */
@@ -110788,6 +116064,9 @@ struct WhereTerm {
#else
# define TERM_VNULL 0x00 /* Disabled if not using stat3 */
#endif
+#define TERM_LIKEOPT 0x100 /* Virtual terms from the LIKE optimization */
+#define TERM_LIKECOND 0x200 /* Conditionally this LIKE operator term */
+#define TERM_LIKE 0x400 /* The original LIKE operator */
/*
** An instance of the WhereScan object is used as an iterator for locating
@@ -110975,6 +116254,7 @@ struct WhereInfo {
#define WHERE_AUTO_INDEX 0x00004000 /* Uses an ephemeral index */
#define WHERE_SKIPSCAN 0x00008000 /* Uses the skip-scan algorithm */
#define WHERE_UNQ_WANTED 0x00010000 /* WHERE_ONEROW would have been helpful*/
+#define WHERE_PARTIALIDX 0x00020000 /* The automatic index is partial */
/************** End of whereInt.h ********************************************/
/************** Continuing where we left off in where.c **********************/
@@ -111162,7 +116442,7 @@ static void whereClauseClear(WhereClause *pWC){
** calling this routine. Such pointers may be reinitialized by referencing
** the pWC->a[] array.
*/
-static int whereClauseInsert(WhereClause *pWC, Expr *p, u8 wtFlags){
+static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){
WhereTerm *pTerm;
int idx;
testcase( wtFlags & TERM_VIRTUAL );
@@ -111182,10 +116462,11 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u8 wtFlags){
sqlite3DbFree(db, pOld);
}
pWC->nSlot = sqlite3DbMallocSize(db, pWC->a)/sizeof(pWC->a[0]);
+ memset(&pWC->a[pWC->nTerm], 0, sizeof(pWC->a[0])*(pWC->nSlot-pWC->nTerm));
}
pTerm = &pWC->a[idx = pWC->nTerm++];
if( p && ExprHasProperty(p, EP_Unlikely) ){
- pTerm->truthProb = sqlite3LogEst(p->iTable) - 99;
+ pTerm->truthProb = sqlite3LogEst(p->iTable) - 270;
}else{
pTerm->truthProb = 1;
}
@@ -111214,13 +116495,14 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u8 wtFlags){
** all terms of the WHERE clause.
*/
static void whereSplit(WhereClause *pWC, Expr *pExpr, u8 op){
+ Expr *pE2 = sqlite3ExprSkipCollate(pExpr);
pWC->op = op;
- if( pExpr==0 ) return;
- if( pExpr->op!=op ){
+ if( pE2==0 ) return;
+ if( pE2->op!=op ){
whereClauseInsert(pWC, pExpr, 0);
}else{
- whereSplit(pWC, pExpr->pLeft, op);
- whereSplit(pWC, pExpr->pRight, op);
+ whereSplit(pWC, pE2->pLeft, op);
+ whereSplit(pWC, pE2->pRight, op);
}
}
@@ -111325,11 +116607,6 @@ static int allowedOp(int op){
}
/*
-** Swap two objects of type TYPE.
-*/
-#define SWAP(TYPE,A,B) {TYPE t=A; A=B; B=t;}
-
-/*
** Commute a comparison operator. Expressions of the form "X op Y"
** are converted into "Y op X".
**
@@ -111591,7 +116868,11 @@ static void exprAnalyzeAll(
** so and false if not.
**
** In order for the operator to be optimizible, the RHS must be a string
-** literal that does not begin with a wildcard.
+** literal that does not begin with a wildcard. The LHS must be a column
+** that may only be NULL, a string, or a BLOB, never a number. (This means
+** that virtual tables cannot participate in the LIKE optimization.) If the
+** collating sequence for the column on the LHS must be appropriate for
+** the operator.
*/
static int isLikeOrGlob(
Parse *pParse, /* Parsing and code generating context */
@@ -111620,7 +116901,7 @@ static int isLikeOrGlob(
pLeft = pList->a[1].pExpr;
if( pLeft->op!=TK_COLUMN
|| sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT
- || IsVirtual(pLeft->pTab)
+ || IsVirtual(pLeft->pTab) /* Value might be numeric */
){
/* IMP: R-02065-49465 The left-hand side of the LIKE or GLOB operator must
** be the name of an indexed column with TEXT affinity. */
@@ -111661,7 +116942,7 @@ static int isLikeOrGlob(
** value of the variable means there is no need to invoke the LIKE
** function, then no OP_Variable will be added to the program.
** This causes problems for the sqlite3_bind_parameter_name()
- ** API. To workaround them, add a dummy OP_Variable here.
+ ** API. To work around them, add a dummy OP_Variable here.
*/
int r1 = sqlite3GetTempReg(pParse);
sqlite3ExprCodeTarget(pParse, pRight, r1);
@@ -111721,6 +117002,88 @@ static void transferJoinMarkings(Expr *pDerived, Expr *pBase){
}
}
+/*
+** Mark term iChild as being a child of term iParent
+*/
+static void markTermAsChild(WhereClause *pWC, int iChild, int iParent){
+ pWC->a[iChild].iParent = iParent;
+ pWC->a[iChild].truthProb = pWC->a[iParent].truthProb;
+ pWC->a[iParent].nChild++;
+}
+
+/*
+** Return the N-th AND-connected subterm of pTerm. Or if pTerm is not
+** a conjunction, then return just pTerm when N==0. If N is exceeds
+** the number of available subterms, return NULL.
+*/
+static WhereTerm *whereNthSubterm(WhereTerm *pTerm, int N){
+ if( pTerm->eOperator!=WO_AND ){
+ return N==0 ? pTerm : 0;
+ }
+ if( N<pTerm->u.pAndInfo->wc.nTerm ){
+ return &pTerm->u.pAndInfo->wc.a[N];
+ }
+ return 0;
+}
+
+/*
+** Subterms pOne and pTwo are contained within WHERE clause pWC. The
+** two subterms are in disjunction - they are OR-ed together.
+**
+** If these two terms are both of the form: "A op B" with the same
+** A and B values but different operators and if the operators are
+** compatible (if one is = and the other is <, for example) then
+** add a new virtual AND term to pWC that is the combination of the
+** two.
+**
+** Some examples:
+**
+** x<y OR x=y --> x<=y
+** x=y OR x=y --> x=y
+** x<=y OR x<y --> x<=y
+**
+** The following is NOT generated:
+**
+** x<y OR x>y --> x!=y
+*/
+static void whereCombineDisjuncts(
+ SrcList *pSrc, /* the FROM clause */
+ WhereClause *pWC, /* The complete WHERE clause */
+ WhereTerm *pOne, /* First disjunct */
+ WhereTerm *pTwo /* Second disjunct */
+){
+ u16 eOp = pOne->eOperator | pTwo->eOperator;
+ sqlite3 *db; /* Database connection (for malloc) */
+ Expr *pNew; /* New virtual expression */
+ int op; /* Operator for the combined expression */
+ int idxNew; /* Index in pWC of the next virtual term */
+
+ if( (pOne->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE))==0 ) return;
+ if( (pTwo->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE))==0 ) return;
+ if( (eOp & (WO_EQ|WO_LT|WO_LE))!=eOp
+ && (eOp & (WO_EQ|WO_GT|WO_GE))!=eOp ) return;
+ assert( pOne->pExpr->pLeft!=0 && pOne->pExpr->pRight!=0 );
+ assert( pTwo->pExpr->pLeft!=0 && pTwo->pExpr->pRight!=0 );
+ if( sqlite3ExprCompare(pOne->pExpr->pLeft, pTwo->pExpr->pLeft, -1) ) return;
+ if( sqlite3ExprCompare(pOne->pExpr->pRight, pTwo->pExpr->pRight, -1) )return;
+ /* If we reach this point, it means the two subterms can be combined */
+ if( (eOp & (eOp-1))!=0 ){
+ if( eOp & (WO_LT|WO_LE) ){
+ eOp = WO_LE;
+ }else{
+ assert( eOp & (WO_GT|WO_GE) );
+ eOp = WO_GE;
+ }
+ }
+ db = pWC->pWInfo->pParse->db;
+ pNew = sqlite3ExprDup(db, pOne->pExpr, 0);
+ if( pNew==0 ) return;
+ for(op=TK_EQ; eOp!=(WO_EQ<<(op-TK_EQ)); op++){ assert( op<TK_GE ); }
+ pNew->op = op;
+ idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC);
+ exprAnalyze(pSrc, pWC, idxNew);
+}
+
#if !defined(SQLITE_OMIT_OR_OPTIMIZATION) && !defined(SQLITE_OMIT_SUBQUERY)
/*
** Analyze a term that consists of two or more OR-connected
@@ -111745,6 +117108,7 @@ static void transferJoinMarkings(Expr *pDerived, Expr *pBase){
** (C) t1.x=t2.y OR (t1.x=t2.z AND t1.y=15)
** (D) x=expr1 OR (y>11 AND y<22 AND z LIKE '*hello*')
** (E) (p.a=1 AND q.b=2 AND r.c=3) OR (p.x=4 AND q.y=5 AND r.z=6)
+** (F) x>A OR (x=A AND y>=B)
**
** CASE 1:
**
@@ -111761,6 +117125,16 @@ static void transferJoinMarkings(Expr *pDerived, Expr *pBase){
**
** CASE 2:
**
+** If there are exactly two disjuncts one side has x>A and the other side
+** has x=A (for the same x and A) then add a new virtual conjunct term to the
+** WHERE clause of the form "x>=A". Example:
+**
+** x>A OR (x=A AND y>B) adds: x>=A
+**
+** The added conjunct can sometimes be helpful in query planning.
+**
+** CASE 3:
+**
** If all subterms are indexable by a single table T, then set
**
** WhereTerm.eOperator = WO_OR
@@ -111781,7 +117155,7 @@ static void transferJoinMarkings(Expr *pDerived, Expr *pBase){
** appropriate for indexing exist.
**
** All examples A through E above satisfy case 2. But if a term
-** also statisfies case 1 (such as B) we know that the optimizer will
+** also satisfies case 1 (such as B) we know that the optimizer will
** always prefer case 1, so in that case we pretend that case 2 is not
** satisfied.
**
@@ -111887,12 +117261,26 @@ static void exprAnalyzeOrTerm(
}
/*
- ** Record the set of tables that satisfy case 2. The set might be
+ ** Record the set of tables that satisfy case 3. The set might be
** empty.
*/
pOrInfo->indexable = indexable;
pTerm->eOperator = indexable==0 ? 0 : WO_OR;
+ /* For a two-way OR, attempt to implementation case 2.
+ */
+ if( indexable && pOrWc->nTerm==2 ){
+ int iOne = 0;
+ WhereTerm *pOne;
+ while( (pOne = whereNthSubterm(&pOrWc->a[0],iOne++))!=0 ){
+ int iTwo = 0;
+ WhereTerm *pTwo;
+ while( (pTwo = whereNthSubterm(&pOrWc->a[1],iTwo++))!=0 ){
+ whereCombineDisjuncts(pSrc, pWC, pOne, pTwo);
+ }
+ }
+ }
+
/*
** chngToIN holds a set of tables that *might* satisfy case 1. But
** we have to do some additional checking to see if case 1 really
@@ -111939,7 +117327,7 @@ static void exprAnalyzeOrTerm(
}
if( (chngToIN & getMask(&pWInfo->sMaskSet, pOrTerm->leftCursor))==0 ){
/* This term must be of the form t1.a==t2.b where t2 is in the
- ** chngToIN set but t1 is not. This term will be either preceeded
+ ** chngToIN set but t1 is not. This term will be either preceded
** or follwed by an inverted copy (t2.b==t1.a). Skip this term
** and use its inversion. */
testcase( pOrTerm->wtFlags & TERM_COPIED );
@@ -112018,12 +117406,11 @@ static void exprAnalyzeOrTerm(
testcase( idxNew==0 );
exprAnalyze(pSrc, pWC, idxNew);
pTerm = &pWC->a[idxTerm];
- pWC->a[idxNew].iParent = idxTerm;
- pTerm->nChild = 1;
+ markTermAsChild(pWC, idxNew, idxTerm);
}else{
sqlite3ExprListDelete(db, pList);
}
- pTerm->eOperator = WO_NOOP; /* case 1 trumps case 2 */
+ pTerm->eOperator = WO_NOOP; /* case 1 trumps case 3 */
}
}
}
@@ -112061,7 +117448,7 @@ static void exprAnalyze(
Bitmask extraRight = 0; /* Extra dependencies on LEFT JOIN */
Expr *pStr1 = 0; /* RHS of LIKE/GLOB operator */
int isComplete = 0; /* RHS of LIKE/GLOB ends with wildcard */
- int noCase = 0; /* LIKE/GLOB distinguishes case */
+ int noCase = 0; /* uppercase equivalent to lowercase */
int op; /* Top-level operator. pExpr->op */
Parse *pParse = pWInfo->pParse; /* Parsing context */
sqlite3 *db = pParse->db; /* Database connection */
@@ -112121,9 +117508,8 @@ static void exprAnalyze(
idxNew = whereClauseInsert(pWC, pDup, TERM_VIRTUAL|TERM_DYNAMIC);
if( idxNew==0 ) return;
pNew = &pWC->a[idxNew];
- pNew->iParent = idxTerm;
+ markTermAsChild(pWC, idxNew, idxTerm);
pTerm = &pWC->a[idxTerm];
- pTerm->nChild = 1;
pTerm->wtFlags |= TERM_COPIED;
if( pExpr->op==TK_EQ
&& !ExprHasProperty(pExpr, EP_FromJoin)
@@ -112180,9 +117566,8 @@ static void exprAnalyze(
testcase( idxNew==0 );
exprAnalyze(pSrc, pWC, idxNew);
pTerm = &pWC->a[idxTerm];
- pWC->a[idxNew].iParent = idxTerm;
+ markTermAsChild(pWC, idxNew, idxTerm);
}
- pTerm->nChild = 2;
}
#endif /* SQLITE_OMIT_BETWEEN_OPTIMIZATION */
@@ -112201,12 +117586,15 @@ static void exprAnalyze(
/* Add constraints to reduce the search space on a LIKE or GLOB
** operator.
**
- ** A like pattern of the form "x LIKE 'abc%'" is changed into constraints
+ ** A like pattern of the form "x LIKE 'aBc%'" is changed into constraints
**
- ** x>='abc' AND x<'abd' AND x LIKE 'abc%'
+ ** x>='ABC' AND x<'abd' AND x LIKE 'aBc%'
**
** The last character of the prefix "abc" is incremented to form the
- ** termination condition "abd".
+ ** termination condition "abd". If case is not significant (the default
+ ** for LIKE) then the lower-bound is made all uppercase and the upper-
+ ** bound is made all lowercase so that the bounds also work when comparing
+ ** BLOBs.
*/
if( pWC->op==TK_AND
&& isLikeOrGlob(pParse, pExpr, &pStr1, &isComplete, &noCase)
@@ -112217,10 +117605,26 @@ static void exprAnalyze(
Expr *pNewExpr2;
int idxNew1;
int idxNew2;
- Token sCollSeqName; /* Name of collating sequence */
+ const char *zCollSeqName; /* Name of collating sequence */
+ const u16 wtFlags = TERM_LIKEOPT | TERM_VIRTUAL | TERM_DYNAMIC;
pLeft = pExpr->x.pList->a[1].pExpr;
pStr2 = sqlite3ExprDup(db, pStr1, 0);
+
+ /* Convert the lower bound to upper-case and the upper bound to
+ ** lower-case (upper-case is less than lower-case in ASCII) so that
+ ** the range constraints also work for BLOBs
+ */
+ if( noCase && !pParse->db->mallocFailed ){
+ int i;
+ char c;
+ pTerm->wtFlags |= TERM_LIKE;
+ for(i=0; (c = pStr1->u.zToken[i])!=0; i++){
+ pStr1->u.zToken[i] = sqlite3Toupper(c);
+ pStr2->u.zToken[i] = sqlite3Tolower(c);
+ }
+ }
+
if( !db->mallocFailed ){
u8 c, *pC; /* Last character before the first wildcard */
pC = (u8*)&pStr2->u.zToken[sqlite3Strlen30(pStr2->u.zToken)-1];
@@ -112237,29 +117641,27 @@ static void exprAnalyze(
}
*pC = c + 1;
}
- sCollSeqName.z = noCase ? "NOCASE" : "BINARY";
- sCollSeqName.n = 6;
+ zCollSeqName = noCase ? "NOCASE" : "BINARY";
pNewExpr1 = sqlite3ExprDup(db, pLeft, 0);
- pNewExpr1 = sqlite3PExpr(pParse, TK_GE,
- sqlite3ExprAddCollateToken(pParse,pNewExpr1,&sCollSeqName),
+ pNewExpr1 = sqlite3PExpr(pParse, TK_GE,
+ sqlite3ExprAddCollateString(pParse,pNewExpr1,zCollSeqName),
pStr1, 0);
transferJoinMarkings(pNewExpr1, pExpr);
- idxNew1 = whereClauseInsert(pWC, pNewExpr1, TERM_VIRTUAL|TERM_DYNAMIC);
+ idxNew1 = whereClauseInsert(pWC, pNewExpr1, wtFlags);
testcase( idxNew1==0 );
exprAnalyze(pSrc, pWC, idxNew1);
pNewExpr2 = sqlite3ExprDup(db, pLeft, 0);
pNewExpr2 = sqlite3PExpr(pParse, TK_LT,
- sqlite3ExprAddCollateToken(pParse,pNewExpr2,&sCollSeqName),
+ sqlite3ExprAddCollateString(pParse,pNewExpr2,zCollSeqName),
pStr2, 0);
transferJoinMarkings(pNewExpr2, pExpr);
- idxNew2 = whereClauseInsert(pWC, pNewExpr2, TERM_VIRTUAL|TERM_DYNAMIC);
+ idxNew2 = whereClauseInsert(pWC, pNewExpr2, wtFlags);
testcase( idxNew2==0 );
exprAnalyze(pSrc, pWC, idxNew2);
pTerm = &pWC->a[idxTerm];
if( isComplete ){
- pWC->a[idxNew1].iParent = idxTerm;
- pWC->a[idxNew2].iParent = idxTerm;
- pTerm->nChild = 2;
+ markTermAsChild(pWC, idxNew1, idxTerm);
+ markTermAsChild(pWC, idxNew2, idxTerm);
}
}
#endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */
@@ -112292,9 +117694,8 @@ static void exprAnalyze(
pNewTerm->leftCursor = pLeft->iTable;
pNewTerm->u.leftColumn = pLeft->iColumn;
pNewTerm->eOperator = WO_MATCH;
- pNewTerm->iParent = idxTerm;
+ markTermAsChild(pWC, idxNew, idxTerm);
pTerm = &pWC->a[idxTerm];
- pTerm->nChild = 1;
pTerm->wtFlags |= TERM_COPIED;
pNewTerm->prereqAll = pTerm->prereqAll;
}
@@ -112315,7 +117716,7 @@ static void exprAnalyze(
if( pExpr->op==TK_NOTNULL
&& pExpr->pLeft->op==TK_COLUMN
&& pExpr->pLeft->iColumn>=0
- && OptimizationEnabled(db, SQLITE_Stat3)
+ && OptimizationEnabled(db, SQLITE_Stat34)
){
Expr *pNewExpr;
Expr *pLeft = pExpr->pLeft;
@@ -112334,9 +117735,8 @@ static void exprAnalyze(
pNewTerm->leftCursor = pLeft->iTable;
pNewTerm->u.leftColumn = pLeft->iColumn;
pNewTerm->eOperator = WO_GT;
- pNewTerm->iParent = idxTerm;
+ markTermAsChild(pWC, idxNew, idxTerm);
pTerm = &pWC->a[idxTerm];
- pTerm->nChild = 1;
pTerm->wtFlags |= TERM_COPIED;
pNewTerm->prereqAll = pTerm->prereqAll;
}
@@ -112350,7 +117750,7 @@ static void exprAnalyze(
}
/*
-** This function searches pList for a entry that matches the iCol-th column
+** This function searches pList for an entry that matches the iCol-th column
** of index pIdx.
**
** If such an expression is found, its index in pList->a[] is returned. If
@@ -112373,7 +117773,7 @@ static int findIndexCol(
&& p->iTable==iBase
){
CollSeq *pColl = sqlite3ExprCollSeq(pParse, pList->a[i].pExpr);
- if( ALWAYS(pColl) && 0==sqlite3StrICmp(pColl->zName, zColl) ){
+ if( pColl && 0==sqlite3StrICmp(pColl->zName, zColl) ){
return i;
}
}
@@ -112556,6 +117956,8 @@ static void constructAutomaticIndex(
Bitmask idxCols; /* Bitmap of columns used for indexing */
Bitmask extraCols; /* Bitmap of additional columns */
u8 sentWarning = 0; /* True if a warnning has been issued */
+ Expr *pPartial = 0; /* Partial Index Expression */
+ int iContinue = 0; /* Jump here to skip excluded rows */
/* Generate code to skip over the creation and initialization of the
** transient index on 2nd and subsequent iterations of the loop. */
@@ -112571,6 +117973,17 @@ static void constructAutomaticIndex(
pLoop = pLevel->pWLoop;
idxCols = 0;
for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
+ Expr *pExpr = pTerm->pExpr;
+ assert( !ExprHasProperty(pExpr, EP_FromJoin) /* prereq always non-zero */
+ || pExpr->iRightJoinTable!=pSrc->iCursor /* for the right-hand */
+ || pLoop->prereq!=0 ); /* table of a LEFT JOIN */
+ if( pLoop->prereq==0
+ && (pTerm->wtFlags & TERM_VIRTUAL)==0
+ && !ExprHasProperty(pExpr, EP_FromJoin)
+ && sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor) ){
+ pPartial = sqlite3ExprAnd(pParse->db, pPartial,
+ sqlite3ExprDup(pParse->db, pExpr, 0));
+ }
if( termCanDriveIndex(pTerm, pSrc, notReady) ){
int iCol = pTerm->u.leftColumn;
Bitmask cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol);
@@ -112583,7 +117996,9 @@ static void constructAutomaticIndex(
sentWarning = 1;
}
if( (idxCols & cMask)==0 ){
- if( whereLoopResize(pParse->db, pLoop, nKeyCol+1) ) return;
+ if( whereLoopResize(pParse->db, pLoop, nKeyCol+1) ){
+ goto end_auto_index_create;
+ }
pLoop->aLTerm[nKeyCol++] = pTerm;
idxCols |= cMask;
}
@@ -112603,7 +118018,7 @@ static void constructAutomaticIndex(
** if they go out of sync.
*/
extraCols = pSrc->colUsed & (~idxCols | MASKBIT(BMS-1));
- mxBitCol = (pTable->nCol >= BMS-1) ? BMS-1 : pTable->nCol;
+ mxBitCol = MIN(BMS-1,pTable->nCol);
testcase( pTable->nCol==BMS-1 );
testcase( pTable->nCol==BMS-2 );
for(i=0; i<mxBitCol; i++){
@@ -112612,11 +118027,10 @@ static void constructAutomaticIndex(
if( pSrc->colUsed & MASKBIT(BMS-1) ){
nKeyCol += pTable->nCol - BMS + 1;
}
- pLoop->wsFlags |= WHERE_COLUMN_EQ | WHERE_IDX_ONLY;
/* Construct the Index object to describe this index */
pIdx = sqlite3AllocateIndexObject(pParse->db, nKeyCol+1, 0, &zNotUsed);
- if( pIdx==0 ) return;
+ if( pIdx==0 ) goto end_auto_index_create;
pLoop->u.btree.pIndex = pIdx;
pIdx->zName = "auto-index";
pIdx->pTable = pTable;
@@ -112633,7 +118047,7 @@ static void constructAutomaticIndex(
idxCols |= cMask;
pIdx->aiColumn[n] = pTerm->u.leftColumn;
pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight);
- pIdx->azColl[n] = ALWAYS(pColl) ? pColl->zName : "BINARY";
+ pIdx->azColl[n] = pColl ? pColl->zName : "BINARY";
n++;
}
}
@@ -112668,18 +118082,29 @@ static void constructAutomaticIndex(
VdbeComment((v, "for %s", pTable->zName));
/* Fill the automatic index with content */
+ sqlite3ExprCachePush(pParse);
addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v);
+ if( pPartial ){
+ iContinue = sqlite3VdbeMakeLabel(v);
+ sqlite3ExprIfFalse(pParse, pPartial, iContinue, SQLITE_JUMPIFNULL);
+ pLoop->wsFlags |= WHERE_PARTIALIDX;
+ }
regRecord = sqlite3GetTempReg(pParse);
sqlite3GenerateIndexKey(pParse, pIdx, pLevel->iTabCur, regRecord, 0, 0, 0, 0);
sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord);
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
+ if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue);
sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v);
sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX);
sqlite3VdbeJumpHere(v, addrTop);
sqlite3ReleaseTempReg(pParse, regRecord);
+ sqlite3ExprCachePop(pParse);
/* Jump here when skipping the initialization */
sqlite3VdbeJumpHere(v, addrInit);
+
+end_auto_index_create:
+ sqlite3ExprDelete(pParse->db, pPartial);
}
#endif /* SQLITE_OMIT_AUTOMATIC_INDEX */
@@ -112839,18 +118264,21 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
}
#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */
-
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
/*
** Estimate the location of a particular key among all keys in an
** index. Store the results in aStat as follows:
**
-** aStat[0] Est. number of rows less than pVal
-** aStat[1] Est. number of rows equal to pVal
+** aStat[0] Est. number of rows less than pRec
+** aStat[1] Est. number of rows equal to pRec
**
-** Return SQLITE_OK on success.
+** Return the index of the sample that is the smallest sample that
+** is greater than or equal to pRec. Note that this index is not an index
+** into the aSample[] array - it is an index into a virtual set of samples
+** based on the contents of aSample[] and the number of fields in record
+** pRec.
*/
-static void whereKeyStats(
+static int whereKeyStats(
Parse *pParse, /* Database connection */
Index *pIdx, /* Index to consider domain of */
UnpackedRecord *pRec, /* Vector of values to consider */
@@ -112859,67 +118287,158 @@ static void whereKeyStats(
){
IndexSample *aSample = pIdx->aSample;
int iCol; /* Index of required stats in anEq[] etc. */
+ int i; /* Index of first sample >= pRec */
+ int iSample; /* Smallest sample larger than or equal to pRec */
int iMin = 0; /* Smallest sample not yet tested */
- int i = pIdx->nSample; /* Smallest sample larger than or equal to pRec */
int iTest; /* Next sample to test */
int res; /* Result of comparison operation */
+ int nField; /* Number of fields in pRec */
+ tRowcnt iLower = 0; /* anLt[] + anEq[] of largest sample pRec is > */
#ifndef SQLITE_DEBUG
UNUSED_PARAMETER( pParse );
#endif
assert( pRec!=0 );
- iCol = pRec->nField - 1;
assert( pIdx->nSample>0 );
- assert( pRec->nField>0 && iCol<pIdx->nSampleCol );
+ assert( pRec->nField>0 && pRec->nField<=pIdx->nSampleCol );
+
+ /* Do a binary search to find the first sample greater than or equal
+ ** to pRec. If pRec contains a single field, the set of samples to search
+ ** is simply the aSample[] array. If the samples in aSample[] contain more
+ ** than one fields, all fields following the first are ignored.
+ **
+ ** If pRec contains N fields, where N is more than one, then as well as the
+ ** samples in aSample[] (truncated to N fields), the search also has to
+ ** consider prefixes of those samples. For example, if the set of samples
+ ** in aSample is:
+ **
+ ** aSample[0] = (a, 5)
+ ** aSample[1] = (a, 10)
+ ** aSample[2] = (b, 5)
+ ** aSample[3] = (c, 100)
+ ** aSample[4] = (c, 105)
+ **
+ ** Then the search space should ideally be the samples above and the
+ ** unique prefixes [a], [b] and [c]. But since that is hard to organize,
+ ** the code actually searches this set:
+ **
+ ** 0: (a)
+ ** 1: (a, 5)
+ ** 2: (a, 10)
+ ** 3: (a, 10)
+ ** 4: (b)
+ ** 5: (b, 5)
+ ** 6: (c)
+ ** 7: (c, 100)
+ ** 8: (c, 105)
+ ** 9: (c, 105)
+ **
+ ** For each sample in the aSample[] array, N samples are present in the
+ ** effective sample array. In the above, samples 0 and 1 are based on
+ ** sample aSample[0]. Samples 2 and 3 on aSample[1] etc.
+ **
+ ** Often, sample i of each block of N effective samples has (i+1) fields.
+ ** Except, each sample may be extended to ensure that it is greater than or
+ ** equal to the previous sample in the array. For example, in the above,
+ ** sample 2 is the first sample of a block of N samples, so at first it
+ ** appears that it should be 1 field in size. However, that would make it
+ ** smaller than sample 1, so the binary search would not work. As a result,
+ ** it is extended to two fields. The duplicates that this creates do not
+ ** cause any problems.
+ */
+ nField = pRec->nField;
+ iCol = 0;
+ iSample = pIdx->nSample * nField;
do{
- iTest = (iMin+i)/2;
- res = sqlite3VdbeRecordCompare(aSample[iTest].n, aSample[iTest].p, pRec, 0);
+ int iSamp; /* Index in aSample[] of test sample */
+ int n; /* Number of fields in test sample */
+
+ iTest = (iMin+iSample)/2;
+ iSamp = iTest / nField;
+ if( iSamp>0 ){
+ /* The proposed effective sample is a prefix of sample aSample[iSamp].
+ ** Specifically, the shortest prefix of at least (1 + iTest%nField)
+ ** fields that is greater than the previous effective sample. */
+ for(n=(iTest % nField) + 1; n<nField; n++){
+ if( aSample[iSamp-1].anLt[n-1]!=aSample[iSamp].anLt[n-1] ) break;
+ }
+ }else{
+ n = iTest + 1;
+ }
+
+ pRec->nField = n;
+ res = sqlite3VdbeRecordCompare(aSample[iSamp].n, aSample[iSamp].p, pRec);
if( res<0 ){
+ iLower = aSample[iSamp].anLt[n-1] + aSample[iSamp].anEq[n-1];
+ iMin = iTest+1;
+ }else if( res==0 && n<nField ){
+ iLower = aSample[iSamp].anLt[n-1];
iMin = iTest+1;
+ res = -1;
}else{
- i = iTest;
+ iSample = iTest;
+ iCol = n-1;
}
- }while( res && iMin<i );
+ }while( res && iMin<iSample );
+ i = iSample / nField;
#ifdef SQLITE_DEBUG
/* The following assert statements check that the binary search code
** above found the right answer. This block serves no purpose other
** than to invoke the asserts. */
- if( res==0 ){
- /* If (res==0) is true, then sample $i must be equal to pRec */
- assert( i<pIdx->nSample );
- assert( 0==sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec, 0)
- || pParse->db->mallocFailed );
- }else{
- /* Otherwise, pRec must be smaller than sample $i and larger than
- ** sample ($i-1). */
- assert( i==pIdx->nSample
- || sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec, 0)>0
- || pParse->db->mallocFailed );
- assert( i==0
- || sqlite3VdbeRecordCompare(aSample[i-1].n, aSample[i-1].p, pRec, 0)<0
- || pParse->db->mallocFailed );
+ if( pParse->db->mallocFailed==0 ){
+ if( res==0 ){
+ /* If (res==0) is true, then pRec must be equal to sample i. */
+ assert( i<pIdx->nSample );
+ assert( iCol==nField-1 );
+ pRec->nField = nField;
+ assert( 0==sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)
+ || pParse->db->mallocFailed
+ );
+ }else{
+ /* Unless i==pIdx->nSample, indicating that pRec is larger than
+ ** all samples in the aSample[] array, pRec must be smaller than the
+ ** (iCol+1) field prefix of sample i. */
+ assert( i<=pIdx->nSample && i>=0 );
+ pRec->nField = iCol+1;
+ assert( i==pIdx->nSample
+ || sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)>0
+ || pParse->db->mallocFailed );
+
+ /* if i==0 and iCol==0, then record pRec is smaller than all samples
+ ** in the aSample[] array. Otherwise, if (iCol>0) then pRec must
+ ** be greater than or equal to the (iCol) field prefix of sample i.
+ ** If (i>0), then pRec must also be greater than sample (i-1). */
+ if( iCol>0 ){
+ pRec->nField = iCol;
+ assert( sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)<=0
+ || pParse->db->mallocFailed );
+ }
+ if( i>0 ){
+ pRec->nField = nField;
+ assert( sqlite3VdbeRecordCompare(aSample[i-1].n, aSample[i-1].p, pRec)<0
+ || pParse->db->mallocFailed );
+ }
+ }
}
#endif /* ifdef SQLITE_DEBUG */
- /* At this point, aSample[i] is the first sample that is greater than
- ** or equal to pVal. Or if i==pIdx->nSample, then all samples are less
- ** than pVal. If aSample[i]==pVal, then res==0.
- */
if( res==0 ){
+ /* Record pRec is equal to sample i */
+ assert( iCol==nField-1 );
aStat[0] = aSample[i].anLt[iCol];
aStat[1] = aSample[i].anEq[iCol];
}else{
- tRowcnt iLower, iUpper, iGap;
- if( i==0 ){
- iLower = 0;
- iUpper = aSample[0].anLt[iCol];
+ /* At this point, the (iCol+1) field prefix of aSample[i] is the first
+ ** sample that is greater than pRec. Or, if i==pIdx->nSample then pRec
+ ** is larger than all samples in the array. */
+ tRowcnt iUpper, iGap;
+ if( i>=pIdx->nSample ){
+ iUpper = sqlite3LogEstToInt(pIdx->aiRowLogEst[0]);
}else{
- i64 nRow0 = sqlite3LogEstToInt(pIdx->aiRowLogEst[0]);
- iUpper = i>=pIdx->nSample ? nRow0 : aSample[i].anLt[iCol];
- iLower = aSample[i-1].anEq[iCol] + aSample[i-1].anLt[iCol];
+ iUpper = aSample[i].anLt[iCol];
}
- aStat[1] = pIdx->aAvgEq[iCol];
+
if( iLower>=iUpper ){
iGap = 0;
}else{
@@ -112931,7 +118450,12 @@ static void whereKeyStats(
iGap = iGap/3;
}
aStat[0] = iLower + iGap;
+ aStat[1] = pIdx->aAvgEq[iCol];
}
+
+ /* Restore the pRec->nField value before returning. */
+ pRec->nField = nField;
+ return i;
}
#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
@@ -113082,7 +118606,7 @@ static int whereRangeSkipScanEst(
** If either of the upper or lower bound is not present, then NULL is passed in
** place of the corresponding WhereTerm.
**
-** The value in (pBuilder->pNew->u.btree.nEq) is the index of the index
+** The value in (pBuilder->pNew->u.btree.nEq) is the number of the index
** column subject to the range constraint. Or, equivalently, the number of
** equality constraints optimized by the proposed index scan. For example,
** assuming index p is on t1(a, b), and the SQL query is:
@@ -113098,9 +118622,9 @@ static int whereRangeSkipScanEst(
**
** When this function is called, *pnOut is set to the sqlite3LogEst() of the
** number of rows that the index scan is expected to visit without
-** considering the range constraints. If nEq is 0, this is the number of
+** considering the range constraints. If nEq is 0, then *pnOut is the number of
** rows in the index. Assuming no error occurs, *pnOut is adjusted (reduced)
-** to account for the range contraints pLower and pUpper.
+** to account for the range constraints pLower and pUpper.
**
** In the absence of sqlite_stat4 ANALYZE data, or if such data cannot be
** used, a single range inequality reduces the search space by a factor of 4.
@@ -113122,10 +118646,7 @@ static int whereRangeScanEst(
Index *p = pLoop->u.btree.pIndex;
int nEq = pLoop->u.btree.nEq;
- if( p->nSample>0
- && nEq<p->nSampleCol
- && OptimizationEnabled(pParse->db, SQLITE_Stat3)
- ){
+ if( p->nSample>0 && nEq<p->nSampleCol ){
if( nEq==pBuilder->nRecValid ){
UnpackedRecord *pRec = pBuilder->pRec;
tRowcnt a[2];
@@ -113141,16 +118662,24 @@ static int whereRangeScanEst(
** is not a simple variable or literal value), the lower bound of the
** range is $P. Due to a quirk in the way whereKeyStats() works, even
** if $L is available, whereKeyStats() is called for both ($P) and
- ** ($P:$L) and the larger of the two returned values used.
+ ** ($P:$L) and the larger of the two returned values is used.
**
** Similarly, iUpper is to be set to the estimate of the number of rows
** less than the upper bound of the range query. Where the upper bound
** is either ($P) or ($P:$U). Again, even if $U is available, both values
** of iUpper are requested of whereKeyStats() and the smaller used.
+ **
+ ** The number of rows between the two bounds is then just iUpper-iLower.
*/
- tRowcnt iLower;
- tRowcnt iUpper;
+ tRowcnt iLower; /* Rows less than the lower bound */
+ tRowcnt iUpper; /* Rows less than the upper bound */
+ int iLwrIdx = -2; /* aSample[] for the lower bound */
+ int iUprIdx = -1; /* aSample[] for the upper bound */
+ if( pRec ){
+ testcase( pRec->nField!=pBuilder->nRecValid );
+ pRec->nField = pBuilder->nRecValid;
+ }
if( nEq==p->nKeyCol ){
aff = SQLITE_AFF_INTEGER;
}else{
@@ -113159,7 +118688,7 @@ static int whereRangeScanEst(
/* Determine iLower and iUpper using ($P) only. */
if( nEq==0 ){
iLower = 0;
- iUpper = sqlite3LogEstToInt(p->aiRowLogEst[0]);
+ iUpper = p->nRowEst0;
}else{
/* Note: this call could be optimized away - since the same values must
** have been requested when testing key $P in whereEqualScanEst(). */
@@ -113168,18 +118697,26 @@ static int whereRangeScanEst(
iUpper = a[0] + a[1];
}
+ assert( pLower==0 || (pLower->eOperator & (WO_GT|WO_GE))!=0 );
+ assert( pUpper==0 || (pUpper->eOperator & (WO_LT|WO_LE))!=0 );
+ assert( p->aSortOrder!=0 );
+ if( p->aSortOrder[nEq] ){
+ /* The roles of pLower and pUpper are swapped for a DESC index */
+ SWAP(WhereTerm*, pLower, pUpper);
+ }
+
/* If possible, improve on the iLower estimate using ($P:$L). */
if( pLower ){
int bOk; /* True if value is extracted from pExpr */
Expr *pExpr = pLower->pExpr->pRight;
- assert( (pLower->eOperator & (WO_GT|WO_GE))!=0 );
rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk);
if( rc==SQLITE_OK && bOk ){
tRowcnt iNew;
- whereKeyStats(pParse, p, pRec, 0, a);
- iNew = a[0] + ((pLower->eOperator & WO_GT) ? a[1] : 0);
+ iLwrIdx = whereKeyStats(pParse, p, pRec, 0, a);
+ iNew = a[0] + ((pLower->eOperator & (WO_GT|WO_LE)) ? a[1] : 0);
if( iNew>iLower ) iLower = iNew;
nOut--;
+ pLower = 0;
}
}
@@ -113187,14 +118724,14 @@ static int whereRangeScanEst(
if( pUpper ){
int bOk; /* True if value is extracted from pExpr */
Expr *pExpr = pUpper->pExpr->pRight;
- assert( (pUpper->eOperator & (WO_LT|WO_LE))!=0 );
rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk);
if( rc==SQLITE_OK && bOk ){
tRowcnt iNew;
- whereKeyStats(pParse, p, pRec, 1, a);
- iNew = a[0] + ((pUpper->eOperator & WO_LE) ? a[1] : 0);
+ iUprIdx = whereKeyStats(pParse, p, pRec, 1, a);
+ iNew = a[0] + ((pUpper->eOperator & (WO_GT|WO_LE)) ? a[1] : 0);
if( iNew<iUpper ) iUpper = iNew;
nOut--;
+ pUpper = 0;
}
}
@@ -113202,16 +118739,19 @@ static int whereRangeScanEst(
if( rc==SQLITE_OK ){
if( iUpper>iLower ){
nNew = sqlite3LogEst(iUpper - iLower);
+ /* TUNING: If both iUpper and iLower are derived from the same
+ ** sample, then assume they are 4x more selective. This brings
+ ** the estimated selectivity more in line with what it would be
+ ** if estimated without the use of STAT3/4 tables. */
+ if( iLwrIdx==iUprIdx ) nNew -= 20; assert( 20==sqlite3LogEst(4) );
}else{
nNew = 10; assert( 10==sqlite3LogEst(2) );
}
if( nNew<nOut ){
nOut = nNew;
}
- pLoop->nOut = (LogEst)nOut;
- WHERETRACE(0x10, ("range scan regions: %u..%u est=%d\n",
+ WHERETRACE(0x10, ("STAT4 range scan: %u..%u est=%d\n",
(u32)iLower, (u32)iUpper, nOut));
- return SQLITE_OK;
}
}else{
int bDone = 0;
@@ -113222,22 +118762,31 @@ static int whereRangeScanEst(
#else
UNUSED_PARAMETER(pParse);
UNUSED_PARAMETER(pBuilder);
-#endif
assert( pLower || pUpper );
+#endif
assert( pUpper==0 || (pUpper->wtFlags & TERM_VNULL)==0 );
nNew = whereRangeAdjust(pLower, nOut);
nNew = whereRangeAdjust(pUpper, nNew);
- /* TUNING: If there is both an upper and lower limit, assume the range is
+ /* TUNING: If there is both an upper and lower limit and neither limit
+ ** has an application-defined likelihood(), assume the range is
** reduced by an additional 75%. This means that, by default, an open-ended
** range query (e.g. col > ?) is assumed to match 1/4 of the rows in the
** index. While a closed range (e.g. col BETWEEN ? AND ?) is estimated to
** match 1/64 of the index. */
- if( pLower && pUpper ) nNew -= 20;
+ if( pLower && pLower->truthProb>0 && pUpper && pUpper->truthProb>0 ){
+ nNew -= 20;
+ }
nOut -= (pLower!=0) + (pUpper!=0);
if( nNew<10 ) nNew = 10;
if( nNew<nOut ) nOut = nNew;
+#if defined(WHERETRACE_ENABLED)
+ if( pLoop->nOut>nOut ){
+ WHERETRACE(0x10,("Range scan lowers nOut from %d to %d\n",
+ pLoop->nOut, nOut));
+ }
+#endif
pLoop->nOut = (LogEst)nOut;
return rc;
}
@@ -113350,7 +118899,7 @@ static int whereInScanEst(
if( rc==SQLITE_OK ){
if( nRowEst > nRow0 ) nRowEst = nRow0;
*pnRow = nRowEst;
- WHERETRACE(0x10,("IN row estimate: est=%g\n", nRowEst));
+ WHERETRACE(0x10,("IN row estimate: est=%d\n", nRowEst));
}
assert( pBuilder->nRecValid==nRecValid );
return rc;
@@ -113379,20 +118928,43 @@ static int whereInScanEst(
** but joins might run a little slower. The trick is to disable as much
** as we can without disabling too much. If we disabled in (1), we'd get
** the wrong answer. See ticket #813.
+**
+** If all the children of a term are disabled, then that term is also
+** automatically disabled. In this way, terms get disabled if derived
+** virtual terms are tested first. For example:
+**
+** x GLOB 'abc*' AND x>='abc' AND x<'acd'
+** \___________/ \______/ \_____/
+** parent child1 child2
+**
+** Only the parent term was in the original WHERE clause. The child1
+** and child2 terms were added by the LIKE optimization. If both of
+** the virtual child terms are valid, then testing of the parent can be
+** skipped.
+**
+** Usually the parent term is marked as TERM_CODED. But if the parent
+** term was originally TERM_LIKE, then the parent gets TERM_LIKECOND instead.
+** The TERM_LIKECOND marking indicates that the term should be coded inside
+** a conditional such that is only evaluated on the second pass of a
+** LIKE-optimization loop, when scanning BLOBs instead of strings.
*/
static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
- if( pTerm
+ int nLoop = 0;
+ while( pTerm
&& (pTerm->wtFlags & TERM_CODED)==0
&& (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin))
&& (pLevel->notReady & pTerm->prereqAll)==0
){
- pTerm->wtFlags |= TERM_CODED;
- if( pTerm->iParent>=0 ){
- WhereTerm *pOther = &pTerm->pWC->a[pTerm->iParent];
- if( (--pOther->nChild)==0 ){
- disableTerm(pLevel, pOther);
- }
+ if( nLoop && (pTerm->wtFlags & TERM_LIKE)!=0 ){
+ pTerm->wtFlags |= TERM_LIKECOND;
+ }else{
+ pTerm->wtFlags |= TERM_CODED;
}
+ if( pTerm->iParent<0 ) break;
+ pTerm = &pTerm->pWC->a[pTerm->iParent];
+ pTerm->nChild--;
+ if( pTerm->nChild!=0 ) break;
+ nLoop++;
}
}
@@ -113587,7 +119159,7 @@ static int codeAllEqualityTerms(
pLoop = pLevel->pWLoop;
assert( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 );
nEq = pLoop->u.btree.nEq;
- nSkip = pLoop->u.btree.nSkip;
+ nSkip = pLoop->nSkip;
pIdx = pLoop->u.btree.pIndex;
assert( pIdx!=0 );
@@ -113686,9 +119258,8 @@ static void explainAppendTerm(
/*
** Argument pLevel describes a strategy for scanning table pTab. This
-** function returns a pointer to a string buffer containing a description
-** of the subset of table rows scanned by the strategy in the form of an
-** SQL expression. Or, if all rows are scanned, NULL is returned.
+** function appends text to pStr that describes the subset of table
+** rows scanned by the strategy in the form of an SQL expression.
**
** For example, if the query:
**
@@ -113698,58 +119269,49 @@ static void explainAppendTerm(
** string similar to:
**
** "a=? AND b>?"
-**
-** The returned pointer points to memory obtained from sqlite3DbMalloc().
-** It is the responsibility of the caller to free the buffer when it is
-** no longer required.
*/
-static char *explainIndexRange(sqlite3 *db, WhereLoop *pLoop, Table *pTab){
+static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop, Table *pTab){
Index *pIndex = pLoop->u.btree.pIndex;
u16 nEq = pLoop->u.btree.nEq;
- u16 nSkip = pLoop->u.btree.nSkip;
+ u16 nSkip = pLoop->nSkip;
int i, j;
Column *aCol = pTab->aCol;
i16 *aiColumn = pIndex->aiColumn;
- StrAccum txt;
- if( nEq==0 && (pLoop->wsFlags & (WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ){
- return 0;
- }
- sqlite3StrAccumInit(&txt, 0, 0, SQLITE_MAX_LENGTH);
- txt.db = db;
- sqlite3StrAccumAppend(&txt, " (", 2);
+ if( nEq==0 && (pLoop->wsFlags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ) return;
+ sqlite3StrAccumAppend(pStr, " (", 2);
for(i=0; i<nEq; i++){
char *z = aiColumn[i] < 0 ? "rowid" : aCol[aiColumn[i]].zName;
if( i>=nSkip ){
- explainAppendTerm(&txt, i, z, "=");
+ explainAppendTerm(pStr, i, z, "=");
}else{
- if( i ) sqlite3StrAccumAppend(&txt, " AND ", 5);
- sqlite3StrAccumAppend(&txt, "ANY(", 4);
- sqlite3StrAccumAppendAll(&txt, z);
- sqlite3StrAccumAppend(&txt, ")", 1);
+ if( i ) sqlite3StrAccumAppend(pStr, " AND ", 5);
+ sqlite3XPrintf(pStr, 0, "ANY(%s)", z);
}
}
j = i;
if( pLoop->wsFlags&WHERE_BTM_LIMIT ){
char *z = aiColumn[j] < 0 ? "rowid" : aCol[aiColumn[j]].zName;
- explainAppendTerm(&txt, i++, z, ">");
+ explainAppendTerm(pStr, i++, z, ">");
}
if( pLoop->wsFlags&WHERE_TOP_LIMIT ){
char *z = aiColumn[j] < 0 ? "rowid" : aCol[aiColumn[j]].zName;
- explainAppendTerm(&txt, i, z, "<");
+ explainAppendTerm(pStr, i, z, "<");
}
- sqlite3StrAccumAppend(&txt, ")", 1);
- return sqlite3StrAccumFinish(&txt);
+ sqlite3StrAccumAppend(pStr, ")", 1);
}
/*
** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN
-** command. If the query being compiled is an EXPLAIN QUERY PLAN, a single
-** record is added to the output to describe the table scan strategy in
-** pLevel.
+** command, or if either SQLITE_DEBUG or SQLITE_ENABLE_STMT_SCANSTATUS was
+** defined at compile-time. If it is not a no-op, a single OP_Explain opcode
+** is added to the output to describe the table scan strategy in pLevel.
+**
+** If an OP_Explain opcode is added to the VM, its address is returned.
+** Otherwise, if no OP_Explain is coded, zero is returned.
*/
-static void explainOneScan(
+static int explainOneScan(
Parse *pParse, /* Parse context */
SrcList *pTabList, /* Table list this loop refers to */
WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */
@@ -113757,82 +119319,162 @@ static void explainOneScan(
int iFrom, /* Value for "from" column of output */
u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */
){
-#ifndef SQLITE_DEBUG
+ int ret = 0;
+#if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS)
if( pParse->explain==2 )
#endif
{
struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom];
Vdbe *v = pParse->pVdbe; /* VM being constructed */
sqlite3 *db = pParse->db; /* Database handle */
- char *zMsg; /* Text to add to EQP output */
int iId = pParse->iSelectId; /* Select id (left-most output column) */
int isSearch; /* True for a SEARCH. False for SCAN. */
WhereLoop *pLoop; /* The controlling WhereLoop object */
u32 flags; /* Flags that describe this loop */
+ char *zMsg; /* Text to add to EQP output */
+ StrAccum str; /* EQP output string */
+ char zBuf[100]; /* Initial space for EQP output string */
pLoop = pLevel->pWLoop;
flags = pLoop->wsFlags;
- if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_ONETABLE_ONLY) ) return;
+ if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_ONETABLE_ONLY) ) return 0;
isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0
|| ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0))
|| (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX));
- zMsg = sqlite3MPrintf(db, "%s", isSearch?"SEARCH":"SCAN");
+ sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH);
+ sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN");
if( pItem->pSelect ){
- zMsg = sqlite3MAppendf(db, zMsg, "%s SUBQUERY %d", zMsg,pItem->iSelectId);
+ sqlite3XPrintf(&str, 0, " SUBQUERY %d", pItem->iSelectId);
}else{
- zMsg = sqlite3MAppendf(db, zMsg, "%s TABLE %s", zMsg, pItem->zName);
+ sqlite3XPrintf(&str, 0, " TABLE %s", pItem->zName);
}
if( pItem->zAlias ){
- zMsg = sqlite3MAppendf(db, zMsg, "%s AS %s", zMsg, pItem->zAlias);
+ sqlite3XPrintf(&str, 0, " AS %s", pItem->zAlias);
}
- if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0
- && ALWAYS(pLoop->u.btree.pIndex!=0)
- ){
- const char *zFmt;
- Index *pIdx = pLoop->u.btree.pIndex;
- char *zWhere = explainIndexRange(db, pLoop, pItem->pTab);
+ if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){
+ const char *zFmt = 0;
+ Index *pIdx;
+
+ assert( pLoop->u.btree.pIndex!=0 );
+ pIdx = pLoop->u.btree.pIndex;
assert( !(flags&WHERE_AUTO_INDEX) || (flags&WHERE_IDX_ONLY) );
if( !HasRowid(pItem->pTab) && IsPrimaryKeyIndex(pIdx) ){
- zFmt = zWhere ? "%s USING PRIMARY KEY%.0s%s" : "%s%.0s%s";
+ if( isSearch ){
+ zFmt = "PRIMARY KEY";
+ }
+ }else if( flags & WHERE_PARTIALIDX ){
+ zFmt = "AUTOMATIC PARTIAL COVERING INDEX";
}else if( flags & WHERE_AUTO_INDEX ){
- zFmt = "%s USING AUTOMATIC COVERING INDEX%.0s%s";
+ zFmt = "AUTOMATIC COVERING INDEX";
}else if( flags & WHERE_IDX_ONLY ){
- zFmt = "%s USING COVERING INDEX %s%s";
+ zFmt = "COVERING INDEX %s";
}else{
- zFmt = "%s USING INDEX %s%s";
+ zFmt = "INDEX %s";
+ }
+ if( zFmt ){
+ sqlite3StrAccumAppend(&str, " USING ", 7);
+ sqlite3XPrintf(&str, 0, zFmt, pIdx->zName);
+ explainIndexRange(&str, pLoop, pItem->pTab);
}
- zMsg = sqlite3MAppendf(db, zMsg, zFmt, zMsg, pIdx->zName, zWhere);
- sqlite3DbFree(db, zWhere);
}else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){
- zMsg = sqlite3MAppendf(db, zMsg, "%s USING INTEGER PRIMARY KEY", zMsg);
-
+ const char *zRange;
if( flags&(WHERE_COLUMN_EQ|WHERE_COLUMN_IN) ){
- zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid=?)", zMsg);
+ zRange = "(rowid=?)";
}else if( (flags&WHERE_BOTH_LIMIT)==WHERE_BOTH_LIMIT ){
- zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid>? AND rowid<?)", zMsg);
+ zRange = "(rowid>? AND rowid<?)";
}else if( flags&WHERE_BTM_LIMIT ){
- zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid>?)", zMsg);
- }else if( ALWAYS(flags&WHERE_TOP_LIMIT) ){
- zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid<?)", zMsg);
+ zRange = "(rowid>?)";
+ }else{
+ assert( flags&WHERE_TOP_LIMIT);
+ zRange = "(rowid<?)";
}
+ sqlite3StrAccumAppendAll(&str, " USING INTEGER PRIMARY KEY ");
+ sqlite3StrAccumAppendAll(&str, zRange);
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
else if( (flags & WHERE_VIRTUALTABLE)!=0 ){
- zMsg = sqlite3MAppendf(db, zMsg, "%s VIRTUAL TABLE INDEX %d:%s", zMsg,
+ sqlite3XPrintf(&str, 0, " VIRTUAL TABLE INDEX %d:%s",
pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr);
}
#endif
- zMsg = sqlite3MAppendf(db, zMsg, "%s", zMsg);
- sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg, P4_DYNAMIC);
+#ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS
+ if( pLoop->nOut>=10 ){
+ sqlite3XPrintf(&str, 0, " (~%llu rows)", sqlite3LogEstToInt(pLoop->nOut));
+ }else{
+ sqlite3StrAccumAppend(&str, " (~1 row)", 9);
+ }
+#endif
+ zMsg = sqlite3StrAccumFinish(&str);
+ ret = sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg,P4_DYNAMIC);
}
+ return ret;
}
#else
-# define explainOneScan(u,v,w,x,y,z)
+# define explainOneScan(u,v,w,x,y,z) 0
#endif /* SQLITE_OMIT_EXPLAIN */
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+/*
+** Configure the VM passed as the first argument with an
+** sqlite3_stmt_scanstatus() entry corresponding to the scan used to
+** implement level pLvl. Argument pSrclist is a pointer to the FROM
+** clause that the scan reads data from.
+**
+** If argument addrExplain is not 0, it must be the address of an
+** OP_Explain instruction that describes the same loop.
+*/
+static void addScanStatus(
+ Vdbe *v, /* Vdbe to add scanstatus entry to */
+ SrcList *pSrclist, /* FROM clause pLvl reads data from */
+ WhereLevel *pLvl, /* Level to add scanstatus() entry for */
+ int addrExplain /* Address of OP_Explain (or 0) */
+){
+ const char *zObj = 0;
+ WhereLoop *pLoop = pLvl->pWLoop;
+ if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 && pLoop->u.btree.pIndex!=0 ){
+ zObj = pLoop->u.btree.pIndex->zName;
+ }else{
+ zObj = pSrclist->a[pLvl->iFrom].zName;
+ }
+ sqlite3VdbeScanStatus(
+ v, addrExplain, pLvl->addrBody, pLvl->addrVisit, pLoop->nOut, zObj
+ );
+}
+#else
+# define addScanStatus(a, b, c, d) ((void)d)
+#endif
+
+/*
+** If the most recently coded instruction is a constant range contraint
+** that originated from the LIKE optimization, then change the P3 to be
+** pLoop->iLikeRepCntr and set P5.
+**
+** The LIKE optimization trys to evaluate "x LIKE 'abc%'" as a range
+** expression: "x>='ABC' AND x<'abd'". But this requires that the range
+** scan loop run twice, once for strings and a second time for BLOBs.
+** The OP_String opcodes on the second pass convert the upper and lower
+** bound string contants to blobs. This routine makes the necessary changes
+** to the OP_String opcodes for that to happen.
+*/
+static void whereLikeOptimizationStringFixup(
+ Vdbe *v, /* prepared statement under construction */
+ WhereLevel *pLevel, /* The loop that contains the LIKE operator */
+ WhereTerm *pTerm /* The upper or lower bound just coded */
+){
+ if( pTerm->wtFlags & TERM_LIKEOPT ){
+ VdbeOp *pOp;
+ assert( pLevel->iLikeRepCntr>0 );
+ pOp = sqlite3VdbeGetOp(v, -1);
+ assert( pOp!=0 );
+ assert( pOp->opcode==OP_String8
+ || pTerm->pWC->pWInfo->pParse->db->mallocFailed );
+ pOp->p3 = pLevel->iLikeRepCntr;
+ pOp->p5 = 1;
+ }
+}
/*
** Generate code for the start of the iLevel-th loop in the WHERE clause
@@ -114133,7 +119775,7 @@ static Bitmask codeOneLoopStart(
pIdx = pLoop->u.btree.pIndex;
iIdxCur = pLevel->iIdxCur;
- assert( nEq>=pLoop->u.btree.nSkip );
+ assert( nEq>=pLoop->nSkip );
/* If this loop satisfies a sort order (pOrderBy) request that
** was passed to this function to implement a "SELECT min(x) ..."
@@ -114150,7 +119792,7 @@ static Bitmask codeOneLoopStart(
&& pWInfo->nOBSat>0
&& (pIdx->nKeyCol>nEq)
){
- assert( pLoop->u.btree.nSkip==0 );
+ assert( pLoop->nSkip==0 );
bSeekPastNull = 1;
nExtraReg = 1;
}
@@ -114162,10 +119804,25 @@ static Bitmask codeOneLoopStart(
if( pLoop->wsFlags & WHERE_BTM_LIMIT ){
pRangeStart = pLoop->aLTerm[j++];
nExtraReg = 1;
+ /* Like optimization range constraints always occur in pairs */
+ assert( (pRangeStart->wtFlags & TERM_LIKEOPT)==0 ||
+ (pLoop->wsFlags & WHERE_TOP_LIMIT)!=0 );
}
if( pLoop->wsFlags & WHERE_TOP_LIMIT ){
pRangeEnd = pLoop->aLTerm[j++];
nExtraReg = 1;
+ if( (pRangeEnd->wtFlags & TERM_LIKEOPT)!=0 ){
+ assert( pRangeStart!=0 ); /* LIKE opt constraints */
+ assert( pRangeStart->wtFlags & TERM_LIKEOPT ); /* occur in pairs */
+ pLevel->iLikeRepCntr = ++pParse->nMem;
+ testcase( bRev );
+ testcase( pIdx->aSortOrder[nEq]==SQLITE_SO_DESC );
+ sqlite3VdbeAddOp2(v, OP_Integer,
+ bRev ^ (pIdx->aSortOrder[nEq]==SQLITE_SO_DESC),
+ pLevel->iLikeRepCntr);
+ VdbeComment((v, "LIKE loop counter"));
+ pLevel->addrLikeRep = sqlite3VdbeCurrentAddr(v);
+ }
if( pRangeStart==0
&& (j = pIdx->aiColumn[nEq])>=0
&& pIdx->pTable->aCol[j].notNull==0
@@ -114208,6 +119865,7 @@ static Bitmask codeOneLoopStart(
if( pRangeStart ){
Expr *pRight = pRangeStart->pExpr->pRight;
sqlite3ExprCode(pParse, pRight, regBase+nEq);
+ whereLikeOptimizationStringFixup(v, pLevel, pRangeStart);
if( (pRangeStart->wtFlags & TERM_VNULL)==0
&& sqlite3ExprCanBeNull(pRight)
){
@@ -114253,6 +119911,7 @@ static Bitmask codeOneLoopStart(
Expr *pRight = pRangeEnd->pExpr->pRight;
sqlite3ExprCacheRemove(pParse, regBase+nEq, 1);
sqlite3ExprCode(pParse, pRight, regBase+nEq);
+ whereLikeOptimizationStringFixup(v, pLevel, pRangeEnd);
if( (pRangeEnd->wtFlags & TERM_VNULL)==0
&& sqlite3ExprCanBeNull(pRight)
){
@@ -114367,7 +120026,7 @@ static Bitmask codeOneLoopStart(
** B: <after the loop>
**
** Added 2014-05-26: If the table is a WITHOUT ROWID table, then
- ** use an ephermeral index instead of a RowSet to record the primary
+ ** use an ephemeral index instead of a RowSet to record the primary
** keys of the rows we have already seen.
**
*/
@@ -114418,7 +120077,7 @@ static Bitmask codeOneLoopStart(
}
/* Initialize the rowset register to contain NULL. An SQL NULL is
- ** equivalent to an empty rowset. Or, create an ephermeral index
+ ** equivalent to an empty rowset. Or, create an ephemeral index
** capable of holding primary keys in the case of a WITHOUT ROWID.
**
** Also initialize regReturn to contain the address of the instruction
@@ -114463,10 +120122,9 @@ static Bitmask codeOneLoopStart(
Expr *pExpr = pWC->a[iTerm].pExpr;
if( &pWC->a[iTerm] == pTerm ) continue;
if( ExprHasProperty(pExpr, EP_FromJoin) ) continue;
- testcase( pWC->a[iTerm].wtFlags & TERM_ORINFO );
- testcase( pWC->a[iTerm].wtFlags & TERM_VIRTUAL );
- if( pWC->a[iTerm].wtFlags & (TERM_ORINFO|TERM_VIRTUAL) ) continue;
+ if( (pWC->a[iTerm].wtFlags & TERM_VIRTUAL)!=0 ) continue;
if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue;
+ testcase( pWC->a[iTerm].wtFlags & TERM_ORINFO );
pExpr = sqlite3ExprDup(db, pExpr, 0);
pAndExpr = sqlite3ExprAnd(db, pAndExpr, pExpr);
}
@@ -114479,8 +120137,10 @@ static Bitmask codeOneLoopStart(
** eliminating duplicates from other WHERE clauses, the action for each
** sub-WHERE clause is to to invoke the main loop body as a subroutine.
*/
- wctrlFlags = WHERE_OMIT_OPEN_CLOSE | WHERE_AND_ONLY |
- WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY;
+ wctrlFlags = WHERE_OMIT_OPEN_CLOSE
+ | WHERE_FORCE_TABLE
+ | WHERE_ONETABLE_ONLY
+ | WHERE_NO_AUTOINDEX;
for(ii=0; ii<pOrWc->nTerm; ii++){
WhereTerm *pOrTerm = &pOrWc->a[ii];
if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){
@@ -114492,14 +120152,17 @@ static Bitmask codeOneLoopStart(
pOrExpr = pAndExpr;
}
/* Loop through table entries that match term pOrTerm. */
+ WHERETRACE(0xffff, ("Subplan for OR-clause:\n"));
pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0,
wctrlFlags, iCovCur);
assert( pSubWInfo || pParse->nErr || db->mallocFailed );
if( pSubWInfo ){
WhereLoop *pSubLoop;
- explainOneScan(
+ int addrExplain = explainOneScan(
pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0
);
+ addScanStatus(v, pOrTab, &pSubWInfo->a[0], addrExplain);
+
/* This is the sub-WHERE clause body. First skip over
** duplicate rows from prior sub-WHERE clauses, and record the
** rowid (or PRIMARY KEY) for the current row so that the same
@@ -114630,11 +120293,16 @@ static Bitmask codeOneLoopStart(
}
}
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ pLevel->addrVisit = sqlite3VdbeCurrentAddr(v);
+#endif
+
/* Insert code to test every subexpression that can be completely
** computed using the current set of tables.
*/
for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
Expr *pE;
+ int skipLikeAddr = 0;
testcase( pTerm->wtFlags & TERM_VIRTUAL );
testcase( pTerm->wtFlags & TERM_CODED );
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
@@ -114649,7 +120317,13 @@ static Bitmask codeOneLoopStart(
if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){
continue;
}
+ if( pTerm->wtFlags & TERM_LIKECOND ){
+ assert( pLevel->iLikeRepCntr>0 );
+ skipLikeAddr = sqlite3VdbeAddOp1(v, OP_IfNot, pLevel->iLikeRepCntr);
+ VdbeCoverage(v);
+ }
sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL);
+ if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr);
pTerm->wtFlags |= TERM_CODED;
}
@@ -114711,21 +120385,26 @@ static Bitmask codeOneLoopStart(
return pLevel->notReady;
}
-#if defined(WHERETRACE_ENABLED) && defined(SQLITE_ENABLE_TREE_EXPLAIN)
+#ifdef WHERETRACE_ENABLED
/*
-** Generate "Explanation" text for a WhereTerm.
+** Print the content of a WhereTerm object
*/
-static void whereExplainTerm(Vdbe *v, WhereTerm *pTerm){
- char zType[4];
- memcpy(zType, "...", 4);
- if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V';
- if( pTerm->eOperator & WO_EQUIV ) zType[1] = 'E';
- if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) zType[2] = 'L';
- sqlite3ExplainPrintf(v, "%s ", zType);
- sqlite3ExplainExpr(v, pTerm->pExpr);
+static void whereTermPrint(WhereTerm *pTerm, int iTerm){
+ if( pTerm==0 ){
+ sqlite3DebugPrintf("TERM-%-3d NULL\n", iTerm);
+ }else{
+ char zType[4];
+ memcpy(zType, "...", 4);
+ if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V';
+ if( pTerm->eOperator & WO_EQUIV ) zType[1] = 'E';
+ if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) zType[2] = 'L';
+ sqlite3DebugPrintf("TERM-%-3d %p %s cursor=%-3d prob=%-3d op=0x%03x\n",
+ iTerm, pTerm, zType, pTerm->leftCursor, pTerm->truthProb,
+ pTerm->eOperator);
+ sqlite3TreeViewExpr(0, pTerm->pExpr, 0);
+ }
}
-#endif /* WHERETRACE_ENABLED && SQLITE_ENABLE_TREE_EXPLAIN */
-
+#endif
#ifdef WHERETRACE_ENABLED
/*
@@ -114741,8 +120420,8 @@ static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){
sqlite3DebugPrintf(" %12s",
pItem->zAlias ? pItem->zAlias : pTab->zName);
if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){
- const char *zName;
- if( p->u.btree.pIndex && (zName = p->u.btree.pIndex->zName)!=0 ){
+ const char *zName;
+ if( p->u.btree.pIndex && (zName = p->u.btree.pIndex->zName)!=0 ){
if( strncmp(zName, "sqlite_autoindex_", 17)==0 ){
int i = sqlite3Strlen30(zName) - 1;
while( zName[i]!='_' ) i--;
@@ -114763,29 +120442,18 @@ static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){
sqlite3DebugPrintf(" %-19s", z);
sqlite3_free(z);
}
- sqlite3DebugPrintf(" f %05x N %d", p->wsFlags, p->nLTerm);
+ if( p->wsFlags & WHERE_SKIPSCAN ){
+ sqlite3DebugPrintf(" f %05x %d-%d", p->wsFlags, p->nLTerm,p->nSkip);
+ }else{
+ sqlite3DebugPrintf(" f %05x N %d", p->wsFlags, p->nLTerm);
+ }
sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut);
-#ifdef SQLITE_ENABLE_TREE_EXPLAIN
- /* If the 0x100 bit of wheretracing is set, then show all of the constraint
- ** expressions in the WhereLoop.aLTerm[] array.
- */
- if( p->nLTerm && (sqlite3WhereTrace & 0x100)!=0 ){ /* WHERETRACE 0x100 */
+ if( p->nLTerm && (sqlite3WhereTrace & 0x100)!=0 ){
int i;
- Vdbe *v = pWInfo->pParse->pVdbe;
- sqlite3ExplainBegin(v);
for(i=0; i<p->nLTerm; i++){
- WhereTerm *pTerm = p->aLTerm[i];
- if( pTerm==0 ) continue;
- sqlite3ExplainPrintf(v, " (%d) #%-2d ", i+1, (int)(pTerm-pWC->a));
- sqlite3ExplainPush(v);
- whereExplainTerm(v, pTerm);
- sqlite3ExplainPop(v);
- sqlite3ExplainNL(v);
+ whereTermPrint(p->aLTerm[i], i);
}
- sqlite3ExplainFinish(v);
- sqlite3DebugPrintf("%s", sqlite3VdbeExplanation(v));
}
-#endif
}
#endif
@@ -114811,7 +120479,6 @@ static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){
p->u.vtab.idxStr = 0;
}else if( (p->wsFlags & WHERE_AUTO_INDEX)!=0 && p->u.btree.pIndex!=0 ){
sqlite3DbFree(db, p->u.btree.pIndex->zColAff);
- sqlite3KeyInfoUnref(p->u.btree.pIndex->pKeyInfo);
sqlite3DbFree(db, p->u.btree.pIndex);
p->u.btree.pIndex = 0;
}
@@ -114875,6 +120542,13 @@ static void whereLoopDelete(sqlite3 *db, WhereLoop *p){
*/
static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
if( ALWAYS(pWInfo) ){
+ int i;
+ for(i=0; i<pWInfo->nLevel; i++){
+ WhereLevel *pLevel = &pWInfo->a[i];
+ if( pLevel->pWLoop && (pLevel->pWLoop->wsFlags & WHERE_IN_ABLE) ){
+ sqlite3DbFree(db, pLevel->u.in.aInLoop);
+ }
+ }
whereClauseClear(&pWInfo->sWC);
while( pWInfo->pLoops ){
WhereLoop *p = pWInfo->pLoops;
@@ -114886,10 +120560,11 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
}
/*
-** Return TRUE if both of the following are true:
+** Return TRUE if all of the following are true:
**
** (1) X has the same or lower cost that Y
** (2) X is a proper subset of Y
+** (3) X skips at least as many columns as Y
**
** By "proper subset" we mean that X uses fewer WHERE clause terms
** than Y and that every WHERE clause term used by X is also used
@@ -114897,19 +120572,25 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
**
** If X is a proper subset of Y then Y is a better choice and ought
** to have a lower cost. This routine returns TRUE when that cost
-** relationship is inverted and needs to be adjusted.
+** relationship is inverted and needs to be adjusted. The third rule
+** was added because if X uses skip-scan less than Y it still might
+** deserve a lower cost even if it is a proper subset of Y.
*/
static int whereLoopCheaperProperSubset(
const WhereLoop *pX, /* First WhereLoop to compare */
const WhereLoop *pY /* Compare against this WhereLoop */
){
int i, j;
- if( pX->nLTerm >= pY->nLTerm ) return 0; /* X is not a subset of Y */
+ if( pX->nLTerm-pX->nSkip >= pY->nLTerm-pY->nSkip ){
+ return 0; /* X is not a subset of Y */
+ }
+ if( pY->nSkip > pX->nSkip ) return 0;
if( pX->rRun >= pY->rRun ){
if( pX->rRun > pY->rRun ) return 0; /* X costs more than Y */
if( pX->nOut > pY->nOut ) return 0; /* X costs more than Y */
}
for(i=pX->nLTerm-1; i>=0; i--){
+ if( pX->aLTerm[i]==0 ) continue;
for(j=pY->nLTerm-1; j>=0; j--){
if( pY->aLTerm[j]==pX->aLTerm[i] ) break;
}
@@ -114931,33 +120612,24 @@ static int whereLoopCheaperProperSubset(
** To say "WhereLoop X is a proper subset of Y" means that X uses fewer
** WHERE clause terms than Y and that every WHERE clause term used by X is
** also used by Y.
-**
-** This adjustment is omitted for SKIPSCAN loops. In a SKIPSCAN loop, the
-** WhereLoop.nLTerm field is not an accurate measure of the number of WHERE
-** clause terms covered, since some of the first nLTerm entries in aLTerm[]
-** will be NULL (because they are skipped). That makes it more difficult
-** to compare the loops. We could add extra code to do the comparison, and
-** perhaps we will someday. But SKIPSCAN is sufficiently uncommon, and this
-** adjustment is sufficient minor, that it is very difficult to construct
-** a test case where the extra code would improve the query plan. Better
-** to avoid the added complexity and just omit cost adjustments to SKIPSCAN
-** loops.
*/
static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){
if( (pTemplate->wsFlags & WHERE_INDEXED)==0 ) return;
- if( (pTemplate->wsFlags & WHERE_SKIPSCAN)!=0 ) return;
for(; p; p=p->pNextLoop){
if( p->iTab!=pTemplate->iTab ) continue;
if( (p->wsFlags & WHERE_INDEXED)==0 ) continue;
- if( (p->wsFlags & WHERE_SKIPSCAN)!=0 ) continue;
if( whereLoopCheaperProperSubset(p, pTemplate) ){
/* Adjust pTemplate cost downward so that it is cheaper than its
- ** subset p */
+ ** subset p. */
+ WHERETRACE(0x80,("subset cost adjustment %d,%d to %d,%d\n",
+ pTemplate->rRun, pTemplate->nOut, p->rRun, p->nOut-1));
pTemplate->rRun = p->rRun;
pTemplate->nOut = p->nOut - 1;
}else if( whereLoopCheaperProperSubset(pTemplate, p) ){
/* Adjust pTemplate cost upward so that it is costlier than p since
** pTemplate is a proper subset of p */
+ WHERETRACE(0x80,("subset cost adjustment %d,%d to %d,%d\n",
+ pTemplate->rRun, pTemplate->nOut, p->rRun, p->nOut+1));
pTemplate->rRun = p->rRun;
pTemplate->nOut = p->nOut + 1;
}
@@ -115002,8 +120674,9 @@ static WhereLoop **whereLoopFindLesser(
/* Any loop using an appliation-defined index (or PRIMARY KEY or
** UNIQUE constraint) with one or more == constraints is better
- ** than an automatic index. */
+ ** than an automatic index. Unless it is a skip-scan. */
if( (p->wsFlags & WHERE_AUTO_INDEX)!=0
+ && (pTemplate->nSkip)==0
&& (pTemplate->wsFlags & WHERE_INDEXED)!=0
&& (pTemplate->wsFlags & WHERE_COLUMN_EQ)!=0
&& (p->prereq & pTemplate->prereq)==pTemplate->prereq
@@ -115098,7 +120771,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
** than pTemplate, so just ignore pTemplate */
#if WHERETRACE_ENABLED /* 0x8 */
if( sqlite3WhereTrace & 0x8 ){
- sqlite3DebugPrintf("ins-noop: ");
+ sqlite3DebugPrintf(" skip: ");
whereLoopPrint(pTemplate, pBuilder->pWC);
}
#endif
@@ -115114,10 +120787,10 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
#if WHERETRACE_ENABLED /* 0x8 */
if( sqlite3WhereTrace & 0x8 ){
if( p!=0 ){
- sqlite3DebugPrintf("ins-del: ");
+ sqlite3DebugPrintf("replace: ");
whereLoopPrint(p, pBuilder->pWC);
}
- sqlite3DebugPrintf("ins-new: ");
+ sqlite3DebugPrintf(" add: ");
whereLoopPrint(pTemplate, pBuilder->pWC);
}
#endif
@@ -115141,7 +120814,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
*ppTail = pToDel->pNextLoop;
#if WHERETRACE_ENABLED /* 0x8 */
if( sqlite3WhereTrace & 0x8 ){
- sqlite3DebugPrintf("ins-del: ");
+ sqlite3DebugPrintf(" delete: ");
whereLoopPrint(pToDel, pBuilder->pWC);
}
#endif
@@ -115162,19 +120835,42 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
** Adjust the WhereLoop.nOut value downward to account for terms of the
** WHERE clause that reference the loop but which are not used by an
** index.
-**
-** In the current implementation, the first extra WHERE clause term reduces
-** the number of output rows by a factor of 10 and each additional term
-** reduces the number of output rows by sqrt(2).
-*/
-static void whereLoopOutputAdjust(WhereClause *pWC, WhereLoop *pLoop){
+*
+** For every WHERE clause term that is not used by the index
+** and which has a truth probability assigned by one of the likelihood(),
+** likely(), or unlikely() SQL functions, reduce the estimated number
+** of output rows by the probability specified.
+**
+** TUNING: For every WHERE clause term that is not used by the index
+** and which does not have an assigned truth probability, heuristics
+** described below are used to try to estimate the truth probability.
+** TODO --> Perhaps this is something that could be improved by better
+** table statistics.
+**
+** Heuristic 1: Estimate the truth probability as 93.75%. The 93.75%
+** value corresponds to -1 in LogEst notation, so this means decrement
+** the WhereLoop.nOut field for every such WHERE clause term.
+**
+** Heuristic 2: If there exists one or more WHERE clause terms of the
+** form "x==EXPR" and EXPR is not a constant 0 or 1, then make sure the
+** final output row estimate is no greater than 1/4 of the total number
+** of rows in the table. In other words, assume that x==EXPR will filter
+** out at least 3 out of 4 rows. If EXPR is -1 or 0 or 1, then maybe the
+** "x" column is boolean or else -1 or 0 or 1 is a common default value
+** on the "x" column and so in that case only cap the output row estimate
+** at 1/2 instead of 1/4.
+*/
+static void whereLoopOutputAdjust(
+ WhereClause *pWC, /* The WHERE clause */
+ WhereLoop *pLoop, /* The loop to adjust downward */
+ LogEst nRow /* Number of rows in the entire table */
+){
WhereTerm *pTerm, *pX;
Bitmask notAllowed = ~(pLoop->prereq|pLoop->maskSelf);
- int i, j;
+ int i, j, k;
+ LogEst iReduce = 0; /* pLoop->nOut should not exceed nRow-iReduce */
- if( !OptimizationEnabled(pWC->pWInfo->pParse->db, SQLITE_AdjustOutEst) ){
- return;
- }
+ assert( (pLoop->wsFlags & WHERE_AUTO_INDEX)==0 );
for(i=pWC->nTerm, pTerm=pWC->a; i>0; i--, pTerm++){
if( (pTerm->wtFlags & TERM_VIRTUAL)!=0 ) break;
if( (pTerm->prereqAll & pLoop->maskSelf)==0 ) continue;
@@ -115186,9 +120882,27 @@ static void whereLoopOutputAdjust(WhereClause *pWC, WhereLoop *pLoop){
if( pX->iParent>=0 && (&pWC->a[pX->iParent])==pTerm ) break;
}
if( j<0 ){
- pLoop->nOut += (pTerm->truthProb<=0 ? pTerm->truthProb : -1);
+ if( pTerm->truthProb<=0 ){
+ /* If a truth probability is specified using the likelihood() hints,
+ ** then use the probability provided by the application. */
+ pLoop->nOut += pTerm->truthProb;
+ }else{
+ /* In the absence of explicit truth probabilities, use heuristics to
+ ** guess a reasonable truth probability. */
+ pLoop->nOut--;
+ if( pTerm->eOperator&WO_EQ ){
+ Expr *pRight = pTerm->pExpr->pRight;
+ if( sqlite3ExprIsInteger(pRight, &k) && k>=(-1) && k<=1 ){
+ k = 10;
+ }else{
+ k = 20;
+ }
+ if( iReduce<k ) iReduce = k;
+ }
+ }
}
}
+ if( pLoop->nOut > nRow-iReduce ) pLoop->nOut = nRow - iReduce;
}
/*
@@ -115229,11 +120943,12 @@ static int whereLoopAddBtreeIndex(
Bitmask saved_prereq; /* Original value of pNew->prereq */
u16 saved_nLTerm; /* Original value of pNew->nLTerm */
u16 saved_nEq; /* Original value of pNew->u.btree.nEq */
- u16 saved_nSkip; /* Original value of pNew->u.btree.nSkip */
+ u16 saved_nSkip; /* Original value of pNew->nSkip */
u32 saved_wsFlags; /* Original value of pNew->wsFlags */
LogEst saved_nOut; /* Original value of pNew->nOut */
int iCol; /* Index of the column in the table */
int rc = SQLITE_OK; /* Return code */
+ LogEst rSize; /* Number of rows in the table */
LogEst rLogSize; /* Logarithm of table size */
WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */
@@ -115257,41 +120972,14 @@ static int whereLoopAddBtreeIndex(
pTerm = whereScanInit(&scan, pBuilder->pWC, pSrc->iCursor, iCol,
opMask, pProbe);
saved_nEq = pNew->u.btree.nEq;
- saved_nSkip = pNew->u.btree.nSkip;
+ saved_nSkip = pNew->nSkip;
saved_nLTerm = pNew->nLTerm;
saved_wsFlags = pNew->wsFlags;
saved_prereq = pNew->prereq;
saved_nOut = pNew->nOut;
pNew->rSetup = 0;
- rLogSize = estLog(pProbe->aiRowLogEst[0]);
-
- /* Consider using a skip-scan if there are no WHERE clause constraints
- ** available for the left-most terms of the index, and if the average
- ** number of repeats in the left-most terms is at least 18.
- **
- ** The magic number 18 is selected on the basis that scanning 17 rows
- ** is almost always quicker than an index seek (even though if the index
- ** contains fewer than 2^17 rows we assume otherwise in other parts of
- ** the code). And, even if it is not, it should not be too much slower.
- ** On the other hand, the extra seeks could end up being significantly
- ** more expensive. */
- assert( 42==sqlite3LogEst(18) );
- if( pTerm==0
- && saved_nEq==saved_nSkip
- && saved_nEq+1<pProbe->nKeyCol
- && pProbe->aiRowLogEst[saved_nEq+1]>=42 /* TUNING: Minimum for skip-scan */
- && (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK
- ){
- LogEst nIter;
- pNew->u.btree.nEq++;
- pNew->u.btree.nSkip++;
- pNew->aLTerm[pNew->nLTerm++] = 0;
- pNew->wsFlags |= WHERE_SKIPSCAN;
- nIter = pProbe->aiRowLogEst[saved_nEq] - pProbe->aiRowLogEst[saved_nEq+1];
- pNew->nOut -= nIter;
- whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nIter + nInMul);
- pNew->nOut = saved_nOut;
- }
+ rSize = pProbe->aiRowLogEst[0];
+ rLogSize = estLog(rSize);
for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){
u16 eOp = pTerm->eOperator; /* Shorthand for pTerm->eOperator */
LogEst rCostIdx;
@@ -115307,6 +120995,10 @@ static int whereLoopAddBtreeIndex(
}
if( pTerm->prereqRight & pNew->maskSelf ) continue;
+ /* Do not allow the upper bound of a LIKE optimization range constraint
+ ** to mix with a lower range bound from some other source */
+ if( pTerm->wtFlags & TERM_LIKEOPT && pTerm->eOperator==WO_LT ) continue;
+
pNew->wsFlags = saved_wsFlags;
pNew->u.btree.nEq = saved_nEq;
pNew->nLTerm = saved_nLTerm;
@@ -115336,7 +121028,7 @@ static int whereLoopAddBtreeIndex(
}else if( eOp & (WO_EQ) ){
pNew->wsFlags |= WHERE_COLUMN_EQ;
if( iCol<0 || (nInMul==0 && pNew->u.btree.nEq==pProbe->nKeyCol-1) ){
- if( iCol>=0 && !IsUniqueIndex(pProbe) ){
+ if( iCol>=0 && pProbe->uniqNotNull==0 ){
pNew->wsFlags |= WHERE_UNQ_WANTED;
}else{
pNew->wsFlags |= WHERE_ONEROW;
@@ -115350,6 +121042,17 @@ static int whereLoopAddBtreeIndex(
pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT;
pBtm = pTerm;
pTop = 0;
+ if( pTerm->wtFlags & TERM_LIKEOPT ){
+ /* Range contraints that come from the LIKE optimization are
+ ** always used in pairs. */
+ pTop = &pTerm[1];
+ assert( (pTop-(pTerm->pWC->a))<pTerm->pWC->nTerm );
+ assert( pTop->wtFlags & TERM_LIKEOPT );
+ assert( pTop->eOperator==WO_LT );
+ if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */
+ pNew->aLTerm[pNew->nLTerm++] = pTop;
+ pNew->wsFlags |= WHERE_TOP_LIMIT;
+ }
}else{
assert( eOp & (WO_LT|WO_LE) );
testcase( eOp & WO_LT );
@@ -115386,7 +121089,6 @@ static int whereLoopAddBtreeIndex(
if( nInMul==0
&& pProbe->nSample
&& pNew->u.btree.nEq<=pProbe->nSampleCol
- && OptimizationEnabled(db, SQLITE_Stat3)
&& ((eOp & WO_IN)==0 || !ExprHasProperty(pTerm->pExpr, EP_xIsSelect))
){
Expr *pExpr = pTerm->pExpr;
@@ -115433,7 +121135,7 @@ static int whereLoopAddBtreeIndex(
nOutUnadjusted = pNew->nOut;
pNew->rRun += nInMul + nIn;
pNew->nOut += nInMul + nIn;
- whereLoopOutputAdjust(pBuilder->pWC, pNew);
+ whereLoopOutputAdjust(pBuilder->pWC, pNew, rSize);
rc = whereLoopInsert(pBuilder, pNew);
if( pNew->wsFlags & WHERE_COLUMN_RANGE ){
@@ -115454,10 +121156,45 @@ static int whereLoopAddBtreeIndex(
}
pNew->prereq = saved_prereq;
pNew->u.btree.nEq = saved_nEq;
- pNew->u.btree.nSkip = saved_nSkip;
+ pNew->nSkip = saved_nSkip;
pNew->wsFlags = saved_wsFlags;
pNew->nOut = saved_nOut;
pNew->nLTerm = saved_nLTerm;
+
+ /* Consider using a skip-scan if there are no WHERE clause constraints
+ ** available for the left-most terms of the index, and if the average
+ ** number of repeats in the left-most terms is at least 18.
+ **
+ ** The magic number 18 is selected on the basis that scanning 17 rows
+ ** is almost always quicker than an index seek (even though if the index
+ ** contains fewer than 2^17 rows we assume otherwise in other parts of
+ ** the code). And, even if it is not, it should not be too much slower.
+ ** On the other hand, the extra seeks could end up being significantly
+ ** more expensive. */
+ assert( 42==sqlite3LogEst(18) );
+ if( saved_nEq==saved_nSkip
+ && saved_nEq+1<pProbe->nKeyCol
+ && pProbe->noSkipScan==0
+ && pProbe->aiRowLogEst[saved_nEq+1]>=42 /* TUNING: Minimum for skip-scan */
+ && (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK
+ ){
+ LogEst nIter;
+ pNew->u.btree.nEq++;
+ pNew->nSkip++;
+ pNew->aLTerm[pNew->nLTerm++] = 0;
+ pNew->wsFlags |= WHERE_SKIPSCAN;
+ nIter = pProbe->aiRowLogEst[saved_nEq] - pProbe->aiRowLogEst[saved_nEq+1];
+ pNew->nOut -= nIter;
+ /* TUNING: Because uncertainties in the estimates for skip-scan queries,
+ ** add a 1.375 fudge factor to make skip-scan slightly less likely. */
+ nIter += 5;
+ whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nIter + nInMul);
+ pNew->nOut = saved_nOut;
+ pNew->u.btree.nEq = saved_nEq;
+ pNew->nSkip = saved_nSkip;
+ pNew->wsFlags = saved_wsFlags;
+ }
+
return rc;
}
@@ -115483,6 +121220,7 @@ static int indexMightHelpWithOrderBy(
Expr *pExpr = sqlite3ExprSkipCollate(pOB->a[ii].pExpr);
if( pExpr->op!=TK_COLUMN ) return 0;
if( pExpr->iTable==iCursor ){
+ if( pExpr->iColumn<0 ) return 1;
for(jj=0; jj<pIndex->nKeyCol; jj++){
if( pExpr->iColumn==pIndex->aiColumn[jj] ) return 1;
}
@@ -115516,7 +121254,12 @@ static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){
int i;
WhereTerm *pTerm;
for(i=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
- if( sqlite3ExprImpliesExpr(pTerm->pExpr, pWhere, iTab) ) return 1;
+ Expr *pExpr = pTerm->pExpr;
+ if( sqlite3ExprImpliesExpr(pExpr, pWhere, iTab)
+ && (!ExprHasProperty(pExpr, EP_FromJoin) || pExpr->iRightJoinTable==iTab)
+ ){
+ return 1;
+ }
}
return 0;
}
@@ -115620,6 +121363,7 @@ static int whereLoopAddBtree(
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
/* Automatic indexes */
if( !pBuilder->pOrSet
+ && (pWInfo->wctrlFlags & WHERE_NO_AUTOINDEX)==0
&& (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0
&& pSrc->pIndex==0
&& !pSrc->viaCoroutine
@@ -115635,18 +121379,26 @@ static int whereLoopAddBtree(
if( pTerm->prereqRight & pNew->maskSelf ) continue;
if( termCanDriveIndex(pTerm, pSrc, 0) ){
pNew->u.btree.nEq = 1;
- pNew->u.btree.nSkip = 0;
+ pNew->nSkip = 0;
pNew->u.btree.pIndex = 0;
pNew->nLTerm = 1;
pNew->aLTerm[0] = pTerm;
/* TUNING: One-time cost for computing the automatic index is
- ** approximately 7*N*log2(N) where N is the number of rows in
- ** the table being indexed. */
- pNew->rSetup = rLogSize + rSize + 28; assert( 28==sqlite3LogEst(7) );
+ ** estimated to be X*N*log2(N) where N is the number of rows in
+ ** the table being indexed and where X is 7 (LogEst=28) for normal
+ ** tables or 1.375 (LogEst=4) for views and subqueries. The value
+ ** of X is smaller for views and subqueries so that the query planner
+ ** will be more aggressive about generating automatic indexes for
+ ** those objects, since there is no opportunity to add schema
+ ** indexes on subqueries and views. */
+ pNew->rSetup = rLogSize + rSize + 4;
+ if( pTab->pSelect==0 && (pTab->tabFlags & TF_Ephemeral)==0 ){
+ pNew->rSetup += 24;
+ }
ApplyCostMultiplier(pNew->rSetup, pTab->costMult);
/* TUNING: Each index lookup yields 20 rows in the table. This
** is more than the usual guess of 10 rows, since we have no way
- ** of knowning how selective the index will ultimately be. It would
+ ** of knowing how selective the index will ultimately be. It would
** not be unreasonable to make this value much larger. */
pNew->nOut = 43; assert( 43==sqlite3LogEst(20) );
pNew->rRun = sqlite3LogEstAdd(rLogSize,pNew->nOut);
@@ -115662,12 +121414,13 @@ static int whereLoopAddBtree(
*/
for(; rc==SQLITE_OK && pProbe; pProbe=pProbe->pNext, iSortIdx++){
if( pProbe->pPartIdxWhere!=0
- && !whereUsablePartialIndex(pNew->iTab, pWC, pProbe->pPartIdxWhere) ){
+ && !whereUsablePartialIndex(pSrc->iCursor, pWC, pProbe->pPartIdxWhere) ){
+ testcase( pNew->iTab!=pSrc->iCursor ); /* See ticket [98d973b8f5] */
continue; /* Partial index inappropriate for this query */
}
rSize = pProbe->aiRowLogEst[0];
pNew->u.btree.nEq = 0;
- pNew->u.btree.nSkip = 0;
+ pNew->nSkip = 0;
pNew->nLTerm = 0;
pNew->iSortIdx = 0;
pNew->rSetup = 0;
@@ -115686,7 +121439,7 @@ static int whereLoopAddBtree(
/* TUNING: Cost of full table scan is (N*3.0). */
pNew->rRun = rSize + 16;
ApplyCostMultiplier(pNew->rRun, pTab->costMult);
- whereLoopOutputAdjust(pWC, pNew);
+ whereLoopOutputAdjust(pWC, pNew, rSize);
rc = whereLoopInsert(pBuilder, pNew);
pNew->nOut = rSize;
if( rc ) break;
@@ -115722,7 +121475,7 @@ static int whereLoopAddBtree(
pNew->rRun = sqlite3LogEstAdd(pNew->rRun, rSize+16);
}
ApplyCostMultiplier(pNew->rRun, pTab->costMult);
- whereLoopOutputAdjust(pWC, pNew);
+ whereLoopOutputAdjust(pWC, pNew, rSize);
rc = whereLoopInsert(pBuilder, pNew);
pNew->nOut = rSize;
if( rc ) break;
@@ -115929,7 +121682,6 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){
struct SrcList_item *pItem;
pWC = pBuilder->pWC;
- if( pWInfo->wctrlFlags & WHERE_AND_ONLY ) return SQLITE_OK;
pWCEnd = pWC->a + pWC->nTerm;
pNew = pBuilder->pNew;
memset(&sSum, 0, sizeof(sSum));
@@ -115950,6 +121702,7 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){
sSubBuild.pOrderBy = 0;
sSubBuild.pOrSet = &sCur;
+ WHERETRACE(0x200, ("Begin processing OR-clause %p\n", pTerm));
for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){
if( (pOrTerm->eOperator & WO_AND)!=0 ){
sSubBuild.pWC = &pOrTerm->u.pAndInfo->wc;
@@ -115964,6 +121717,15 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){
continue;
}
sCur.n = 0;
+#ifdef WHERETRACE_ENABLED
+ WHERETRACE(0x200, ("OR-term %d of %p has %d subterms:\n",
+ (int)(pOrTerm-pOrWC->a), pTerm, sSubBuild.pWC->nTerm));
+ if( sqlite3WhereTrace & 0x400 ){
+ for(i=0; i<sSubBuild.pWC->nTerm; i++){
+ whereTermPrint(&sSubBuild.pWC->a[i], i);
+ }
+ }
+#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pItem->pTab) ){
rc = whereLoopAddVirtual(&sSubBuild, mExtra);
@@ -115972,6 +121734,9 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){
{
rc = whereLoopAddBtree(&sSubBuild, mExtra);
}
+ if( rc==SQLITE_OK ){
+ rc = whereLoopAddOr(&sSubBuild, mExtra);
+ }
assert( rc==SQLITE_OK || sCur.n==0 );
if( sCur.n==0 ){
sSum.n = 0;
@@ -116016,6 +121781,7 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){
pNew->prereq = sSum.a[i].prereq;
rc = whereLoopInsert(pBuilder, pNew);
}
+ WHERETRACE(0x200, ("End processing OR-clause %p\n", pTerm));
}
}
return rc;
@@ -116075,7 +121841,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
** strict. With GROUP BY and DISTINCT the only requirement is that
** equivalent rows appear immediately adjacent to one another. GROUP BY
** and DISTINCT do not require rows to appear in any particular order as long
-** as equivelent rows are grouped together. Thus for GROUP BY and DISTINCT
+** as equivalent rows are grouped together. Thus for GROUP BY and DISTINCT
** the pOrderBy terms can be matched in any order. With ORDER BY, the
** pOrderBy terms must be matched in strict left-to-right order.
*/
@@ -116204,7 +121970,7 @@ static i8 wherePathSatisfiesOrderBy(
/* Skip over == and IS NULL terms */
if( j<pLoop->u.btree.nEq
- && pLoop->u.btree.nSkip==0
+ && pLoop->nSkip==0
&& ((i = pLoop->aLTerm[j]->eOperator) & (WO_EQ|WO_ISNULL))!=0
){
if( i & WO_ISNULL ){
@@ -116259,7 +122025,7 @@ static i8 wherePathSatisfiesOrderBy(
isMatch = 1;
break;
}
- if( isMatch && (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ){
+ if( isMatch && (wctrlFlags & WHERE_GROUPBY)==0 ){
/* Make sure the sort order is compatible in an ORDER BY clause.
** Sort order is irrelevant for a GROUP BY clause. */
if( revSet ){
@@ -116481,10 +122247,10 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
/* Seed the search with a single WherePath containing zero WhereLoops.
**
- ** TUNING: Do not let the number of iterations go above 25. If the cost
- ** of computing an automatic index is not paid back within the first 25
+ ** TUNING: Do not let the number of iterations go above 28. If the cost
+ ** of computing an automatic index is not paid back within the first 28
** rows, then do not use the automatic index. */
- aFrom[0].nRow = MIN(pParse->nQueryLoop, 46); assert( 46==sqlite3LogEst(25) );
+ aFrom[0].nRow = MIN(pParse->nQueryLoop, 48); assert( 48==sqlite3LogEst(28) );
nFrom = 1;
assert( aFrom[0].isOrdered==0 );
if( nOrderBy ){
@@ -116658,7 +122424,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
}
#ifdef WHERETRACE_ENABLED /* >=2 */
- if( sqlite3WhereTrace>=2 ){
+ if( sqlite3WhereTrace & 0x02 ){
sqlite3DebugPrintf("---- after round %d ----\n", iLoop);
for(ii=0, pTo=aTo; ii<nTo; ii++, pTo++){
sqlite3DebugPrintf(" %s cost=%-3d nrow=%-3d order=%c",
@@ -116722,14 +122488,17 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
pWInfo->revMask = pFrom->revLoop;
}
if( (pWInfo->wctrlFlags & WHERE_SORTBYGROUP)
- && pWInfo->nOBSat==pWInfo->pOrderBy->nExpr
+ && pWInfo->nOBSat==pWInfo->pOrderBy->nExpr && nLoop>0
){
- Bitmask notUsed = 0;
+ Bitmask revMask = 0;
int nOrder = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy,
- pFrom, 0, nLoop-1, pFrom->aLoop[nLoop-1], ¬Used
+ pFrom, 0, nLoop-1, pFrom->aLoop[nLoop-1], &revMask
);
assert( pWInfo->sorted==0 );
- pWInfo->sorted = (nOrder==pWInfo->pOrderBy->nExpr);
+ if( nOrder==pWInfo->pOrderBy->nExpr ){
+ pWInfo->sorted = 1;
+ pWInfo->revMask = revMask;
+ }
}
}
@@ -116774,7 +122543,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
pWC = &pWInfo->sWC;
pLoop = pBuilder->pNew;
pLoop->wsFlags = 0;
- pLoop->u.btree.nSkip = 0;
+ pLoop->nSkip = 0;
pTerm = findTerm(pWC, iCur, -1, 0, WO_EQ, 0);
if( pTerm ){
pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_IPK|WHERE_ONEROW;
@@ -116786,7 +122555,6 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
}else{
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
assert( pLoop->aLTermSpace==pLoop->aLTerm );
- assert( ArraySize(pLoop->aLTermSpace)==4 );
if( !IsUniqueIndex(pIdx)
|| pIdx->pPartIdxWhere!=0
|| pIdx->nKeyCol>ArraySize(pLoop->aLTermSpace)
@@ -117082,23 +122850,16 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
/* Construct the WhereLoop objects */
WHERETRACE(0xffff,("*** Optimizer Start ***\n"));
+#if defined(WHERETRACE_ENABLED)
/* Display all terms of the WHERE clause */
-#if defined(WHERETRACE_ENABLED) && defined(SQLITE_ENABLE_TREE_EXPLAIN)
if( sqlite3WhereTrace & 0x100 ){
int i;
- Vdbe *v = pParse->pVdbe;
- sqlite3ExplainBegin(v);
for(i=0; i<sWLB.pWC->nTerm; i++){
- sqlite3ExplainPrintf(v, "#%-2d ", i);
- sqlite3ExplainPush(v);
- whereExplainTerm(v, &sWLB.pWC->a[i]);
- sqlite3ExplainPop(v);
- sqlite3ExplainNL(v);
+ whereTermPrint(&sWLB.pWC->a[i], i);
}
- sqlite3ExplainFinish(v);
- sqlite3DebugPrintf("%s", sqlite3VdbeExplanation(v));
}
#endif
+
if( nTabList!=1 || whereShortCut(&sWLB)==0 ){
rc = whereLoopAddAll(&sWLB);
if( rc ) goto whereBeginError;
@@ -117132,7 +122893,6 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
}
#ifdef WHERETRACE_ENABLED /* !=0 */
if( sqlite3WhereTrace ){
- int ii;
sqlite3DebugPrintf("---- Solution nRow=%d", pWInfo->nRowOut);
if( pWInfo->nOBSat>0 ){
sqlite3DebugPrintf(" ORDERBY=%d,0x%llx", pWInfo->nOBSat, pWInfo->revMask);
@@ -117287,6 +123047,12 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
if( op ){
sqlite3VdbeAddOp3(v, op, iIndexCur, pIx->tnum, iDb);
sqlite3VdbeSetP4KeyInfo(pParse, pIx);
+ if( (pLoop->wsFlags & WHERE_CONSTRAINT)!=0
+ && (pLoop->wsFlags & (WHERE_COLUMN_RANGE|WHERE_SKIPSCAN))==0
+ && (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0
+ ){
+ sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ); /* Hint to COMDB2 */
+ }
VdbeComment((v, "%s", pIx->zName));
}
}
@@ -117302,7 +123068,10 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
*/
notReady = ~(Bitmask)0;
for(ii=0; ii<nTabList; ii++){
+ int addrExplain;
+ int wsFlags;
pLevel = &pWInfo->a[ii];
+ wsFlags = pLevel->pWLoop->wsFlags;
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
if( (pLevel->pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 ){
constructAutomaticIndex(pParse, &pWInfo->sWC,
@@ -117310,10 +123079,15 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
if( db->mallocFailed ) goto whereBeginError;
}
#endif
- explainOneScan(pParse, pTabList, pLevel, ii, pLevel->iFrom, wctrlFlags);
+ addrExplain = explainOneScan(
+ pParse, pTabList, pLevel, ii, pLevel->iFrom, wctrlFlags
+ );
pLevel->addrBody = sqlite3VdbeCurrentAddr(v);
notReady = codeOneLoopStart(pWInfo, ii, notReady);
pWInfo->iContinue = pLevel->addrCont;
+ if( (wsFlags&WHERE_MULTI_OR)==0 && (wctrlFlags&WHERE_ONETABLE_ONLY)==0 ){
+ addScanStatus(v, pTabList, pLevel, addrExplain);
+ }
}
/* Done. */
@@ -117371,7 +123145,6 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
VdbeCoverageIf(v, pIn->eEndLoopOp==OP_NextIfOpen);
sqlite3VdbeJumpHere(v, pIn->addrInTop-1);
}
- sqlite3DbFree(db, pLevel->u.in.aInLoop);
}
sqlite3VdbeResolveLabel(v, pLevel->addrBrk);
if( pLevel->addrSkip ){
@@ -117380,6 +123153,16 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
sqlite3VdbeJumpHere(v, pLevel->addrSkip);
sqlite3VdbeJumpHere(v, pLevel->addrSkip-2);
}
+ if( pLevel->addrLikeRep ){
+ int op;
+ if( sqlite3VdbeGetOp(v, pLevel->addrLikeRep-1)->p1 ){
+ op = OP_DecrJumpZero;
+ }else{
+ op = OP_JumpZeroIncr;
+ }
+ sqlite3VdbeAddOp2(v, op, pLevel->iLikeRepCntr, pLevel->addrLikeRep);
+ VdbeCoverage(v);
+ }
if( pLevel->iLeftJoin ){
addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin); VdbeCoverage(v);
assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
@@ -117573,6 +123356,28 @@ struct TrigEvent { int a; IdList * b; };
struct AttachKey { int type; Token key; };
+ /*
+ ** For a compound SELECT statement, make sure p->pPrior->pNext==p for
+ ** all elements in the list. And make sure list length does not exceed
+ ** SQLITE_LIMIT_COMPOUND_SELECT.
+ */
+ static void parserDoubleLinkSelect(Parse *pParse, Select *p){
+ if( p->pPrior ){
+ Select *pNext = 0, *pLoop;
+ int mxSelect, cnt = 0;
+ for(pLoop=p; pLoop; pNext=pLoop, pLoop=pLoop->pPrior, cnt++){
+ pLoop->pNext = pNext;
+ pLoop->selFlags |= SF_Compound;
+ }
+ if( (p->selFlags & SF_MultiValue)==0 &&
+ (mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0 &&
+ cnt>mxSelect
+ ){
+ sqlite3ErrorMsg(pParse, "too many terms in compound SELECT");
+ }
+ }
+ }
+
/* This is a utility routine used to set the ExprSpan.zStart and
** ExprSpan.zEnd values of pOut so that the span covers the complete
** range of text beginning with pStart and going to the end of pEnd.
@@ -117625,7 +123430,7 @@ struct AttachKey { int type; Token key; };
** unary TK_ISNULL or TK_NOTNULL expression. */
static void binaryToUnaryIfNull(Parse *pParse, Expr *pY, Expr *pA, int op){
sqlite3 *db = pParse->db;
- if( db->mallocFailed==0 && pY->op==TK_NULL ){
+ if( pY && pA && pY->op==TK_NULL ){
pA->op = (u8)op;
sqlite3ExprDelete(db, pA->pRight);
pA->pRight = 0;
@@ -118852,9 +124657,9 @@ static void yyGrowStack(yyParser *p){
** A pointer to a parser. This pointer is used in subsequent calls
** to sqlite3Parser and sqlite3ParserFree.
*/
-SQLITE_PRIVATE void *sqlite3ParserAlloc(void *(*mallocProc)(size_t)){
+SQLITE_PRIVATE void *sqlite3ParserAlloc(void *(*mallocProc)(u64)){
yyParser *pParser;
- pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
+ pParser = (yyParser*)(*mallocProc)( (u64)sizeof(yyParser) );
if( pParser ){
pParser->yyidx = -1;
#ifdef YYTRACKMAXSTACKDEPTH
@@ -119884,29 +125689,15 @@ static void yy_reduce(
{
SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0};
sqlite3Select(pParse, yymsp[0].minor.yy3, &dest);
- sqlite3ExplainBegin(pParse->pVdbe);
- sqlite3ExplainSelect(pParse->pVdbe, yymsp[0].minor.yy3);
- sqlite3ExplainFinish(pParse->pVdbe);
sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy3);
}
break;
case 112: /* select ::= with selectnowith */
{
- Select *p = yymsp[0].minor.yy3, *pNext, *pLoop;
+ Select *p = yymsp[0].minor.yy3;
if( p ){
- int cnt = 0, mxSelect;
p->pWith = yymsp[-1].minor.yy59;
- if( p->pPrior ){
- pNext = 0;
- for(pLoop=p; pLoop; pNext=pLoop, pLoop=pLoop->pPrior, cnt++){
- pLoop->pNext = pNext;
- pLoop->selFlags |= SF_Compound;
- }
- mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT];
- if( mxSelect && cnt>mxSelect ){
- sqlite3ErrorMsg(pParse, "too many terms in compound SELECT");
- }
- }
+ parserDoubleLinkSelect(pParse, p);
}else{
sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy59);
}
@@ -119924,12 +125715,14 @@ static void yy_reduce(
SrcList *pFrom;
Token x;
x.n = 0;
+ parserDoubleLinkSelect(pParse, pRhs);
pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,0,0);
pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0,0);
}
if( pRhs ){
pRhs->op = (u8)yymsp[-1].minor.yy328;
pRhs->pPrior = yymsp[-2].minor.yy3;
+ pRhs->selFlags &= ~SF_MultiValue;
if( yymsp[-1].minor.yy328!=TK_ALL ) pParse->hasCompound = 1;
}else{
sqlite3SelectDelete(pParse->db, yymsp[-2].minor.yy3);
@@ -119943,6 +125736,30 @@ static void yy_reduce(
case 118: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt
orderby_opt limit_opt */
{
yygotominor.yy3 =
sqlite3SelectNew(pParse,yymsp[-6].minor.yy14,yymsp[-5].minor.yy65,yymsp[-4].minor.yy132,yymsp[-3].minor.yy14,yymsp[-2].minor.yy132,yymsp[-1].minor.yy14,yymsp[-7].minor.yy381,yymsp[0].minor.yy476.pLimit,yymsp[0].minor.yy476.pOffset);
+#if SELECTTRACE_ENABLED
+ /* Populate the Select.zSelName[] string that is used to help with
+ ** query planner debugging, to differentiate between multiple Select
+ ** objects in a complex query.
+ **
+ ** If the SELECT keyword is immediately followed by a C-style comment
+ ** then extract the first few alphanumeric characters from within that
+ ** comment to be the zSelName value. Otherwise, the label is #N where
+ ** is an integer that is incremented with each SELECT statement seen.
+ */
+ if( yygotominor.yy3!=0 ){
+ const char *z = yymsp[-8].minor.yy0.z+6;
+ int i;
+ sqlite3_snprintf(sizeof(yygotominor.yy3->zSelName), yygotominor.yy3->zSelName, "#%d",
+ ++pParse->nSelect);
+ while( z[0]==' ' ) z++;
+ if( z[0]=='/' && z[1]=='*' ){
+ z += 2;
+ while( z[0]==' ' ) z++;
+ for(i=0; sqlite3Isalnum(z[i]); i++){}
+ sqlite3_snprintf(sizeof(yygotominor.yy3->zSelName), yygotominor.yy3->zSelName, "%.*s", i, z);
+ }
+ }
+#endif /* SELECTRACE_ENABLED */
}
break;
case 120: /* values ::= VALUES LP nexprlist RP */
@@ -119952,13 +125769,16 @@ static void yy_reduce(
break;
case 121: /* values ::= values COMMA LP exprlist RP */
{
- Select *pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy14,0,0,0,0,0,SF_Values,0,0);
+ Select *pRight, *pLeft = yymsp[-4].minor.yy3;
+ pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy14,0,0,0,0,0,SF_Values|SF_MultiValue,0,0);
+ if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue;
if( pRight ){
pRight->op = TK_ALL;
- pRight->pPrior = yymsp[-4].minor.yy3;
+ pLeft = yymsp[-4].minor.yy3;
+ pRight->pPrior = pLeft;
yygotominor.yy3 = pRight;
}else{
- yygotominor.yy3 = yymsp[-4].minor.yy3;
+ yygotominor.yy3 = pLeft;
}
}
break;
@@ -120243,7 +126063,7 @@ static void yy_reduce(
break;
case 193: /* expr ::= expr COLLATE ID|STRING */
{
- yygotominor.yy346.pExpr = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy346.pExpr,
&yymsp[0].minor.yy0);
+ yygotominor.yy346.pExpr = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy346.pExpr,
&yymsp[0].minor.yy0, 1);
yygotominor.yy346.zStart = yymsp[-2].minor.yy346.zStart;
yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
@@ -120406,7 +126226,7 @@ static void yy_reduce(
yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy346.pExpr, 0, 0);
if( yygotominor.yy346.pExpr ){
yygotominor.yy346.pExpr->x.pList = yymsp[-1].minor.yy14;
- sqlite3ExprSetHeight(pParse, yygotominor.yy346.pExpr);
+ sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy346.pExpr);
}else{
sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14);
}
@@ -120421,8 +126241,8 @@ static void yy_reduce(
yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0);
if( yygotominor.yy346.pExpr ){
yygotominor.yy346.pExpr->x.pSelect = yymsp[-1].minor.yy3;
- ExprSetProperty(yygotominor.yy346.pExpr, EP_xIsSelect);
- sqlite3ExprSetHeight(pParse, yygotominor.yy346.pExpr);
+ ExprSetProperty(yygotominor.yy346.pExpr, EP_xIsSelect|EP_Subquery);
+ sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy346.pExpr);
}else{
sqlite3SelectDelete(pParse->db, yymsp[-1].minor.yy3);
}
@@ -120435,8 +126255,8 @@ static void yy_reduce(
yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy346.pExpr, 0, 0);
if( yygotominor.yy346.pExpr ){
yygotominor.yy346.pExpr->x.pSelect = yymsp[-1].minor.yy3;
- ExprSetProperty(yygotominor.yy346.pExpr, EP_xIsSelect);
- sqlite3ExprSetHeight(pParse, yygotominor.yy346.pExpr);
+ ExprSetProperty(yygotominor.yy346.pExpr, EP_xIsSelect|EP_Subquery);
+ sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy346.pExpr);
}else{
sqlite3SelectDelete(pParse->db, yymsp[-1].minor.yy3);
}
@@ -120451,8 +126271,8 @@ static void yy_reduce(
yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-3].minor.yy346.pExpr, 0, 0);
if( yygotominor.yy346.pExpr ){
yygotominor.yy346.pExpr->x.pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
- ExprSetProperty(yygotominor.yy346.pExpr, EP_xIsSelect);
- sqlite3ExprSetHeight(pParse, yygotominor.yy346.pExpr);
+ ExprSetProperty(yygotominor.yy346.pExpr, EP_xIsSelect|EP_Subquery);
+ sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy346.pExpr);
}else{
sqlite3SrcListDelete(pParse->db, pSrc);
}
@@ -120466,8 +126286,8 @@ static void yy_reduce(
Expr *p = yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0);
if( p ){
p->x.pSelect = yymsp[-1].minor.yy3;
- ExprSetProperty(p, EP_xIsSelect);
- sqlite3ExprSetHeight(pParse, p);
+ ExprSetProperty(p, EP_xIsSelect|EP_Subquery);
+ sqlite3ExprSetHeightAndFlags(pParse, p);
}else{
sqlite3SelectDelete(pParse->db, yymsp[-1].minor.yy3);
}
@@ -120480,7 +126300,7 @@ static void yy_reduce(
yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy132, 0, 0);
if( yygotominor.yy346.pExpr ){
yygotominor.yy346.pExpr->x.pList = yymsp[-1].minor.yy132 ?
sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy14,yymsp[-1].minor.yy132) : yymsp[-2].minor.yy14;
- sqlite3ExprSetHeight(pParse, yygotominor.yy346.pExpr);
+ sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy346.pExpr);
}else{
sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy14);
sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy132);
@@ -120523,7 +126343,7 @@ static void yy_reduce(
break;
case 244: /* idxlist ::= idxlist COMMA nm collate sortorder */
{
- Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &yymsp[-1].minor.yy0);
+ Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &yymsp[-1].minor.yy0, 1);
yygotominor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14, p);
sqlite3ExprListSetName(pParse,yygotominor.yy14,&yymsp[-2].minor.yy0,1);
sqlite3ExprListCheckLength(pParse, yygotominor.yy14, "index");
@@ -120532,7 +126352,7 @@ static void yy_reduce(
break;
case 245: /* idxlist ::= nm collate sortorder */
{
- Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &yymsp[-1].minor.yy0);
+ Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &yymsp[-1].minor.yy0, 1);
yygotominor.yy14 = sqlite3ExprListAppend(pParse,0, p);
sqlite3ExprListSetName(pParse, yygotominor.yy14, &yymsp[-2].minor.yy0, 1);
sqlite3ExprListCheckLength(pParse, yygotominor.yy14, "index");
@@ -121409,7 +127229,7 @@ SQLITE_PRIVATE int sqlite3KeywordCode(const unsigned char *z, int n){
** end result.
**
** Ticket #1066. the SQL standard does not allow '$' in the
-** middle of identfiers. But many SQL implementations do.
+** middle of identifiers. But many SQL implementations do.
** SQLite will allow '$' in identifiers for compatibility.
** But the feature is undocumented.
*/
@@ -121434,6 +127254,7 @@ SQLITE_PRIVATE const char sqlite3IsEbcdicIdChar[] = {
};
#define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40]))
#endif
+SQLITE_PRIVATE int sqlite3IsIdChar(u8 c){ return IdChar(c); }
/*
@@ -121721,7 +127542,7 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr
sqlite3 *db = pParse->db; /* The database connection */
int mxSqlLen; /* Max length of an SQL string */
-
+ assert( zSql!=0 );
mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
if( db->nVdbeActive==0 ){
db->u1.isInterrupted = 0;
@@ -121730,7 +127551,7 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr
pParse->zTail = zSql;
i = 0;
assert( pzErrMsg!=0 );
- pEngine = sqlite3ParserAlloc((void*(*)(size_t))sqlite3Malloc);
+ pEngine = sqlite3ParserAlloc(sqlite3Malloc);
if( pEngine==0 ){
db->mallocFailed = 1;
return SQLITE_NOMEM;
@@ -121761,10 +127582,8 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr
break;
}
case TK_ILLEGAL: {
- sqlite3DbFree(db, *pzErrMsg);
- *pzErrMsg = sqlite3MPrintf(db, "unrecognized token: \"%T\"",
+ sqlite3ErrorMsg(pParse, "unrecognized token: \"%T\"",
&pParse->sLastToken);
- nErr++;
goto abort_parse;
}
case TK_SEMI: {
@@ -121782,17 +127601,22 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr
}
}
abort_parse:
- if( zSql[i]==0 && nErr==0 && pParse->rc==SQLITE_OK ){
+ assert( nErr==0 );
+ if( zSql[i]==0 && pParse->rc==SQLITE_OK && db->mallocFailed==0 ){
if( lastTokenParsed!=TK_SEMI ){
sqlite3Parser(pEngine, TK_SEMI, pParse->sLastToken, pParse);
pParse->zTail = &zSql[i];
}
- sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse);
+ if( pParse->rc==SQLITE_OK && db->mallocFailed==0 ){
+ sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse);
+ }
}
#ifdef YYTRACKMAXSTACKDEPTH
+ sqlite3_mutex_enter(sqlite3MallocMutex());
sqlite3StatusSet(SQLITE_STATUS_PARSER_STACK,
sqlite3ParserStackPeak(pEngine)
);
+ sqlite3_mutex_leave(sqlite3MallocMutex());
#endif /* YYDEBUG */
sqlite3ParserFree(pEngine, sqlite3_free);
db->lookaside.bEnabled = enableLookaside;
@@ -121846,9 +127670,7 @@ abort_parse:
pParse->pZombieTab = p->pNextZombie;
sqlite3DeleteTable(db, p);
}
- if( nErr>0 && pParse->rc==SQLITE_OK ){
- pParse->rc = SQLITE_ERROR;
- }
+ assert( nErr==0 || pParse->rc!=SQLITE_OK );
return nErr;
}
@@ -121925,7 +127747,7 @@ SQLITE_PRIVATE const char sqlite3IsEbcdicIdChar[];
** a statement.
**
** (4) CREATE The keyword CREATE has been seen at the beginning of a
-** statement, possibly preceeded by EXPLAIN and/or followed by
+** statement, possibly preceded by EXPLAIN and/or followed by
** TEMP or TEMPORARY
**
** (5) TRIGGER We are in the middle of a trigger definition that must be
@@ -121935,7 +127757,7 @@ SQLITE_PRIVATE const char sqlite3IsEbcdicIdChar[];
** the end of a trigger definition.
**
** (7) END We've seen the ";END" of the ";END;" that occurs at the end
-** of a trigger difinition.
+** of a trigger definition.
**
** Transitions between states above are determined by tokens extracted
** from the input. The following tokens are significant:
@@ -121956,7 +127778,7 @@ SQLITE_PRIVATE const char sqlite3IsEbcdicIdChar[];
** to recognize the end of a trigger can be omitted. All we have to do
** is look for a semicolon that is not part of an string or comment.
*/
-SQLITE_API int sqlite3_complete(const char *zSql){
+SQLITE_API int SQLITE_STDCALL sqlite3_complete(const char *zSql){
u8 state = 0; /* Current state, using numbers defined in header comment */
u8 token; /* Value of the next token */
@@ -121978,7 +127800,7 @@ SQLITE_API int sqlite3_complete(const char *zSql){
};
#else
/* If triggers are not supported by this compile then the statement machine
- ** used to detect the end of a statement is much simplier
+ ** used to detect the end of a statement is much simpler
*/
static const u8 trans[3][3] = {
/* Token: */
@@ -121989,6 +127811,13 @@ SQLITE_API int sqlite3_complete(const char *zSql){
};
#endif /* SQLITE_OMIT_TRIGGER */
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( zSql==0 ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
+
while( *zSql ){
switch( *zSql ){
case ';': { /* A semicolon */
@@ -122114,10 +127943,10 @@ SQLITE_API int sqlite3_complete(const char *zSql){
** above, except that the parameter is required to be UTF-16 encoded, not
** UTF-8.
*/
-SQLITE_API int sqlite3_complete16(const void *zSql){
+SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *zSql){
sqlite3_value *pVal;
char const *zSql8;
- int rc = SQLITE_NOMEM;
+ int rc;
#ifndef SQLITE_OMIT_AUTOINIT
rc = sqlite3_initialize();
@@ -122264,24 +128093,36 @@ SQLITE_API const char sqlite3_version[] = SQLITE_VERSION;
/* IMPLEMENTATION-OF: R-53536-42575 The sqlite3_libversion() function returns
** a pointer to the to the sqlite3_version[] string constant.
*/
-SQLITE_API const char *sqlite3_libversion(void){ return sqlite3_version; }
+SQLITE_API const char *SQLITE_STDCALL sqlite3_libversion(void){ return sqlite3_version; }
/* IMPLEMENTATION-OF: R-63124-39300 The sqlite3_sourceid() function returns a
** pointer to a string constant whose value is the same as the
** SQLITE_SOURCE_ID C preprocessor macro.
*/
-SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
+SQLITE_API const char *SQLITE_STDCALL sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
/* IMPLEMENTATION-OF: R-35210-63508 The sqlite3_libversion_number() function
** returns an integer equal to SQLITE_VERSION_NUMBER.
*/
-SQLITE_API int sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; }
+SQLITE_API int SQLITE_STDCALL sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; }
/* IMPLEMENTATION-OF: R-20790-14025 The sqlite3_threadsafe() function returns
** zero if and only if SQLite was compiled with mutexing code omitted due to
** the SQLITE_THREADSAFE compile-time option being set to 0.
*/
-SQLITE_API int sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; }
+SQLITE_API int SQLITE_STDCALL sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; }
+
+/*
+** When compiling the test fixture or with debugging enabled (on Win32),
+** this variable being set to non-zero will cause OSTRACE macros to emit
+** extra diagnostic information.
+*/
+#ifdef SQLITE_HAVE_OS_TRACE
+# ifndef SQLITE_DEBUG_OS_TRACE
+# define SQLITE_DEBUG_OS_TRACE 0
+# endif
+ int sqlite3OSTrace = SQLITE_DEBUG_OS_TRACE;
+#endif
#if !defined(SQLITE_OMIT_TRACE) && defined(SQLITE_ENABLE_IOTRACE)
/*
@@ -122290,7 +128131,7 @@ SQLITE_API int sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; }
** I/O active are written using this function. These messages
** are intended for debugging activity only.
*/
-SQLITE_PRIVATE void (*sqlite3IoTrace)(const char*, ...) = 0;
+SQLITE_API void (SQLITE_CDECL *sqlite3IoTrace)(const char*, ...) = 0;
#endif
/*
@@ -122342,7 +128183,7 @@ SQLITE_API char *sqlite3_data_directory = 0;
** * Recursive calls to this routine from thread X return immediately
** without blocking.
*/
-SQLITE_API int sqlite3_initialize(void){
+SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void){
MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */
int rc; /* Result code */
#ifdef SQLITE_EXTRA_INIT
@@ -122356,6 +128197,11 @@ SQLITE_API int sqlite3_initialize(void){
}
#endif
+ /* If the following assert() fails on some obscure processor/compiler
+ ** combination, the work-around is to set the correct pointer
+ ** size at compile-time using -DSQLITE_PTRSIZE=n compile-time option */
+ assert( SQLITE_PTRSIZE==sizeof(char*) );
+
/* If SQLite is already completely initialized, then this call
** to sqlite3_initialize() should be a no-op. But the initialization
** must be complete. So isInit must not be set until the very end
@@ -122498,7 +128344,14 @@ SQLITE_API int sqlite3_initialize(void){
** on when SQLite is already shut down. If SQLite is already shut down
** when this routine is invoked, then this routine is a harmless no-op.
*/
-SQLITE_API int sqlite3_shutdown(void){
+SQLITE_API int SQLITE_STDCALL sqlite3_shutdown(void){
+#ifdef SQLITE_OMIT_WSD
+ int rc = sqlite3_wsd_init(4096, 24);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+#endif
+
if( sqlite3GlobalConfig.isInit ){
#ifdef SQLITE_EXTRA_SHUTDOWN
void SQLITE_EXTRA_SHUTDOWN(void);
@@ -122545,7 +128398,7 @@ SQLITE_API int sqlite3_shutdown(void){
** threadsafe. Failure to heed these warnings can lead to unpredictable
** behavior.
*/
-SQLITE_API int sqlite3_config(int op, ...){
+SQLITE_API int SQLITE_CDECL sqlite3_config(int op, ...){
va_list ap;
int rc = SQLITE_OK;
@@ -122557,33 +128410,43 @@ SQLITE_API int sqlite3_config(int op, ...){
switch( op ){
/* Mutex configuration options are only available in a threadsafe
- ** compile.
+ ** compile.
*/
-#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0
+#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-54466-46756 */
case SQLITE_CONFIG_SINGLETHREAD: {
- /* Disable all mutexing */
- sqlite3GlobalConfig.bCoreMutex = 0;
- sqlite3GlobalConfig.bFullMutex = 0;
+ /* EVIDENCE-OF: R-02748-19096 This option sets the threading mode to
+ ** Single-thread. */
+ sqlite3GlobalConfig.bCoreMutex = 0; /* Disable mutex on core */
+ sqlite3GlobalConfig.bFullMutex = 0; /* Disable mutex on connections */
break;
}
+#endif
+#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-20520-54086 */
case SQLITE_CONFIG_MULTITHREAD: {
- /* Disable mutexing of database connections */
- /* Enable mutexing of core data structures */
- sqlite3GlobalConfig.bCoreMutex = 1;
- sqlite3GlobalConfig.bFullMutex = 0;
+ /* EVIDENCE-OF: R-14374-42468 This option sets the threading mode to
+ ** Multi-thread. */
+ sqlite3GlobalConfig.bCoreMutex = 1; /* Enable mutex on core */
+ sqlite3GlobalConfig.bFullMutex = 0; /* Disable mutex on connections */
break;
}
+#endif
+#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-59593-21810 */
case SQLITE_CONFIG_SERIALIZED: {
- /* Enable all mutexing */
- sqlite3GlobalConfig.bCoreMutex = 1;
- sqlite3GlobalConfig.bFullMutex = 1;
+ /* EVIDENCE-OF: R-41220-51800 This option sets the threading mode to
+ ** Serialized. */
+ sqlite3GlobalConfig.bCoreMutex = 1; /* Enable mutex on core */
+ sqlite3GlobalConfig.bFullMutex = 1; /* Enable mutex on connections */
break;
}
+#endif
+#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-63666-48755 */
case SQLITE_CONFIG_MUTEX: {
/* Specify an alternative mutex implementation */
sqlite3GlobalConfig.mutex = *va_arg(ap, sqlite3_mutex_methods*);
break;
}
+#endif
+#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-14450-37597 */
case SQLITE_CONFIG_GETMUTEX: {
/* Retrieve the current mutex implementation */
*va_arg(ap, sqlite3_mutex_methods*) = sqlite3GlobalConfig.mutex;
@@ -122591,37 +128454,61 @@ SQLITE_API int sqlite3_config(int op, ...){
}
#endif
-
case SQLITE_CONFIG_MALLOC: {
- /* Specify an alternative malloc implementation */
+ /* EVIDENCE-OF: R-55594-21030 The SQLITE_CONFIG_MALLOC option takes a
+ ** single argument which is a pointer to an instance of the
+ ** sqlite3_mem_methods structure. The argument specifies alternative
+ ** low-level memory allocation routines to be used in place of the memory
+ ** allocation routines built into SQLite. */
sqlite3GlobalConfig.m = *va_arg(ap, sqlite3_mem_methods*);
break;
}
case SQLITE_CONFIG_GETMALLOC: {
- /* Retrieve the current malloc() implementation */
+ /* EVIDENCE-OF: R-51213-46414 The SQLITE_CONFIG_GETMALLOC option takes a
+ ** single argument which is a pointer to an instance of the
+ ** sqlite3_mem_methods structure. The sqlite3_mem_methods structure is
+ ** filled with the currently defined memory allocation routines. */
if( sqlite3GlobalConfig.m.xMalloc==0 ) sqlite3MemSetDefault();
*va_arg(ap, sqlite3_mem_methods*) = sqlite3GlobalConfig.m;
break;
}
case SQLITE_CONFIG_MEMSTATUS: {
- /* Enable or disable the malloc status collection */
+ /* EVIDENCE-OF: R-61275-35157 The SQLITE_CONFIG_MEMSTATUS option takes
+ ** single argument of type int, interpreted as a boolean, which enables
+ ** or disables the collection of memory allocation statistics. */
sqlite3GlobalConfig.bMemstat = va_arg(ap, int);
break;
}
case SQLITE_CONFIG_SCRATCH: {
- /* Designate a buffer for scratch memory space */
+ /* EVIDENCE-OF: R-08404-60887 There are three arguments to
+ ** SQLITE_CONFIG_SCRATCH: A pointer an 8-byte aligned memory buffer from
+ ** which the scratch allocations will be drawn, the size of each scratch
+ ** allocation (sz), and the maximum number of scratch allocations (N). */
sqlite3GlobalConfig.pScratch = va_arg(ap, void*);
sqlite3GlobalConfig.szScratch = va_arg(ap, int);
sqlite3GlobalConfig.nScratch = va_arg(ap, int);
break;
}
case SQLITE_CONFIG_PAGECACHE: {
- /* Designate a buffer for page cache memory space */
+ /* EVIDENCE-OF: R-31408-40510 There are three arguments to
+ ** SQLITE_CONFIG_PAGECACHE: A pointer to 8-byte aligned memory, the size
+ ** of each page buffer (sz), and the number of pages (N). */
sqlite3GlobalConfig.pPage = va_arg(ap, void*);
sqlite3GlobalConfig.szPage = va_arg(ap, int);
sqlite3GlobalConfig.nPage = va_arg(ap, int);
break;
}
+ case SQLITE_CONFIG_PCACHE_HDRSZ: {
+ /* EVIDENCE-OF: R-39100-27317 The SQLITE_CONFIG_PCACHE_HDRSZ option takes
+ ** a single parameter which is a pointer to an integer and writes into
+ ** that integer the number of extra bytes per page required for each page
+ ** in SQLITE_CONFIG_PAGECACHE. */
+ *va_arg(ap, int*) =
+ sqlite3HeaderSizeBtree() +
+ sqlite3HeaderSizePcache() +
+ sqlite3HeaderSizePcache1();
+ break;
+ }
case SQLITE_CONFIG_PCACHE: {
/* no-op */
@@ -122634,11 +128521,18 @@ SQLITE_API int sqlite3_config(int op, ...){
}
case SQLITE_CONFIG_PCACHE2: {
- /* Specify an alternative page cache implementation */
+ /* EVIDENCE-OF: R-63325-48378 The SQLITE_CONFIG_PCACHE2 option takes a
+ ** single argument which is a pointer to an sqlite3_pcache_methods2
+ ** object. This object specifies the interface to a custom page cache
+ ** implementation. */
sqlite3GlobalConfig.pcache2 = *va_arg(ap, sqlite3_pcache_methods2*);
break;
}
case SQLITE_CONFIG_GETPCACHE2: {
+ /* EVIDENCE-OF: R-22035-46182 The SQLITE_CONFIG_GETPCACHE2 option takes a
+ ** single argument which is a pointer to an sqlite3_pcache_methods2
+ ** object. SQLite copies of the current page cache implementation into
+ ** that object. */
if( sqlite3GlobalConfig.pcache2.xInit==0 ){
sqlite3PCacheSetDefault();
}
@@ -122646,9 +128540,15 @@ SQLITE_API int sqlite3_config(int op, ...){
break;
}
+/* EVIDENCE-OF: R-06626-12911 The SQLITE_CONFIG_HEAP option is only
+** available if SQLite is compiled with either SQLITE_ENABLE_MEMSYS3 or
+** SQLITE_ENABLE_MEMSYS5 and returns SQLITE_ERROR if invoked otherwise. */
#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
case SQLITE_CONFIG_HEAP: {
- /* Designate a buffer for heap memory space */
+ /* EVIDENCE-OF: R-19854-42126 There are three arguments to
+ ** SQLITE_CONFIG_HEAP: An 8-byte aligned pointer to the memory, the
+ ** number of bytes in the memory buffer, and the minimum allocation size.
+ */
sqlite3GlobalConfig.pHeap = va_arg(ap, void*);
sqlite3GlobalConfig.nHeap = va_arg(ap, int);
sqlite3GlobalConfig.mnReq = va_arg(ap, int);
@@ -122661,17 +128561,19 @@ SQLITE_API int sqlite3_config(int op, ...){
}
if( sqlite3GlobalConfig.pHeap==0 ){
- /* If the heap pointer is NULL, then restore the malloc implementation
- ** back to NULL pointers too. This will cause the malloc to go
- ** back to its default implementation when sqlite3_initialize() is
- ** run.
+ /* EVIDENCE-OF: R-49920-60189 If the first pointer (the memory pointer)
+ ** is NULL, then SQLite reverts to using its default memory allocator
+ ** (the system malloc() implementation), undoing any prior invocation of
+ ** SQLITE_CONFIG_MALLOC.
+ **
+ ** Setting sqlite3GlobalConfig.m to all zeros will cause malloc to
+ ** revert to its default implementation when sqlite3_initialize() is run
*/
memset(&sqlite3GlobalConfig.m, 0, sizeof(sqlite3GlobalConfig.m));
}else{
- /* The heap pointer is not NULL, then install one of the
- ** mem5.c/mem3.c methods. The enclosing #if guarantees at
- ** least one of these methods is currently enabled.
- */
+ /* EVIDENCE-OF: R-61006-08918 If the memory pointer is not NULL then the
+ ** alternative memory allocator is engaged to handle all of SQLites
+ ** memory allocation needs. */
#ifdef SQLITE_ENABLE_MEMSYS3
sqlite3GlobalConfig.m = *sqlite3MemGetMemsys3();
#endif
@@ -122704,12 +128606,25 @@ SQLITE_API int sqlite3_config(int op, ...){
break;
}
+ /* EVIDENCE-OF: R-55548-33817 The compile-time setting for URI filenames
+ ** can be changed at start-time using the
+ ** sqlite3_config(SQLITE_CONFIG_URI,1) or
+ ** sqlite3_config(SQLITE_CONFIG_URI,0) configuration calls.
+ */
case SQLITE_CONFIG_URI: {
+ /* EVIDENCE-OF: R-25451-61125 The SQLITE_CONFIG_URI option takes a single
+ ** argument of type int. If non-zero, then URI handling is globally
+ ** enabled. If the parameter is zero, then URI handling is globally
+ ** disabled. */
sqlite3GlobalConfig.bOpenUri = va_arg(ap, int);
break;
}
case SQLITE_CONFIG_COVERING_INDEX_SCAN: {
+ /* EVIDENCE-OF: R-36592-02772 The SQLITE_CONFIG_COVERING_INDEX_SCAN
+ ** option takes a single integer argument which is interpreted as a
+ ** boolean in order to enable or disable the use of covering indices for
+ ** full table scans in the query optimizer. */
sqlite3GlobalConfig.bUseCis = va_arg(ap, int);
break;
}
@@ -122724,25 +128639,45 @@ SQLITE_API int sqlite3_config(int op, ...){
#endif
case SQLITE_CONFIG_MMAP_SIZE: {
+ /* EVIDENCE-OF: R-58063-38258 SQLITE_CONFIG_MMAP_SIZE takes two 64-bit
+ ** integer (sqlite3_int64) values that are the default mmap size limit
+ ** (the default setting for PRAGMA mmap_size) and the maximum allowed
+ ** mmap size limit. */
sqlite3_int64 szMmap = va_arg(ap, sqlite3_int64);
sqlite3_int64 mxMmap = va_arg(ap, sqlite3_int64);
+ /* EVIDENCE-OF: R-53367-43190 If either argument to this option is
+ ** negative, then that argument is changed to its compile-time default.
+ **
+ ** EVIDENCE-OF: R-34993-45031 The maximum allowed mmap size will be
+ ** silently truncated if necessary so that it does not exceed the
+ ** compile-time maximum mmap size set by the SQLITE_MAX_MMAP_SIZE
+ ** compile-time option.
+ */
if( mxMmap<0 || mxMmap>SQLITE_MAX_MMAP_SIZE ){
mxMmap = SQLITE_MAX_MMAP_SIZE;
}
- sqlite3GlobalConfig.mxMmap = mxMmap;
if( szMmap<0 ) szMmap = SQLITE_DEFAULT_MMAP_SIZE;
if( szMmap>mxMmap) szMmap = mxMmap;
+ sqlite3GlobalConfig.mxMmap = mxMmap;
sqlite3GlobalConfig.szMmap = szMmap;
break;
}
-#if SQLITE_OS_WIN && defined(SQLITE_WIN32_MALLOC)
+#if SQLITE_OS_WIN && defined(SQLITE_WIN32_MALLOC) /* IMP: R-04780-55815 */
case SQLITE_CONFIG_WIN32_HEAPSIZE: {
+ /* EVIDENCE-OF: R-34926-03360 SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit
+ ** unsigned integer value that specifies the maximum size of the created
+ ** heap. */
sqlite3GlobalConfig.nHeap = va_arg(ap, int);
break;
}
#endif
+ case SQLITE_CONFIG_PMASZ: {
+ sqlite3GlobalConfig.szPma = va_arg(ap, unsigned int);
+ break;
+ }
+
default: {
rc = SQLITE_ERROR;
break;
@@ -122820,7 +128755,13 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
/*
** Return the mutex associated with a database connection.
*/
-SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3 *db){
+SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3 *db){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
return db->mutex;
}
@@ -122828,8 +128769,12 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3 *db){
** Free up as much memory as we can from the given database
** connection.
*/
-SQLITE_API int sqlite3_db_release_memory(sqlite3 *db){
+SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3 *db){
int i;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
sqlite3_mutex_enter(db->mutex);
sqlite3BtreeEnterAll(db);
for(i=0; i<db->nDb; i++){
@@ -122847,7 +128792,7 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3 *db){
/*
** Configuration settings for an individual database connection
*/
-SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){
+SQLITE_API int SQLITE_CDECL sqlite3_db_config(sqlite3 *db, int op, ...){
va_list ap;
int rc;
va_start(ap, op);
@@ -122919,13 +128864,20 @@ static int binCollFunc(
){
int rc, n;
n = nKey1<nKey2 ? nKey1 : nKey2;
+ /* EVIDENCE-OF: R-65033-28449 The built-in BINARY collation compares
+ ** strings byte by byte using the memcmp() function from the standard C
+ ** library. */
rc = memcmp(pKey1, pKey2, n);
if( rc==0 ){
if( padFlag
&& allSpaces(((char*)pKey1)+n, nKey1-n)
&& allSpaces(((char*)pKey2)+n, nKey2-n)
){
- /* Leave rc unchanged at 0 */
+ /* EVIDENCE-OF: R-31624-24737 RTRIM is like BINARY except that extra
+ ** spaces at the end of either string do not change the result. In other
+ ** words, strings will compare equal to one another as long as they
+ ** differ only in the number of spaces at the end.
+ */
}else{
rc = nKey1 - nKey2;
}
@@ -122959,21 +128911,39 @@ static int nocaseCollatingFunc(
/*
** Return the ROWID of the most recent insert
*/
-SQLITE_API sqlite_int64 sqlite3_last_insert_rowid(sqlite3 *db){
+SQLITE_API sqlite_int64 SQLITE_STDCALL sqlite3_last_insert_rowid(sqlite3 *db){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
return db->lastRowid;
}
/*
** Return the number of changes in the most recent call to sqlite3_exec().
*/
-SQLITE_API int sqlite3_changes(sqlite3 *db){
+SQLITE_API int SQLITE_STDCALL sqlite3_changes(sqlite3 *db){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
return db->nChange;
}
/*
** Return the number of changes since the database handle was opened.
*/
-SQLITE_API int sqlite3_total_changes(sqlite3 *db){
+SQLITE_API int SQLITE_STDCALL sqlite3_total_changes(sqlite3 *db){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
return db->nTotalChange;
}
@@ -123080,7 +129050,7 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){
** SQLITE_BUSY if the connection can not be closed immediately.
*/
if( !forceZombie && connectionIsBusy(db) ){
- sqlite3Error(db, SQLITE_BUSY, "unable to close due to unfinalized "
+ sqlite3ErrorWithMsg(db, SQLITE_BUSY, "unable to close due to unfinalized "
"statements or unfinished backups");
sqlite3_mutex_leave(db->mutex);
return SQLITE_BUSY;
@@ -123109,8 +129079,8 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){
** unclosed resources, and arranges for deallocation when the last
** prepare statement or sqlite3_backup closes.
*/
-SQLITE_API int sqlite3_close(sqlite3 *db){ return sqlite3Close(db,0); }
-SQLITE_API int sqlite3_close_v2(sqlite3 *db){ return sqlite3Close(db,1); }
+SQLITE_API int SQLITE_STDCALL sqlite3_close(sqlite3 *db){ return sqlite3Close(db,0); }
+SQLITE_API int SQLITE_STDCALL sqlite3_close_v2(sqlite3 *db){ return sqlite3Close(db,1); }
/*
@@ -123210,9 +129180,13 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
sqlite3HashClear(&db->aModule);
#endif
- sqlite3Error(db, SQLITE_OK, 0); /* Deallocates any cached error strings. */
+ sqlite3Error(db, SQLITE_OK); /* Deallocates any cached error strings. */
sqlite3ValueFree(db->pErr);
sqlite3CloseExtensions(db);
+#if SQLITE_USER_AUTHENTICATION
+ sqlite3_free(db->auth.zAuthUser);
+ sqlite3_free(db->auth.zAuthPW);
+#endif
db->magic = SQLITE_MAGIC_ERROR;
@@ -123235,13 +129209,15 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
/*
** Rollback all database files. If tripCode is not SQLITE_OK, then
-** any open cursors are invalidated ("tripped" - as in "tripping a circuit
+** any write cursors are invalidated ("tripped" - as in "tripping a circuit
** breaker") and made to return tripCode if there are any further
-** attempts to use that cursor.
+** attempts to use that cursor. Read cursors remain open and valid
+** but are "saved" in case the table pages are moved around.
*/
SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){
int i;
int inTrans = 0;
+ int schemaChange;
assert( sqlite3_mutex_held(db->mutex) );
sqlite3BeginBenignMalloc();
@@ -123252,6 +129228,7 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){
** the database rollback and schema reset, which can cause false
** corruption reports in some cases. */
sqlite3BtreeEnterAll(db);
+ schemaChange = (db->flags & SQLITE_InternChanges)!=0 && db->init.busy==0;
for(i=0; i<db->nDb; i++){
Btree *p = db->aDb[i].pBt;
@@ -123259,7 +129236,7 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){
if( sqlite3BtreeIsInTrans(p) ){
inTrans = 1;
}
- sqlite3BtreeRollback(p, tripCode);
+ sqlite3BtreeRollback(p, tripCode, !schemaChange);
}
}
sqlite3VtabRollback(db);
@@ -123286,7 +129263,7 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){
** Return a static string containing the name corresponding to the error code
** specified in the argument.
*/
-#if (defined(SQLITE_DEBUG) && SQLITE_OS_WIN) || defined(SQLITE_TEST)
+#if defined(SQLITE_NEED_ERR_NAME)
SQLITE_PRIVATE const char *sqlite3ErrName(int rc){
const char *zName = 0;
int i, origRc = rc;
@@ -123452,7 +129429,7 @@ static int sqliteDefaultBusyCallback(
void *ptr, /* Database connection */
int count /* Number of times table has been busy */
){
-#if SQLITE_OS_WIN || (defined(HAVE_USLEEP) && HAVE_USLEEP)
+#if SQLITE_OS_WIN || HAVE_USLEEP
static const u8 delays[] =
{ 1, 2, 5, 10, 15, 20, 25, 25, 25, 50, 50, 100 };
static const u8 totals[] =
@@ -123510,11 +129487,14 @@ SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler *p){
** This routine sets the busy callback for an Sqlite database to the
** given callback function with the given argument.
*/
-SQLITE_API int sqlite3_busy_handler(
+SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler(
sqlite3 *db,
int (*xBusy)(void*,int),
void *pArg
){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
sqlite3_mutex_enter(db->mutex);
db->busyHandler.xFunc = xBusy;
db->busyHandler.pArg = pArg;
@@ -123530,12 +129510,18 @@ SQLITE_API int sqlite3_busy_handler(
** given callback function with the given argument. The progress callback will
** be invoked every nOps opcodes.
*/
-SQLITE_API void sqlite3_progress_handler(
+SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(
sqlite3 *db,
int nOps,
int (*xProgress)(void*),
void *pArg
){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return;
+ }
+#endif
sqlite3_mutex_enter(db->mutex);
if( nOps>0 ){
db->xProgress = xProgress;
@@ -123555,7 +129541,10 @@ SQLITE_API void sqlite3_progress_handler(
** This routine installs a default busy handler that waits for the
** specified number of milliseconds before returning 0.
*/
-SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms){
+SQLITE_API int SQLITE_STDCALL sqlite3_busy_timeout(sqlite3 *db, int ms){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
if( ms>0 ){
sqlite3_busy_handler(db, sqliteDefaultBusyCallback, (void*)db);
db->busyTimeout = ms;
@@ -123568,7 +129557,13 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms){
/*
** Cause any pending operation to stop at its earliest opportunity.
*/
-SQLITE_API void sqlite3_interrupt(sqlite3 *db){
+SQLITE_API void SQLITE_STDCALL sqlite3_interrupt(sqlite3 *db){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return;
+ }
+#endif
db->u1.isInterrupted = 1;
}
@@ -123643,7 +129638,7 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
p = sqlite3FindFunction(db, zFunctionName, nName, nArg, (u8)enc, 0);
if( p && (p->funcFlags & SQLITE_FUNC_ENCMASK)==enc && p->nArg==nArg ){
if( db->nVdbeActive ){
- sqlite3Error(db, SQLITE_BUSY,
+ sqlite3ErrorWithMsg(db, SQLITE_BUSY,
"unable to delete/modify user-function due to active statements");
assert( !db->mallocFailed );
return SQLITE_BUSY;
@@ -123679,7 +129674,7 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
/*
** Create new user functions.
*/
-SQLITE_API int sqlite3_create_function(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_function(
sqlite3 *db,
const char *zFunc,
int nArg,
@@ -123693,7 +129688,7 @@ SQLITE_API int sqlite3_create_function(
xFinal, 0);
}
-SQLITE_API int sqlite3_create_function_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2(
sqlite3 *db,
const char *zFunc,
int nArg,
@@ -123706,6 +129701,12 @@ SQLITE_API int sqlite3_create_function_v2(
){
int rc = SQLITE_ERROR;
FuncDestructor *pArg = 0;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ return SQLITE_MISUSE_BKPT;
+ }
+#endif
sqlite3_mutex_enter(db->mutex);
if( xDestroy ){
pArg = (FuncDestructor *)sqlite3DbMallocZero(db, sizeof(FuncDestructor));
@@ -123730,7 +129731,7 @@ SQLITE_API int sqlite3_create_function_v2(
}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API int sqlite3_create_function16(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_function16(
sqlite3 *db,
const void *zFunctionName,
int nArg,
@@ -123742,6 +129743,10 @@ SQLITE_API int sqlite3_create_function16(
){
int rc;
char *zFunc8;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) || zFunctionName==0 ) return SQLITE_MISUSE_BKPT;
+#endif
sqlite3_mutex_enter(db->mutex);
assert( !db->mallocFailed );
zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1, SQLITE_UTF16NATIVE);
@@ -123766,13 +129771,19 @@ SQLITE_API int sqlite3_create_function16(
** A global function must exist in order for name resolution to work
** properly.
*/
-SQLITE_API int sqlite3_overload_function(
+SQLITE_API int SQLITE_STDCALL sqlite3_overload_function(
sqlite3 *db,
const char *zName,
int nArg
){
int nName = sqlite3Strlen30(zName);
int rc = SQLITE_OK;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) || zName==0 || nArg<-2 ){
+ return SQLITE_MISUSE_BKPT;
+ }
+#endif
sqlite3_mutex_enter(db->mutex);
if( sqlite3FindFunction(db, zName, nName, nArg, SQLITE_UTF8, 0)==0 ){
rc = sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8,
@@ -123792,8 +129803,15 @@ SQLITE_API int sqlite3_overload_function(
** trace is a pointer to a function that is invoked at the start of each
** SQL statement.
*/
-SQLITE_API void *sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){
+SQLITE_API void *SQLITE_STDCALL sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){
void *pOld;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
sqlite3_mutex_enter(db->mutex);
pOld = db->pTraceArg;
db->xTrace = xTrace;
@@ -123809,12 +129827,19 @@ SQLITE_API void *sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), v
** profile is a pointer to a function that is invoked at the conclusion of
** each SQL statement that is run.
*/
-SQLITE_API void *sqlite3_profile(
+SQLITE_API void *SQLITE_STDCALL sqlite3_profile(
sqlite3 *db,
void (*xProfile)(void*,const char*,sqlite_uint64),
void *pArg
){
void *pOld;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
sqlite3_mutex_enter(db->mutex);
pOld = db->pProfileArg;
db->xProfile = xProfile;
@@ -123829,12 +129854,19 @@ SQLITE_API void *sqlite3_profile(
** If the invoked function returns non-zero, then the commit becomes a
** rollback.
*/
-SQLITE_API void *sqlite3_commit_hook(
+SQLITE_API void *SQLITE_STDCALL sqlite3_commit_hook(
sqlite3 *db, /* Attach the hook to this database */
int (*xCallback)(void*), /* Function to invoke on each commit */
void *pArg /* Argument to the function */
){
void *pOld;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
sqlite3_mutex_enter(db->mutex);
pOld = db->pCommitArg;
db->xCommitCallback = xCallback;
@@ -123847,12 +129879,19 @@ SQLITE_API void *sqlite3_commit_hook(
** Register a callback to be invoked each time a row is updated,
** inserted or deleted using this database connection.
*/
-SQLITE_API void *sqlite3_update_hook(
+SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook(
sqlite3 *db, /* Attach the hook to this database */
void (*xCallback)(void*,int,char const *,char const *,sqlite_int64),
void *pArg /* Argument to the function */
){
void *pRet;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
sqlite3_mutex_enter(db->mutex);
pRet = db->pUpdateArg;
db->xUpdateCallback = xCallback;
@@ -123865,12 +129904,19 @@ SQLITE_API void *sqlite3_update_hook(
** Register a callback to be invoked each time a transaction is rolled
** back by this database connection.
*/
-SQLITE_API void *sqlite3_rollback_hook(
+SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(
sqlite3 *db, /* Attach the hook to this database */
void (*xCallback)(void*), /* Callback function */
void *pArg /* Argument to the function */
){
void *pRet;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
sqlite3_mutex_enter(db->mutex);
pRet = db->pRollbackArg;
db->xRollbackCallback = xCallback;
@@ -123912,11 +129958,14 @@ SQLITE_PRIVATE int sqlite3WalDefaultHook(
** using sqlite3_wal_hook() disables the automatic checkpoint mechanism
** configured by this function.
*/
-SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame){
+SQLITE_API int SQLITE_STDCALL sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame){
#ifdef SQLITE_OMIT_WAL
UNUSED_PARAMETER(db);
UNUSED_PARAMETER(nFrame);
#else
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
if( nFrame>0 ){
sqlite3_wal_hook(db, sqlite3WalDefaultHook, SQLITE_INT_TO_PTR(nFrame));
}else{
@@ -123930,13 +129979,19 @@ SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame){
** Register a callback to be invoked each time a transaction is written
** into the write-ahead-log by this database connection.
*/
-SQLITE_API void *sqlite3_wal_hook(
+SQLITE_API void *SQLITE_STDCALL sqlite3_wal_hook(
sqlite3 *db, /* Attach the hook to this db handle */
int(*xCallback)(void *, sqlite3*, const char*, int),
void *pArg /* First argument passed to xCallback() */
){
#ifndef SQLITE_OMIT_WAL
void *pRet;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
sqlite3_mutex_enter(db->mutex);
pRet = db->pWalArg;
db->xWalCallback = xCallback;
@@ -123951,7 +130006,7 @@ SQLITE_API void *sqlite3_wal_hook(
/*
** Checkpoint database zDb.
*/
-SQLITE_API int sqlite3_wal_checkpoint_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2(
sqlite3 *db, /* Database handle */
const char *zDb, /* Name of attached database (or NULL) */
int eMode, /* SQLITE_CHECKPOINT_* value */
@@ -123964,14 +130019,21 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
int rc; /* Return code */
int iDb = SQLITE_MAX_ATTACHED; /* sqlite3.aDb[] index of db to checkpoint */
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
+
/* Initialize the output variables to -1 in case an error occurs. */
if( pnLog ) *pnLog = -1;
if( pnCkpt ) *pnCkpt = -1;
- assert( SQLITE_CHECKPOINT_FULL>SQLITE_CHECKPOINT_PASSIVE );
- assert( SQLITE_CHECKPOINT_FULL<SQLITE_CHECKPOINT_RESTART );
- assert( SQLITE_CHECKPOINT_PASSIVE+2==SQLITE_CHECKPOINT_RESTART );
- if( eMode<SQLITE_CHECKPOINT_PASSIVE || eMode>SQLITE_CHECKPOINT_RESTART ){
+ assert( SQLITE_CHECKPOINT_PASSIVE==0 );
+ assert( SQLITE_CHECKPOINT_FULL==1 );
+ assert( SQLITE_CHECKPOINT_RESTART==2 );
+ assert( SQLITE_CHECKPOINT_TRUNCATE==3 );
+ if( eMode<SQLITE_CHECKPOINT_PASSIVE || eMode>SQLITE_CHECKPOINT_TRUNCATE ){
+ /* EVIDENCE-OF: R-03996-12088 The M parameter must be a valid checkpoint
+ ** mode: */
return SQLITE_MISUSE;
}
@@ -123981,10 +130043,11 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
}
if( iDb<0 ){
rc = SQLITE_ERROR;
- sqlite3Error(db, SQLITE_ERROR, "unknown database: %s", zDb);
+ sqlite3ErrorWithMsg(db, SQLITE_ERROR, "unknown database: %s", zDb);
}else{
+ db->busyHandler.nBusy = 0;
rc = sqlite3Checkpoint(db, iDb, eMode, pnLog, pnCkpt);
- sqlite3Error(db, rc, 0);
+ sqlite3Error(db, rc);
}
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
@@ -123998,8 +130061,10 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
** to contains a zero-length string, all attached databases are
** checkpointed.
*/
-SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){
- return sqlite3_wal_checkpoint_v2(db, zDb, SQLITE_CHECKPOINT_PASSIVE, 0, 0);
+SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){
+ /* EVIDENCE-OF: R-41613-20553 The sqlite3_wal_checkpoint(D,X) is equivalent to
+ ** sqlite3_wal_checkpoint_v2(D,X,SQLITE_CHECKPOINT_PASSIVE,0,0). */
+ return sqlite3_wal_checkpoint_v2(db,zDb,SQLITE_CHECKPOINT_PASSIVE,0,0);
}
#ifndef SQLITE_OMIT_WAL
@@ -124085,7 +130150,7 @@ SQLITE_PRIVATE int sqlite3TempInMemory(const sqlite3 *db){
** Return UTF-8 encoded English language explanation of the most recent
** error.
*/
-SQLITE_API const char *sqlite3_errmsg(sqlite3 *db){
+SQLITE_API const char *SQLITE_STDCALL sqlite3_errmsg(sqlite3 *db){
const char *z;
if( !db ){
return sqlite3ErrStr(SQLITE_NOMEM);
@@ -124113,7 +130178,7 @@ SQLITE_API const char *sqlite3_errmsg(sqlite3 *db){
** Return UTF-16 encoded English language explanation of the most recent
** error.
*/
-SQLITE_API const void *sqlite3_errmsg16(sqlite3 *db){
+SQLITE_API const void *SQLITE_STDCALL sqlite3_errmsg16(sqlite3 *db){
static const u16 outOfMem[] = {
'o', 'u', 't', ' ', 'o', 'f', ' ', 'm', 'e', 'm', 'o', 'r', 'y', 0
};
@@ -124139,7 +130204,7 @@ SQLITE_API const void *sqlite3_errmsg16(sqlite3 *db){
}else{
z = sqlite3_value_text16(db->pErr);
if( z==0 ){
- sqlite3Error(db, db->errCode, sqlite3ErrStr(db->errCode));
+ sqlite3ErrorWithMsg(db, db->errCode, sqlite3ErrStr(db->errCode));
z = sqlite3_value_text16(db->pErr);
}
/* A malloc() may have failed within the call to sqlite3_value_text16()
@@ -124158,7 +130223,7 @@ SQLITE_API const void *sqlite3_errmsg16(sqlite3 *db){
** Return the most recent error code generated by an SQLite routine. If NULL is
** passed to this function, we assume a malloc() failed during sqlite3_open().
*/
-SQLITE_API int sqlite3_errcode(sqlite3 *db){
+SQLITE_API int SQLITE_STDCALL sqlite3_errcode(sqlite3 *db){
if( db && !sqlite3SafetyCheckSickOrOk(db) ){
return SQLITE_MISUSE_BKPT;
}
@@ -124167,7 +130232,7 @@ SQLITE_API int sqlite3_errcode(sqlite3 *db){
}
return db->errCode & db->errMask;
}
-SQLITE_API int sqlite3_extended_errcode(sqlite3 *db){
+SQLITE_API int SQLITE_STDCALL sqlite3_extended_errcode(sqlite3 *db){
if( db && !sqlite3SafetyCheckSickOrOk(db) ){
return SQLITE_MISUSE_BKPT;
}
@@ -124182,37 +130247,11 @@ SQLITE_API int sqlite3_extended_errcode(sqlite3 *db){
** argument. For now, this simply calls the internal sqlite3ErrStr()
** function.
*/
-SQLITE_API const char *sqlite3_errstr(int rc){
+SQLITE_API const char *SQLITE_STDCALL sqlite3_errstr(int rc){
return sqlite3ErrStr(rc);
}
/*
-** Invalidate all cached KeyInfo objects for database connection "db"
-*/
-static void invalidateCachedKeyInfo(sqlite3 *db){
- Db *pDb; /* A single database */
- int iDb; /* The database index number */
- HashElem *k; /* For looping over tables in pDb */
- Table *pTab; /* A table in the database */
- Index *pIdx; /* Each index */
-
- for(iDb=0, pDb=db->aDb; iDb<db->nDb; iDb++, pDb++){
- if( pDb->pBt==0 ) continue;
- sqlite3BtreeEnter(pDb->pBt);
- for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){
- pTab = (Table*)sqliteHashData(k);
- for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- if( pIdx->pKeyInfo && pIdx->pKeyInfo->db==db ){
- sqlite3KeyInfoUnref(pIdx->pKeyInfo);
- pIdx->pKeyInfo = 0;
- }
- }
- }
- sqlite3BtreeLeave(pDb->pBt);
- }
-}
-
-/*
** Create a new collating function for database "db". The name is zName
** and the encoding is enc.
*/
@@ -124226,7 +130265,6 @@ static int createCollation(
){
CollSeq *pColl;
int enc2;
- int nName = sqlite3Strlen30(zName);
assert( sqlite3_mutex_held(db->mutex) );
@@ -124251,12 +130289,11 @@ static int createCollation(
pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, 0);
if( pColl && pColl->xCmp ){
if( db->nVdbeActive ){
- sqlite3Error(db, SQLITE_BUSY,
+ sqlite3ErrorWithMsg(db, SQLITE_BUSY,
"unable to delete/modify collation sequence due to active statements");
return SQLITE_BUSY;
}
sqlite3ExpirePreparedStatements(db);
- invalidateCachedKeyInfo(db);
/* If collation sequence pColl was created directly by a call to
** sqlite3_create_collation, and not generated by synthCollSeq(),
@@ -124265,7 +130302,7 @@ static int createCollation(
** to be called.
*/
if( (pColl->enc & ~SQLITE_UTF16_ALIGNED)==enc2 ){
- CollSeq *aColl = sqlite3HashFind(&db->aCollSeq, zName, nName);
+ CollSeq *aColl = sqlite3HashFind(&db->aCollSeq, zName);
int j;
for(j=0; j<3; j++){
CollSeq *p = &aColl[j];
@@ -124285,7 +130322,7 @@ static int createCollation(
pColl->pUser = pCtx;
pColl->xDel = xDel;
pColl->enc = (u8)(enc2 | (enc & SQLITE_UTF16_ALIGNED));
- sqlite3Error(db, SQLITE_OK, 0);
+ sqlite3Error(db, SQLITE_OK);
return SQLITE_OK;
}
@@ -124307,6 +130344,7 @@ static const int aHardLimit[] = {
SQLITE_MAX_LIKE_PATTERN_LENGTH,
SQLITE_MAX_VARIABLE_NUMBER, /* IMP: R-38091-32352 */
SQLITE_MAX_TRIGGER_DEPTH,
+ SQLITE_MAX_WORKER_THREADS,
};
/*
@@ -124342,6 +130380,9 @@ static const int aHardLimit[] = {
#if SQLITE_MAX_TRIGGER_DEPTH<1
# error SQLITE_MAX_TRIGGER_DEPTH must be at least 1
#endif
+#if SQLITE_MAX_WORKER_THREADS<0 || SQLITE_MAX_WORKER_THREADS>50
+# error SQLITE_MAX_WORKER_THREADS must be between 0 and 50
+#endif
/*
@@ -124354,9 +130395,15 @@ static const int aHardLimit[] = {
** It merely prevents new constructs that exceed the limit
** from forming.
*/
-SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
+SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
int oldLimit;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return -1;
+ }
+#endif
/* EVIDENCE-OF: R-30189-54097 For each limit category SQLITE_LIMIT_NAME
** there is a hard upper bound set at compile-time by a C preprocessor
@@ -124375,7 +130422,8 @@ SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
SQLITE_MAX_LIKE_PATTERN_LENGTH );
assert( aHardLimit[SQLITE_LIMIT_VARIABLE_NUMBER]==SQLITE_MAX_VARIABLE_NUMBER);
assert( aHardLimit[SQLITE_LIMIT_TRIGGER_DEPTH]==SQLITE_MAX_TRIGGER_DEPTH );
- assert( SQLITE_LIMIT_TRIGGER_DEPTH==(SQLITE_N_LIMIT-1) );
+ assert( aHardLimit[SQLITE_LIMIT_WORKER_THREADS]==SQLITE_MAX_WORKER_THREADS );
+ assert( SQLITE_LIMIT_WORKER_THREADS==(SQLITE_N_LIMIT-1) );
if( limitId<0 || limitId>=SQLITE_N_LIMIT ){
@@ -124432,25 +130480,38 @@ SQLITE_PRIVATE int sqlite3ParseUri(
assert( *pzErrMsg==0 );
- if( ((flags & SQLITE_OPEN_URI) || sqlite3GlobalConfig.bOpenUri)
- && nUri>=5 && memcmp(zUri, "file:", 5)==0
+ if( ((flags & SQLITE_OPEN_URI) /* IMP: R-48725-32206 */
+ || sqlite3GlobalConfig.bOpenUri) /* IMP: R-51689-46548 */
+ && nUri>=5 && memcmp(zUri, "file:", 5)==0 /* IMP: R-57884-37496 */
){
char *zOpt;
int eState; /* Parser state when parsing URI */
int iIn; /* Input character index */
int iOut = 0; /* Output character index */
- int nByte = nUri+2; /* Bytes of space to allocate */
+ u64 nByte = nUri+2; /* Bytes of space to allocate */
/* Make sure the SQLITE_OPEN_URI flag is set to indicate to the VFS xOpen
** method that there may be extra parameters following the file-name. */
flags |= SQLITE_OPEN_URI;
for(iIn=0; iIn<nUri; iIn++) nByte += (zUri[iIn]=='&');
- zFile = sqlite3_malloc(nByte);
+ zFile = sqlite3_malloc64(nByte);
if( !zFile ) return SQLITE_NOMEM;
iIn = 5;
-#ifndef SQLITE_ALLOW_URI_AUTHORITY
+#ifdef SQLITE_ALLOW_URI_AUTHORITY
+ if( strncmp(zUri+5, "///", 3)==0 ){
+ iIn = 7;
+ /* The following condition causes URIs with five leading / characters
+ ** like file://///host/path to be converted into UNCs like //host/path.
+ ** The correct URI for that UNC has only two or four leading / characters
+ ** file://host/path or file:////host/path. But 5 leading slashes is a
+ ** common error, we are told, so we handle it as a special case. */
+ if( strncmp(zUri+7, "///", 3)==0 ){ iIn++; }
+ }else if( strncmp(zUri+5, "//localhost/", 12)==0 ){
+ iIn = 16;
+ }
+#else
/* Discard the scheme and authority segments of the URI. */
if( zUri[5]=='/' && zUri[6]=='/' ){
iIn = 7;
@@ -124600,7 +130661,7 @@ SQLITE_PRIVATE int sqlite3ParseUri(
}
}else{
- zFile = sqlite3_malloc(nUri+2);
+ zFile = sqlite3_malloc64(nUri+2);
if( !zFile ) return SQLITE_NOMEM;
memcpy(zFile, zUri, nUri);
zFile[nUri] = '\0';
@@ -124641,6 +130702,9 @@ static int openDatabase(
char *zOpen = 0; /* Filename argument to pass to BtreeOpen() */
char *zErrMsg = 0; /* Error message from sqlite3ParseUri() */
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( ppDb==0 ) return SQLITE_MISUSE_BKPT;
+#endif
*ppDb = 0;
#ifndef SQLITE_OMIT_AUTOINIT
rc = sqlite3_initialize();
@@ -124663,7 +130727,9 @@ static int openDatabase(
testcase( (1<<(flags&7))==0x02 ); /* READONLY */
testcase( (1<<(flags&7))==0x04 ); /* READWRITE */
testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */
- if( ((1<<(flags&7)) & 0x46)==0 ) return SQLITE_MISUSE_BKPT;
+ if( ((1<<(flags&7)) & 0x46)==0 ){
+ return SQLITE_MISUSE_BKPT; /* IMP: R-65497-44594 */
+ }
if( sqlite3GlobalConfig.bCoreMutex==0 ){
isThreadsafe = 0;
@@ -124722,14 +130788,19 @@ static int openDatabase(
assert( sizeof(db->aLimit)==sizeof(aHardLimit) );
memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit));
+ db->aLimit[SQLITE_LIMIT_WORKER_THREADS] = SQLITE_DEFAULT_WORKER_THREADS;
db->autoCommit = 1;
db->nextAutovac = -1;
db->szMmap = sqlite3GlobalConfig.szMmap;
db->nextPagesize = 0;
+ db->nMaxSorterMmap = 0x7FFFFFFF;
db->flags |= SQLITE_ShortColNames | SQLITE_EnableTrigger | SQLITE_CacheSpill
#if !defined(SQLITE_DEFAULT_AUTOMATIC_INDEX) || SQLITE_DEFAULT_AUTOMATIC_INDEX
| SQLITE_AutoIndex
#endif
+#if SQLITE_DEFAULT_CKPTFULLFSYNC
+ | SQLITE_CkptFullFSync
+#endif
#if SQLITE_DEFAULT_FILE_FORMAT<4
| SQLITE_LegacyFileFmt
#endif
@@ -124742,6 +130813,9 @@ static int openDatabase(
#if defined(SQLITE_DEFAULT_FOREIGN_KEYS) && SQLITE_DEFAULT_FOREIGN_KEYS
| SQLITE_ForeignKeys
#endif
+#if defined(SQLITE_REVERSE_UNORDERED_SELECTS)
+ | SQLITE_ReverseOrder
+#endif
;
sqlite3HashInit(&db->aCollSeq);
#ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -124751,26 +130825,30 @@ static int openDatabase(
/* Add the default collation sequence BINARY. BINARY works for both UTF-8
** and UTF-16, so add a version for each to avoid any unnecessary
** conversions. The only error that can occur here is a malloc() failure.
+ **
+ ** EVIDENCE-OF: R-52786-44878 SQLite defines three built-in collating
+ ** functions:
*/
createCollation(db, "BINARY", SQLITE_UTF8, 0, binCollFunc, 0);
createCollation(db, "BINARY", SQLITE_UTF16BE, 0, binCollFunc, 0);
createCollation(db, "BINARY", SQLITE_UTF16LE, 0, binCollFunc, 0);
+ createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0);
createCollation(db, "RTRIM", SQLITE_UTF8, (void*)1, binCollFunc, 0);
if( db->mallocFailed ){
goto opendb_out;
}
+ /* EVIDENCE-OF: R-08308-17224 The default collating function for all
+ ** strings is BINARY.
+ */
db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 0);
assert( db->pDfltColl!=0 );
- /* Also add a UTF-8 case-insensitive collation sequence. */
- createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0);
-
/* Parse the filename/URI argument. */
db->openFlags = flags;
rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
- sqlite3Error(db, rc, zErrMsg ? "%s" : 0, zErrMsg);
+ sqlite3ErrorWithMsg(db, rc, zErrMsg ? "%s" : 0, zErrMsg);
sqlite3_free(zErrMsg);
goto opendb_out;
}
@@ -124782,13 +130860,15 @@ static int openDatabase(
if( rc==SQLITE_IOERR_NOMEM ){
rc = SQLITE_NOMEM;
}
- sqlite3Error(db, rc, 0);
+ sqlite3Error(db, rc);
goto opendb_out;
}
+ sqlite3BtreeEnter(db->aDb[0].pBt);
db->aDb[0].pSchema = sqlite3SchemaGet(db, db->aDb[0].pBt);
+ if( !db->mallocFailed ) ENC(db) = SCHEMA_ENC(db);
+ sqlite3BtreeLeave(db->aDb[0].pBt);
db->aDb[1].pSchema = sqlite3SchemaGet(db, 0);
-
/* The default safety_level for the main database is 'full'; for the temp
** database it is 'NONE'. This matches the pager layer defaults.
*/
@@ -124806,7 +130886,7 @@ static int openDatabase(
** database schema yet. This is delayed until the first time the database
** is accessed.
*/
- sqlite3Error(db, SQLITE_OK, 0);
+ sqlite3Error(db, SQLITE_OK);
sqlite3RegisterBuiltinFunctions(db);
/* Load automatic extensions - extensions that have been registered
@@ -124853,6 +130933,13 @@ static int openDatabase(
}
#endif
+#ifdef SQLITE_ENABLE_DBSTAT_VTAB
+ if( !db->mallocFailed && rc==SQLITE_OK){
+ int sqlite3_dbstat_register(sqlite3*);
+ rc = sqlite3_dbstat_register(db);
+ }
+#endif
+
/* -DSQLITE_DEFAULT_LOCKING_MODE=1 makes EXCLUSIVE the default locking
** mode. -DSQLITE_DEFAULT_LOCKING_MODE=0 make NORMAL the default locking
** mode. Doing nothing at all also makes NORMAL the default.
@@ -124863,7 +130950,7 @@ static int openDatabase(
SQLITE_DEFAULT_LOCKING_MODE);
#endif
- if( rc ) sqlite3Error(db, rc, 0);
+ if( rc ) sqlite3Error(db, rc);
/* Enable the lookaside-malloc subsystem */
setupLookaside(db, 0, sqlite3GlobalConfig.szLookaside,
@@ -124874,7 +130961,8 @@ static int openDatabase(
opendb_out:
sqlite3_free(zOpen);
if( db ){
- assert( db->mutex!=0 || isThreadsafe==0 || sqlite3GlobalConfig.bFullMutex==0 );
+ assert( db->mutex!=0 || isThreadsafe==0
+ || sqlite3GlobalConfig.bFullMutex==0 );
sqlite3_mutex_leave(db->mutex);
}
rc = sqlite3_errcode(db);
@@ -124899,14 +130987,14 @@ opendb_out:
/*
** Open a new database handle.
*/
-SQLITE_API int sqlite3_open(
+SQLITE_API int SQLITE_STDCALL sqlite3_open(
const char *zFilename,
sqlite3 **ppDb
){
return openDatabase(zFilename, ppDb,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0);
}
-SQLITE_API int sqlite3_open_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_open_v2(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb, /* OUT: SQLite db handle */
int flags, /* Flags */
@@ -124919,7 +131007,7 @@ SQLITE_API int sqlite3_open_v2(
/*
** Open a new database handle.
*/
-SQLITE_API int sqlite3_open16(
+SQLITE_API int SQLITE_STDCALL sqlite3_open16(
const void *zFilename,
sqlite3 **ppDb
){
@@ -124927,13 +131015,15 @@ SQLITE_API int sqlite3_open16(
sqlite3_value *pVal;
int rc;
- assert( zFilename );
- assert( ppDb );
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( ppDb==0 ) return SQLITE_MISUSE_BKPT;
+#endif
*ppDb = 0;
#ifndef SQLITE_OMIT_AUTOINIT
rc = sqlite3_initialize();
if( rc ) return rc;
#endif
+ if( zFilename==0 ) zFilename = "\000\000";
pVal = sqlite3ValueNew(0);
sqlite3ValueSetStr(pVal, -1, zFilename, SQLITE_UTF16NATIVE, SQLITE_STATIC);
zFilename8 = sqlite3ValueText(pVal, SQLITE_UTF8);
@@ -124942,7 +131032,7 @@ SQLITE_API int sqlite3_open16(
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0);
assert( *ppDb || rc==SQLITE_NOMEM );
if( rc==SQLITE_OK && !DbHasProperty(*ppDb, 0, DB_SchemaLoaded) ){
- ENC(*ppDb) = SQLITE_UTF16NATIVE;
+ SCHEMA_ENC(*ppDb) = ENC(*ppDb) = SQLITE_UTF16NATIVE;
}
}else{
rc = SQLITE_NOMEM;
@@ -124956,26 +131046,20 @@ SQLITE_API int sqlite3_open16(
/*
** Register a new collation sequence with the database handle db.
*/
-SQLITE_API int sqlite3_create_collation(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_collation(
sqlite3* db,
const char *zName,
int enc,
void* pCtx,
int(*xCompare)(void*,int,const void*,int,const void*)
){
- int rc;
- sqlite3_mutex_enter(db->mutex);
- assert( !db->mallocFailed );
- rc = createCollation(db, zName, (u8)enc, pCtx, xCompare, 0);
- rc = sqlite3ApiExit(db, rc);
- sqlite3_mutex_leave(db->mutex);
- return rc;
+ return sqlite3_create_collation_v2(db, zName, enc, pCtx, xCompare, 0);
}
/*
** Register a new collation sequence with the database handle db.
*/
-SQLITE_API int sqlite3_create_collation_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_collation_v2(
sqlite3* db,
const char *zName,
int enc,
@@ -124984,6 +131068,10 @@ SQLITE_API int sqlite3_create_collation_v2(
void(*xDel)(void*)
){
int rc;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT;
+#endif
sqlite3_mutex_enter(db->mutex);
assert( !db->mallocFailed );
rc = createCollation(db, zName, (u8)enc, pCtx, xCompare, xDel);
@@ -124996,7 +131084,7 @@ SQLITE_API int sqlite3_create_collation_v2(
/*
** Register a new collation sequence with the database handle db.
*/
-SQLITE_API int sqlite3_create_collation16(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_collation16(
sqlite3* db,
const void *zName,
int enc,
@@ -125005,6 +131093,10 @@ SQLITE_API int sqlite3_create_collation16(
){
int rc = SQLITE_OK;
char *zName8;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT;
+#endif
sqlite3_mutex_enter(db->mutex);
assert( !db->mallocFailed );
zName8 = sqlite3Utf16to8(db, zName, -1, SQLITE_UTF16NATIVE);
@@ -125022,11 +131114,14 @@ SQLITE_API int sqlite3_create_collation16(
** Register a collation sequence factory callback with the database handle
** db. Replace any previously installed collation sequence factory.
*/
-SQLITE_API int sqlite3_collation_needed(
+SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed(
sqlite3 *db,
void *pCollNeededArg,
void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*)
){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
sqlite3_mutex_enter(db->mutex);
db->xCollNeeded = xCollNeeded;
db->xCollNeeded16 = 0;
@@ -125040,11 +131135,14 @@ SQLITE_API int sqlite3_collation_needed(
** Register a collation sequence factory callback with the database handle
** db. Replace any previously installed collation sequence factory.
*/
-SQLITE_API int sqlite3_collation_needed16(
+SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed16(
sqlite3 *db,
void *pCollNeededArg,
void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*)
){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
sqlite3_mutex_enter(db->mutex);
db->xCollNeeded = 0;
db->xCollNeeded16 = xCollNeeded16;
@@ -125059,7 +131157,7 @@ SQLITE_API int sqlite3_collation_needed16(
** This function is now an anachronism. It used to be used to recover from a
** malloc() failure, but SQLite now does this automatically.
*/
-SQLITE_API int sqlite3_global_recover(void){
+SQLITE_API int SQLITE_STDCALL sqlite3_global_recover(void){
return SQLITE_OK;
}
#endif
@@ -125070,14 +131168,20 @@ SQLITE_API int sqlite3_global_recover(void){
** by default. Autocommit is disabled by a BEGIN statement and reenabled
** by the next COMMIT or ROLLBACK.
*/
-SQLITE_API int sqlite3_get_autocommit(sqlite3 *db){
+SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3 *db){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
return db->autoCommit;
}
/*
-** The following routines are subtitutes for constants SQLITE_CORRUPT,
+** The following routines are substitutes for constants SQLITE_CORRUPT,
** SQLITE_MISUSE, SQLITE_CANTOPEN, SQLITE_IOERR and possibly other error
-** constants. They server two purposes:
+** constants. They serve two purposes:
**
** 1. Serve as a convenient place to set a breakpoint in a debugger
** to detect when version error conditions occurs.
@@ -125116,7 +131220,7 @@ SQLITE_PRIVATE int sqlite3CantopenError(int lineno){
** SQLite no longer uses thread-specific data so this routine is now a
** no-op. It is retained for historical compatibility.
*/
-SQLITE_API void sqlite3_thread_cleanup(void){
+SQLITE_API void SQLITE_STDCALL sqlite3_thread_cleanup(void){
}
#endif
@@ -125124,8 +131228,7 @@ SQLITE_API void sqlite3_thread_cleanup(void){
** Return meta information about a specific column of a database table.
** See comment in sqlite3.h (sqlite.h.in) for details.
*/
-#ifdef SQLITE_ENABLE_COLUMN_METADATA
-SQLITE_API int sqlite3_table_column_metadata(
+SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata(
sqlite3 *db, /* Connection handle */
const char *zDbName, /* Database name or NULL */
const char *zTableName, /* Table name */
@@ -125140,14 +131243,20 @@ SQLITE_API int sqlite3_table_column_metadata(
char *zErrMsg = 0;
Table *pTab = 0;
Column *pCol = 0;
- int iCol;
-
+ int iCol = 0;
char const *zDataType = 0;
char const *zCollSeq = 0;
int notnull = 0;
int primarykey = 0;
int autoinc = 0;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) || zTableName==0 ){
+ return SQLITE_MISUSE_BKPT;
+ }
+#endif
+
/* Ensure the database schema has been loaded */
sqlite3_mutex_enter(db->mutex);
sqlite3BtreeEnterAll(db);
@@ -125164,11 +131273,8 @@ SQLITE_API int sqlite3_table_column_metadata(
}
/* Find the column for which info is requested */
- if( sqlite3IsRowid(zColumnName) ){
- iCol = pTab->iPKey;
- if( iCol>=0 ){
- pCol = &pTab->aCol[iCol];
- }
+ if( zColumnName==0 ){
+ /* Query for existance of table only */
}else{
for(iCol=0; iCol<pTab->nCol; iCol++){
pCol = &pTab->aCol[iCol];
@@ -125177,8 +131283,13 @@ SQLITE_API int sqlite3_table_column_metadata(
}
}
if( iCol==pTab->nCol ){
- pTab = 0;
- goto error_out;
+ if( HasRowid(pTab) && sqlite3IsRowid(zColumnName) ){
+ iCol = pTab->iPKey;
+ pCol = iCol>=0 ? &pTab->aCol[iCol] : 0;
+ }else{
+ pTab = 0;
+ goto error_out;
+ }
}
}
@@ -125225,18 +131336,17 @@ error_out:
zColumnName);
rc = SQLITE_ERROR;
}
- sqlite3Error(db, rc, (zErrMsg?"%s":0), zErrMsg);
+ sqlite3ErrorWithMsg(db, rc, (zErrMsg?"%s":0), zErrMsg);
sqlite3DbFree(db, zErrMsg);
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
return rc;
}
-#endif
/*
** Sleep for a little while. Return the amount of time slept.
*/
-SQLITE_API int sqlite3_sleep(int ms){
+SQLITE_API int SQLITE_STDCALL sqlite3_sleep(int ms){
sqlite3_vfs *pVfs;
int rc;
pVfs = sqlite3_vfs_find(0);
@@ -125252,7 +131362,10 @@ SQLITE_API int sqlite3_sleep(int ms){
/*
** Enable or disable the extended result codes.
*/
-SQLITE_API int sqlite3_extended_result_codes(sqlite3 *db, int onoff){
+SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3 *db, int onoff){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
sqlite3_mutex_enter(db->mutex);
db->errMask = onoff ? 0xffffffff : 0xff;
sqlite3_mutex_leave(db->mutex);
@@ -125262,10 +131375,13 @@ SQLITE_API int sqlite3_extended_result_codes(sqlite3 *db, int onoff){
/*
** Invoke the xFileControl method on a particular database.
*/
-SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
+SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
int rc = SQLITE_ERROR;
Btree *pBtree;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
sqlite3_mutex_enter(db->mutex);
pBtree = sqlite3DbNameToBtree(db, zDbName);
if( pBtree ){
@@ -125287,13 +131403,13 @@ SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, vo
sqlite3BtreeLeave(pBtree);
}
sqlite3_mutex_leave(db->mutex);
- return rc;
+ return rc;
}
/*
** Interface to the testing logic.
*/
-SQLITE_API int sqlite3_test_control(int op, ...){
+SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...){
int rc = 0;
#ifndef SQLITE_OMIT_BUILTIN_TEST
va_list ap;
@@ -125391,7 +131507,7 @@ SQLITE_API int sqlite3_test_control(int op, ...){
** IMPORTANT: Changing the PENDING byte from 0x40000000 results in
** an incompatible database file format. Changing the PENDING byte
** while any database connection is open results in undefined and
- ** dileterious behavior.
+ ** deleterious behavior.
*/
case SQLITE_TESTCTRL_PENDING_BYTE: {
rc = PENDING_BYTE;
@@ -125546,22 +131662,6 @@ SQLITE_API int sqlite3_test_control(int op, ...){
break;
}
-#if defined(SQLITE_ENABLE_TREE_EXPLAIN)
- /* sqlite3_test_control(SQLITE_TESTCTRL_EXPLAIN_STMT,
- ** sqlite3_stmt*,const char**);
- **
- ** If compiled with SQLITE_ENABLE_TREE_EXPLAIN, each sqlite3_stmt holds
- ** a string that describes the optimized parse tree. This test-control
- ** returns a pointer to that string.
- */
- case SQLITE_TESTCTRL_EXPLAIN_STMT: {
- sqlite3_stmt *pStmt = va_arg(ap, sqlite3_stmt*);
- const char **pzRet = va_arg(ap, const char**);
- *pzRet = sqlite3VdbeExplanation((Vdbe*)pStmt);
- break;
- }
-#endif
-
/* sqlite3_test_control(SQLITE_TESTCTRL_NEVER_CORRUPT, int);
**
** Set or clear a flag that indicates that the database file is always well-
@@ -125590,6 +131690,13 @@ SQLITE_API int sqlite3_test_control(int op, ...){
break;
}
+ /* sqlite3_test_control(SQLITE_TESTCTRL_SORTER_MMAP, db, nMax); */
+ case SQLITE_TESTCTRL_SORTER_MMAP: {
+ sqlite3 *db = va_arg(ap, sqlite3*);
+ db->nMaxSorterMmap = va_arg(ap, int);
+ break;
+ }
+
/* sqlite3_test_control(SQLITE_TESTCTRL_ISINIT);
**
** Return SQLITE_OK if SQLite has been initialized and SQLITE_ERROR if
@@ -125600,6 +131707,34 @@ SQLITE_API int sqlite3_test_control(int op, ...){
break;
}
+ /* sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, dbName, onOff, tnum);
+ **
+ ** This test control is used to create imposter tables. "db" is a pointer
+ ** to the database connection. dbName is the database name (ex: "main" or
+ ** "temp") which will receive the imposter. "onOff" turns imposter mode on
+ ** or off. "tnum" is the root page of the b-tree to which the imposter
+ ** table should connect.
+ **
+ ** Enable imposter mode only when the schema has already been parsed. Then
+ ** run a single CREATE TABLE statement to construct the imposter table in
+ ** the parsed schema. Then turn imposter mode back off again.
+ **
+ ** If onOff==0 and tnum>0 then reset the schema for all databases, causing
+ ** the schema to be reparsed the next time it is needed. This has the
+ ** effect of erasing all imposter tables.
+ */
+ case SQLITE_TESTCTRL_IMPOSTER: {
+ sqlite3 *db = va_arg(ap, sqlite3*);
+ sqlite3_mutex_enter(db->mutex);
+ db->init.iDb = sqlite3FindDbName(db, va_arg(ap,const char*));
+ db->init.busy = db->init.imposterTable = va_arg(ap,int);
+ db->init.newTnum = va_arg(ap,int);
+ if( db->init.busy==0 && db->init.newTnum>0 ){
+ sqlite3ResetAllSchemasOfConnection(db);
+ }
+ sqlite3_mutex_leave(db->mutex);
+ break;
+ }
}
va_end(ap);
#endif /* SQLITE_OMIT_BUILTIN_TEST */
@@ -125617,8 +131752,8 @@ SQLITE_API int sqlite3_test_control(int op, ...){
** parameter if it exists. If the parameter does not exist, this routine
** returns a NULL pointer.
*/
-SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){
- if( zFilename==0 ) return 0;
+SQLITE_API const char *SQLITE_STDCALL sqlite3_uri_parameter(const char *zFilename, const char *zParam){
+ if( zFilename==0 || zParam==0 ) return 0;
zFilename += sqlite3Strlen30(zFilename) + 1;
while( zFilename[0] ){
int x = strcmp(zFilename, zParam);
@@ -125632,7 +131767,7 @@ SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *
/*
** Return a boolean value for a query parameter.
*/
-SQLITE_API int sqlite3_uri_boolean(const char *zFilename, const char *zParam, int bDflt){
+SQLITE_API int SQLITE_STDCALL sqlite3_uri_boolean(const char *zFilename, const char *zParam, int bDflt){
const char *z = sqlite3_uri_parameter(zFilename, zParam);
bDflt = bDflt!=0;
return z ? sqlite3GetBoolean(z, bDflt) : bDflt;
@@ -125641,7 +131776,7 @@ SQLITE_API int sqlite3_uri_boolean(const char *zFilename, const char *zParam, in
/*
** Return a 64-bit integer value for a query parameter.
*/
-SQLITE_API sqlite3_int64 sqlite3_uri_int64(
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_uri_int64(
const char *zFilename, /* Filename as passed to xOpen */
const char *zParam, /* URI parameter sought */
sqlite3_int64 bDflt /* return if parameter is missing */
@@ -125673,8 +131808,15 @@ SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){
** Return the filename of the database associated with a database
** connection.
*/
-SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){
- Btree *pBt = sqlite3DbNameToBtree(db, zDbName);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_db_filename(sqlite3 *db, const char *zDbName){
+ Btree *pBt;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
+ pBt = sqlite3DbNameToBtree(db, zDbName);
return pBt ? sqlite3BtreeGetFilename(pBt) : 0;
}
@@ -125682,8 +131824,15 @@ SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){
** Return 1 if database is read-only or 0 if read/write. Return -1 if
** no such database exists.
*/
-SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName){
- Btree *pBt = sqlite3DbNameToBtree(db, zDbName);
+SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbName){
+ Btree *pBt;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return -1;
+ }
+#endif
+ pBt = sqlite3DbNameToBtree(db, zDbName);
return pBt ? sqlite3BtreeIsReadonly(pBt) : -1;
}
@@ -125834,7 +131983,7 @@ static void leaveMutex(void){
** on the same "db". If xNotify==0 then any prior callbacks are immediately
** cancelled.
*/
-SQLITE_API int sqlite3_unlock_notify(
+SQLITE_API int SQLITE_STDCALL sqlite3_unlock_notify(
sqlite3 *db,
void (*xNotify)(void **, int),
void *pArg
@@ -125873,7 +132022,7 @@ SQLITE_API int sqlite3_unlock_notify(
leaveMutex();
assert( !db->mallocFailed );
- sqlite3Error(db, rc, (rc?"database is deadlocked":0));
+ sqlite3ErrorWithMsg(db, rc, (rc?"database is deadlocked":0));
sqlite3_mutex_leave(db->mutex);
return rc;
}
@@ -126728,6 +132877,11 @@ SQLITE_PRIVATE Fts3HashElem *sqlite3Fts3HashFindElem(const Fts3Hash *, const voi
#ifdef SQLITE_COVERAGE_TEST
# define ALWAYS(x) (1)
# define NEVER(X) (0)
+#elif defined(SQLITE_DEBUG)
+# define ALWAYS(x) sqlite3Fts3Always((x)!=0)
+# define NEVER(x) sqlite3Fts3Never((x)!=0)
+SQLITE_PRIVATE int sqlite3Fts3Always(int b);
+SQLITE_PRIVATE int sqlite3Fts3Never(int b);
#else
# define ALWAYS(x) (x)
# define NEVER(x) (x)
@@ -126969,6 +133123,11 @@ struct Fts3Phrase {
int bIncr; /* True if doclist is loaded incrementally */
int iDoclistToken;
+ /* Used by sqlite3Fts3EvalPhrasePoslist() if this is a descendent of an
+ ** OR condition. */
+ char *pOrPoslist;
+ i64 iOrDocid;
+
/* Variables below this point are populated by fts3_expr.c when parsing
** a MATCH expression. Everything above is part of the evaluation phase.
*/
@@ -127123,6 +133282,7 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table*,int,int);
)
/* fts3.c */
+SQLITE_PRIVATE void sqlite3Fts3ErrMsg(char**,const char*,...);
SQLITE_PRIVATE int sqlite3Fts3PutVarint(char *, sqlite3_int64);
SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *, sqlite_int64 *);
SQLITE_PRIVATE int sqlite3Fts3GetVarint32(const char *, int *);
@@ -127212,6 +133372,13 @@ static int fts3EvalStart(Fts3Cursor *pCsr);
static int fts3TermSegReaderCursor(
Fts3Cursor *, const char *, int, int, Fts3MultiSegReader **);
+#ifndef SQLITE_AMALGAMATION
+# if defined(SQLITE_DEBUG)
+SQLITE_PRIVATE int sqlite3Fts3Always(int b) { assert( b ); return b; }
+SQLITE_PRIVATE int sqlite3Fts3Never(int b) { assert( !b ); return b; }
+# endif
+#endif
+
/*
** Write a 64-bit variable-length integer to memory starting at p[0].
** The length of data written will be between 1 and FTS3_VARINT_MAX bytes.
@@ -127321,7 +133488,7 @@ SQLITE_PRIVATE void sqlite3Fts3Dequote(char *z){
/* If the first byte was a '[', then the close-quote character is a ']' */
if( quote=='[' ) quote = ']';
- while( ALWAYS(z[iIn]) ){
+ while( z[iIn] ){
if( z[iIn]==quote ){
if( z[iIn+1]!=quote ) break;
z[iOut++] = quote;
@@ -127401,6 +133568,17 @@ static int fts3DisconnectMethod(sqlite3_vtab *pVtab){
}
/*
+** Write an error message into *pzErr
+*/
+SQLITE_PRIVATE void sqlite3Fts3ErrMsg(char **pzErr, const char *zFormat, ...){
+ va_list ap;
+ sqlite3_free(*pzErr);
+ va_start(ap, zFormat);
+ *pzErr = sqlite3_vmprintf(zFormat, ap);
+ va_end(ap);
+}
+
+/*
** Construct one or more SQL statements from the format string given
** and then evaluate those statements. The success code is written
** into *pRc.
@@ -127809,11 +133987,16 @@ static char *fts3WriteExprList(Fts3Table *p, const char *zFunc, int *pRc){
** This function is used when parsing the "prefix=" FTS4 parameter.
*/
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;
+ }
}
if( p==*pp ) return SQLITE_ERROR;
*pnOut = nInt;
@@ -127856,7 +134039,6 @@ static int fts3PrefixParameter(
aIndex = sqlite3_malloc(sizeof(struct Fts3Index) * nIndex);
*apIndex = aIndex;
- *pnIndex = nIndex;
if( !aIndex ){
return SQLITE_NOMEM;
}
@@ -127866,13 +134048,20 @@ static int fts3PrefixParameter(
const char *p = zParam;
int i;
for(i=1; i<nIndex; i++){
- int nPrefix;
+ int nPrefix = 0;
if( fts3GobbleInt(&p, &nPrefix) ) return SQLITE_ERROR;
- aIndex[i].nPrefix = nPrefix;
+ assert( nPrefix>=0 );
+ if( nPrefix==0 ){
+ nIndex--;
+ i--;
+ }else{
+ aIndex[i].nPrefix = nPrefix;
+ }
p++;
}
}
+ *pnIndex = nIndex;
return SQLITE_OK;
}
@@ -127907,7 +134096,8 @@ static int fts3ContentColumns(
const char *zTbl, /* Name of content table */
const char ***pazCol, /* OUT: Malloc'd array of column names */
int *pnCol, /* OUT: Size of array *pazCol */
- int *pnStr /* OUT: Bytes of string content */
+ int *pnStr, /* OUT: Bytes of string content */
+ char **pzErr /* OUT: error message */
){
int rc = SQLITE_OK; /* Return code */
char *zSql; /* "SELECT *" statement on zTbl */
@@ -127918,6 +134108,9 @@ static int fts3ContentColumns(
rc = SQLITE_NOMEM;
}else{
rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
+ if( rc!=SQLITE_OK ){
+ sqlite3Fts3ErrMsg(pzErr, "%s", sqlite3_errmsg(db));
+ }
}
sqlite3_free(zSql);
@@ -127996,7 +134189,7 @@ static int fts3InitVtab(
const char **aCol; /* Array of column names */
sqlite3_tokenizer *pTokenizer = 0; /* Tokenizer for this table */
- int nIndex; /* Size of aIndex[] array */
+ int nIndex = 0; /* Size of aIndex[] array */
struct Fts3Index *aIndex = 0; /* Array of indexes for this table */
/* The results of parsing supported FTS4 key=value options: */
@@ -128084,13 +134277,13 @@ static int fts3InitVtab(
}
}
if( iOpt==SizeofArray(aFts4Opt) ){
- *pzErr = sqlite3_mprintf("unrecognized parameter: %s", z);
+ sqlite3Fts3ErrMsg(pzErr, "unrecognized parameter: %s", z);
rc = SQLITE_ERROR;
}else{
switch( iOpt ){
case 0: /* MATCHINFO */
if( strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "fts3", 4) ){
- *pzErr = sqlite3_mprintf("unrecognized matchinfo: %s", zVal);
+ sqlite3Fts3ErrMsg(pzErr, "unrecognized matchinfo: %s", zVal);
rc = SQLITE_ERROR;
}
bNoDocsize = 1;
@@ -128118,7 +134311,7 @@ static int fts3InitVtab(
if( (strlen(zVal)!=3 || sqlite3_strnicmp(zVal, "asc", 3))
&& (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 4))
){
- *pzErr = sqlite3_mprintf("unrecognized order: %s", zVal);
+ sqlite3Fts3ErrMsg(pzErr, "unrecognized order: %s", zVal);
rc = SQLITE_ERROR;
}
bDescIdx = (zVal[0]=='d' || zVal[0]=='D');
@@ -128169,7 +134362,7 @@ static int fts3InitVtab(
if( nCol==0 ){
sqlite3_free((void*)aCol);
aCol = 0;
- rc = fts3ContentColumns(db, argv[1], zContent, &aCol, &nCol, &nString);
+ rc = fts3ContentColumns(db, argv[1], zContent,&aCol,&nCol,&nString,pzErr);
/* If a languageid= option was specified, remove the language id
** column from the aCol[] array. */
@@ -128204,7 +134397,7 @@ static int fts3InitVtab(
rc = fts3PrefixParameter(zPrefix, &nIndex, &aIndex);
if( rc==SQLITE_ERROR ){
assert( zPrefix );
- *pzErr = sqlite3_mprintf("error parsing prefix parameter: %s", zPrefix);
+ sqlite3Fts3ErrMsg(pzErr, "error parsing prefix parameter: %s", zPrefix);
}
if( rc!=SQLITE_OK ) goto fts3_init_out;
@@ -128286,7 +134479,7 @@ static int fts3InitVtab(
}
for(i=0; i<nNotindexed; i++){
if( azNotindexed[i] ){
- *pzErr = sqlite3_mprintf("no such column: %s", azNotindexed[i]);
+ sqlite3Fts3ErrMsg(pzErr, "no such column: %s", azNotindexed[i]);
rc = SQLITE_ERROR;
}
}
@@ -128294,7 +134487,7 @@ static int fts3InitVtab(
if( rc==SQLITE_OK && (zCompress==0)!=(zUncompress==0) ){
char const *zMiss = (zCompress==0 ? "compress" : "uncompress");
rc = SQLITE_ERROR;
- *pzErr = sqlite3_mprintf("missing %s parameter in fts4 constructor", zMiss);
+ sqlite3Fts3ErrMsg(pzErr, "missing %s parameter in fts4 constructor", zMiss);
}
p->zReadExprlist = fts3ReadExprList(p, zUncompress, &rc);
p->zWriteExprlist = fts3WriteExprList(p, zCompress, &rc);
@@ -128752,7 +134945,7 @@ static int fts3SelectLeaf(
sqlite3_int64 *piLeaf, /* Selected leaf node */
sqlite3_int64 *piLeaf2 /* Selected leaf node */
){
- int rc; /* Return code */
+ int rc = SQLITE_OK; /* Return code */
int iHeight; /* Height of this node in tree */
assert( piLeaf || piLeaf2 );
@@ -128763,7 +134956,7 @@ static int fts3SelectLeaf(
if( rc==SQLITE_OK && iHeight>1 ){
char *zBlob = 0; /* Blob read from %_segments table */
- int nBlob; /* Size of zBlob in bytes */
+ int nBlob = 0; /* Size of zBlob in bytes */
if( piLeaf && piLeaf2 && (*piLeaf!=*piLeaf2) ){
rc = sqlite3Fts3ReadBlock(p, *piLeaf, &zBlob, &nBlob, 0);
@@ -129390,26 +135583,33 @@ static int fts3DoclistOrMerge(
**
** The right-hand input doclist is overwritten by this function.
*/
-static void fts3DoclistPhraseMerge(
+static int fts3DoclistPhraseMerge(
int bDescDoclist, /* True if arguments are desc */
int nDist, /* Distance from left to right (1=adjacent) */
char *aLeft, int nLeft, /* Left doclist */
- char *aRight, int *pnRight /* IN/OUT: Right/output doclist */
+ char **paRight, int *pnRight /* IN/OUT: Right/output doclist */
){
sqlite3_int64 i1 = 0;
sqlite3_int64 i2 = 0;
sqlite3_int64 iPrev = 0;
+ char *aRight = *paRight;
char *pEnd1 = &aLeft[nLeft];
char *pEnd2 = &aRight[*pnRight];
char *p1 = aLeft;
char *p2 = aRight;
char *p;
int bFirstOut = 0;
- char *aOut = aRight;
+ char *aOut;
assert( nDist>0 );
-
+ if( bDescDoclist ){
+ aOut = sqlite3_malloc(*pnRight + FTS3_VARINT_MAX);
+ if( aOut==0 ) return SQLITE_NOMEM;
+ }else{
+ aOut = aRight;
+ }
p = aOut;
+
fts3GetDeltaVarint3(&p1, pEnd1, 0, &i1);
fts3GetDeltaVarint3(&p2, pEnd2, 0, &i2);
@@ -129438,6 +135638,12 @@ static void fts3DoclistPhraseMerge(
}
*pnRight = (int)(p - aOut);
+ if( bDescDoclist ){
+ sqlite3_free(aRight);
+ *paRight = aOut;
+ }
+
+ return SQLITE_OK;
}
/*
@@ -129562,8 +135768,22 @@ static int fts3TermSelectMerge(
){
if( pTS->aaOutput[0]==0 ){
/* If this is the first term selected, copy the doclist to the output
- ** buffer using memcpy(). */
- pTS->aaOutput[0] = sqlite3_malloc(nDoclist);
+ ** buffer using memcpy().
+ **
+ ** Add FTS3_VARINT_MAX bytes of unused space to the end of the
+ ** allocation. This is so as to ensure that the buffer is big enough
+ ** to hold the current doclist AND'd with any other doclist. If the
+ ** doclists are stored in order=ASC order, this padding would not be
+ ** required (since the size of [doclistA AND doclistB] is always less
+ ** than or equal to the size of [doclistA] in that case). But this is
+ ** not true for order=DESC. For example, a doclist containing (1, -1)
+ ** may be smaller than (-1), as in the first example the -1 may be stored
+ ** as a single-byte delta, whereas in the second it must be stored as a
+ ** FTS3_VARINT_MAX byte varint.
+ **
+ ** Similar padding is added in the fts3DoclistOrMerge() function.
+ */
+ pTS->aaOutput[0] = sqlite3_malloc(nDoclist + FTS3_VARINT_MAX + 1);
pTS->anOutput[0] = nDoclist;
if( pTS->aaOutput[0] ){
memcpy(pTS->aaOutput[0], aDoclist, nDoclist);
@@ -129660,7 +135880,7 @@ static int fts3SegReaderCursor(
** calls out here. */
if( iLevel<0 && p->aIndex ){
Fts3SegReader *pSeg = 0;
- rc = sqlite3Fts3SegReaderPending(p, iIndex, zTerm, nTerm, isPrefix, &pSeg);
+ rc = sqlite3Fts3SegReaderPending(p, iIndex, zTerm, nTerm, isPrefix||isScan, &pSeg);
if( rc==SQLITE_OK && pSeg ){
rc = fts3SegReaderCursorAppend(pCsr, pSeg);
}
@@ -129985,7 +136205,7 @@ static int fts3FilterMethod(
int nVal, /* Number of elements in apVal */
sqlite3_value **apVal /* Arguments for the indexing scheme */
){
- int rc;
+ int rc = SQLITE_OK;
char *zSql; /* SQL statement used to access %_content */
int eSearch;
Fts3Table *p = (Fts3Table *)pCursor->pVtab;
@@ -130015,6 +136235,7 @@ static int fts3FilterMethod(
/* In case the cursor has been used before, clear it now. */
sqlite3_finalize(pCsr->pStmt);
sqlite3_free(pCsr->aDoclist);
+ sqlite3_free(pCsr->aMatchinfo);
sqlite3Fts3ExprFree(pCsr->pExpr);
memset(&pCursor[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor));
@@ -130062,10 +136283,17 @@ static int fts3FilterMethod(
** row by docid.
*/
if( eSearch==FTS3_FULLSCAN_SEARCH ){
- zSql = sqlite3_mprintf(
- "SELECT %s ORDER BY rowid %s",
- p->zReadExprlist, (pCsr->bDesc ? "DESC" : "ASC")
- );
+ if( pDocidGe || pDocidLe ){
+ zSql = sqlite3_mprintf(
+ "SELECT %s WHERE rowid BETWEEN %lld AND %lld ORDER BY rowid %s",
+ p->zReadExprlist, pCsr->iMinDocid, pCsr->iMaxDocid,
+ (pCsr->bDesc ? "DESC" : "ASC")
+ );
+ }else{
+ zSql = sqlite3_mprintf("SELECT %s ORDER BY rowid %s",
+ p->zReadExprlist, (pCsr->bDesc ? "DESC" : "ASC")
+ );
+ }
if( zSql ){
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0);
sqlite3_free(zSql);
@@ -130301,11 +136529,31 @@ static void fts3ReversePoslist(char *pStart, char **ppPoslist){
char *p = &(*ppPoslist)[-2];
char c = 0;
+ /* Skip backwards passed any trailing 0x00 bytes added by NearTrim() */
while( p>pStart && (c=*p--)==0 );
+
+ /* Search backwards for a varint with value zero (the end of the previous
+ ** poslist). This is an 0x00 byte preceded by some byte that does not
+ ** have the 0x80 bit set. */
while( p>pStart && (*p & 0x80) | c ){
c = *p--;
}
- if( p>pStart ){ p = &p[2]; }
+ assert( p==pStart || c==0 );
+
+ /* At this point p points to that preceding byte without the 0x80 bit
+ ** set. So to find the start of the poslist, skip forward 2 bytes then
+ ** over a varint.
+ **
+ ** Normally. The other case is that p==pStart and the poslist to return
+ ** is the first in the doclist. In this case do not skip forward 2 bytes.
+ ** The second part of the if condition (c==0 && *ppPoslist>&p[2])
+ ** is required for cases where the first byte of a doclist and the
+ ** doclist is empty. For example, if the first docid is 10, a doclist
+ ** that begins with:
+ **
+ ** 0x0A 0x00 <next docid delta varint>
+ */
+ if( p>pStart || (c==0 && *ppPoslist>&p[2]) ){ p = &p[2]; }
while( *p++&0x80 );
*ppPoslist = p;
}
@@ -130376,6 +136624,8 @@ static void fts3SnippetFunc(
}
if( !zEllipsis || !zEnd || !zStart ){
sqlite3_result_error_nomem(pContext);
+ }else if( nToken==0 ){
+ sqlite3_result_text(pContext, "", -1, SQLITE_STATIC);
}else if( SQLITE_OK==fts3CursorSeek(pContext, pCsr) ){
sqlite3Fts3Snippet(pContext, pCsr, zStart, zEnd, zEllipsis, iCol, nToken);
}
@@ -130811,14 +137061,17 @@ static void fts3EvalAllocateReaders(
** This function assumes that pList points to a buffer allocated using
** sqlite3_malloc(). This function takes responsibility for eventually
** freeing the buffer.
+**
+** SQLITE_OK is returned if successful, or SQLITE_NOMEM if an error occurs.
*/
-static void fts3EvalPhraseMergeToken(
+static int fts3EvalPhraseMergeToken(
Fts3Table *pTab, /* FTS Table pointer */
Fts3Phrase *p, /* Phrase to merge pList/nList into */
int iToken, /* Token pList/nList corresponds to */
char *pList, /* Pointer to doclist */
int nList /* Number of bytes in pList */
){
+ int rc = SQLITE_OK;
assert( iToken!=p->iDoclistToken );
if( pList==0 ){
@@ -130857,13 +137110,16 @@ static void fts3EvalPhraseMergeToken(
nDiff = p->iDoclistToken - iToken;
}
- fts3DoclistPhraseMerge(pTab->bDescIdx, nDiff, pLeft, nLeft, pRight,&nRight);
+ rc = fts3DoclistPhraseMerge(
+ pTab->bDescIdx, nDiff, pLeft, nLeft, &pRight, &nRight
+ );
sqlite3_free(pLeft);
p->doclist.aAll = pRight;
p->doclist.nAll = nRight;
}
if( iToken>p->iDoclistToken ) p->iDoclistToken = iToken;
+ return rc;
}
/*
@@ -130889,7 +137145,7 @@ static int fts3EvalPhraseLoad(
char *pThis = 0;
rc = fts3TermSelect(pTab, pToken, p->iColumn, &nThis, &pThis);
if( rc==SQLITE_OK ){
- fts3EvalPhraseMergeToken(pTab, p, iToken, pThis, nThis);
+ rc = fts3EvalPhraseMergeToken(pTab, p, iToken, pThis, nThis);
}
}
assert( pToken->pSegcsr==0 );
@@ -131325,7 +137581,7 @@ static int fts3EvalIncrPhraseNext(
bMaxSet = 1;
}
}
- assert( rc!=SQLITE_OK || a[p->nToken-1].bIgnore==0 );
+ assert( rc!=SQLITE_OK || (p->nToken>=1 && a[p->nToken-1].bIgnore==0) );
assert( rc!=SQLITE_OK || bMaxSet );
/* Keep advancing iterators until they all point to the same document */
@@ -131431,12 +137687,14 @@ static void fts3EvalStartReaders(
){
if( pExpr && SQLITE_OK==*pRc ){
if( pExpr->eType==FTSQUERY_PHRASE ){
- int i;
int nToken = pExpr->pPhrase->nToken;
- for(i=0; i<nToken; i++){
- if( pExpr->pPhrase->aToken[i].pDeferred==0 ) break;
+ if( nToken ){
+ int i;
+ for(i=0; i<nToken; i++){
+ if( pExpr->pPhrase->aToken[i].pDeferred==0 ) break;
+ }
+ pExpr->bDeferred = (i==nToken);
}
- pExpr->bDeferred = (i==nToken);
*pRc = fts3EvalPhraseStart(pCsr, 1, pExpr->pPhrase);
}else{
fts3EvalStartReaders(pCsr, pExpr->pLeft, pRc);
@@ -131692,8 +137950,12 @@ static int fts3EvalSelectDeferred(
rc = fts3TermSelect(pTab, pToken, pTC->iCol, &nList, &pList);
assert( rc==SQLITE_OK || pList==0 );
if( rc==SQLITE_OK ){
+ rc = fts3EvalPhraseMergeToken(
+ pTab, pTC->pPhrase, pTC->iToken,pList,nList
+ );
+ }
+ if( rc==SQLITE_OK ){
int nCount;
- fts3EvalPhraseMergeToken(pTab, pTC->pPhrase, pTC->iToken,pList,nList);
nCount = fts3DoclistCountDocids(
pTC->pPhrase->doclist.aAll, pTC->pPhrase->doclist.nAll
);
@@ -131918,6 +138180,22 @@ static void fts3EvalNextRow(
}
pExpr->iDocid = pLeft->iDocid;
pExpr->bEof = (pLeft->bEof || pRight->bEof);
+ if( pExpr->eType==FTSQUERY_NEAR && pExpr->bEof ){
+ if( pRight->pPhrase && pRight->pPhrase->doclist.aAll ){
+ Fts3Doclist *pDl = &pRight->pPhrase->doclist;
+ while( *pRc==SQLITE_OK && pRight->bEof==0 ){
+ memset(pDl->pList, 0, pDl->nList);
+ fts3EvalNextRow(pCsr, pRight, pRc);
+ }
+ }
+ if( pLeft->pPhrase && pLeft->pPhrase->doclist.aAll ){
+ Fts3Doclist *pDl = &pLeft->pPhrase->doclist;
+ while( *pRc==SQLITE_OK && pLeft->bEof==0 ){
+ memset(pDl->pList, 0, pDl->nList);
+ fts3EvalNextRow(pCsr, pLeft, pRc);
+ }
+ }
+ }
}
break;
}
@@ -132290,6 +138568,7 @@ static void fts3EvalRestart(
}
pPhrase->doclist.pNextDocid = 0;
pPhrase->doclist.iDocid = 0;
+ pPhrase->pOrPoslist = 0;
}
pExpr->iDocid = 0;
@@ -132535,8 +138814,8 @@ SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(
iDocid = pExpr->iDocid;
pIter = pPhrase->doclist.pList;
if( iDocid!=pCsr->iPrevId || pExpr->bEof ){
+ int rc = SQLITE_OK;
int bDescDoclist = pTab->bDescIdx; /* For DOCID_CMP macro */
- int iMul; /* +1 if csr dir matches index dir, else -1 */
int bOr = 0;
u8 bEof = 0;
u8 bTreeEof = 0;
@@ -132560,72 +138839,44 @@ SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(
** an incremental phrase. Load the entire doclist for the phrase
** into memory in this case. */
if( pPhrase->bIncr ){
- int rc = SQLITE_OK;
- int bEofSave = pExpr->bEof;
- fts3EvalRestart(pCsr, pExpr, &rc);
- while( rc==SQLITE_OK && !pExpr->bEof ){
- fts3EvalNextRow(pCsr, pExpr, &rc);
- if( bEofSave==0 && pExpr->iDocid==iDocid ) break;
+ int bEofSave = pNear->bEof;
+ fts3EvalRestart(pCsr, pNear, &rc);
+ while( rc==SQLITE_OK && !pNear->bEof ){
+ fts3EvalNextRow(pCsr, pNear, &rc);
+ if( bEofSave==0 && pNear->iDocid==iDocid ) break;
}
- pIter = pPhrase->doclist.pList;
assert( rc!=SQLITE_OK || pPhrase->bIncr==0 );
- if( rc!=SQLITE_OK ) return rc;
}
-
- iMul = ((pCsr->bDesc==bDescDoclist) ? 1 : -1);
- while( bTreeEof==1
- && pNear->bEof==0
- && (DOCID_CMP(pNear->iDocid, pCsr->iPrevId) * iMul)<0
- ){
- int rc = SQLITE_OK;
- fts3EvalNextRow(pCsr, pExpr, &rc);
- if( rc!=SQLITE_OK ) return rc;
- iDocid = pExpr->iDocid;
- pIter = pPhrase->doclist.pList;
+ if( bTreeEof ){
+ while( rc==SQLITE_OK && !pNear->bEof ){
+ fts3EvalNextRow(pCsr, pNear, &rc);
+ }
}
+ if( rc!=SQLITE_OK ) return rc;
- bEof = (pPhrase->doclist.nAll==0);
- assert( bDescDoclist==0 || bDescDoclist==1 );
- assert( pCsr->bDesc==0 || pCsr->bDesc==1 );
-
- if( bEof==0 ){
- if( pCsr->bDesc==bDescDoclist ){
+ pIter = pPhrase->pOrPoslist;
+ iDocid = pPhrase->iOrDocid;
+ if( pCsr->bDesc==bDescDoclist ){
+ bEof = !pPhrase->doclist.nAll ||
+ (pIter >= (pPhrase->doclist.aAll + pPhrase->doclist.nAll));
+ while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)<0 ) && bEof==0 ){
+ sqlite3Fts3DoclistNext(
+ bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll,
+ &pIter, &iDocid, &bEof
+ );
+ }
+ }else{
+ bEof = !pPhrase->doclist.nAll || (pIter && pIter<=pPhrase->doclist.aAll);
+ while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)>0 ) && bEof==0 ){
int dummy;
- if( pNear->bEof ){
- /* This expression is already at EOF. So position it to point to the
- ** last entry in the doclist at pPhrase->doclist.aAll[]. Variable
- ** iDocid is already set for this entry, so all that is required is
- ** to set pIter to point to the first byte of the last position-list
- ** in the doclist.
- **
- ** It would also be correct to set pIter and iDocid to zero. In
- ** this case, the first call to sqltie3Fts4DoclistPrev() below
- ** would also move the iterator to point to the last entry in the
- ** doclist. However, this is expensive, as to do so it has to
- ** iterate through the entire doclist from start to finish (since
- ** it does not know the docid for the last entry). */
- pIter = &pPhrase->doclist.aAll[pPhrase->doclist.nAll-1];
- fts3ReversePoslist(pPhrase->doclist.aAll, &pIter);
- }
- while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)>0 ) && bEof==0 ){
- sqlite3Fts3DoclistPrev(
- bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll,
- &pIter, &iDocid, &dummy, &bEof
- );
- }
- }else{
- if( pNear->bEof ){
- pIter = 0;
- iDocid = 0;
- }
- while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)<0 ) && bEof==0 ){
- sqlite3Fts3DoclistNext(
- bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll,
- &pIter, &iDocid, &bEof
- );
- }
+ sqlite3Fts3DoclistPrev(
+ bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll,
+ &pIter, &iDocid, &dummy, &bEof
+ );
}
}
+ pPhrase->pOrPoslist = pIter;
+ pPhrase->iOrDocid = iDocid;
if( bEof || iDocid!=pCsr->iPrevId ) pIter = 0;
}
@@ -132639,10 +138890,13 @@ SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(
}
while( iThis<iCol ){
fts3ColumnlistCopy(0, &pIter);
- if( *pIter==0x00 ) return 0;
+ if( *pIter==0x00 ) return SQLITE_OK;
pIter++;
pIter += fts3GetVarint32(pIter, &iThis);
}
+ if( *pIter==0x00 ){
+ pIter = 0;
+ }
*ppOut = ((iCol==iThis)?pIter:0);
return SQLITE_OK;
@@ -132685,7 +138939,7 @@ SQLITE_PRIVATE int sqlite3Fts3Corrupt(){
#ifdef _WIN32
__declspec(dllexport)
#endif
-SQLITE_API int sqlite3_fts3_init(
+SQLITE_API int SQLITE_STDCALL sqlite3_fts3_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
@@ -132816,7 +139070,7 @@ static int fts3auxConnectMethod(
return SQLITE_OK;
bad_args:
- *pzErr = sqlite3_mprintf("invalid arguments to fts4aux constructor");
+ sqlite3Fts3ErrMsg(pzErr, "invalid arguments to fts4aux constructor");
return SQLITE_ERROR;
}
@@ -133442,7 +139696,7 @@ static int getNextToken(
/* Set variable i to the maximum number of bytes of input to tokenize. */
for(i=0; i<n; i++){
if( sqlite3_fts3_enable_parentheses && (z[i]=='(' || z[i]==')') ) break;
- if( z[i]=='*' || z[i]=='"' ) break;
+ if( z[i]=='"' ) break;
}
*pnConsumed = i;
@@ -134274,13 +140528,13 @@ SQLITE_PRIVATE int sqlite3Fts3ExprParse(
sqlite3Fts3ExprFree(*ppExpr);
*ppExpr = 0;
if( rc==SQLITE_TOOBIG ){
- *pzErr = sqlite3_mprintf(
+ sqlite3Fts3ErrMsg(pzErr,
"FTS expression tree is too large (maximum depth %d)",
SQLITE_FTS3_MAX_EXPR_DEPTH
);
rc = SQLITE_ERROR;
}else if( rc==SQLITE_ERROR ){
- *pzErr = sqlite3_mprintf("malformed MATCH expression: [%s]", z);
+ sqlite3Fts3ErrMsg(pzErr, "malformed MATCH expression: [%s]", z);
}
}
@@ -135103,7 +141357,7 @@ static int isVowel(const char *z){
** by a consonant.
**
** In this routine z[] is in reverse order. So we are really looking
-** for an instance of of a consonant followed by a vowel.
+** for an instance of a consonant followed by a vowel.
*/
static int m_gt_0(const char *z){
while( isVowel(z) ){ z++; }
@@ -135653,7 +141907,7 @@ static void scalarFunc(
if( argc==2 ){
void *pOld;
int n = sqlite3_value_bytes(argv[1]);
- if( n!=sizeof(pPtr) ){
+ if( zName==0 || n!=sizeof(pPtr) ){
sqlite3_result_error(context, "argument type mismatch", -1);
return;
}
@@ -135664,7 +141918,9 @@ static void scalarFunc(
return;
}
}else{
- pPtr = sqlite3Fts3HashFind(pHash, zName, nName);
+ if( zName ){
+ pPtr = sqlite3Fts3HashFind(pHash, zName, nName);
+ }
if( !pPtr ){
char *zErr = sqlite3_mprintf("unknown tokenizer: %s", zName);
sqlite3_result_error(context, zErr, -1);
@@ -135745,12 +142001,16 @@ SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(
zEnd = &zCopy[strlen(zCopy)];
z = (char *)sqlite3Fts3NextToken(zCopy, &n);
+ if( z==0 ){
+ assert( n==0 );
+ z = zCopy;
+ }
z[n] = '\0';
sqlite3Fts3Dequote(z);
m = (sqlite3_tokenizer_module *)sqlite3Fts3HashFind(pHash,z,(int)strlen(z)+1);
if( !m ){
- *pzErr = sqlite3_mprintf("unknown tokenizer: %s", z);
+ sqlite3Fts3ErrMsg(pzErr, "unknown tokenizer: %s", z);
rc = SQLITE_ERROR;
}else{
char const **aArg = 0;
@@ -135773,7 +142033,7 @@ SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(
rc = m->xCreate(iArg, aArg, ppTok);
assert( rc!=SQLITE_OK || *ppTok );
if( rc!=SQLITE_OK ){
- *pzErr = sqlite3_mprintf("unknown tokenizer");
+ sqlite3Fts3ErrMsg(pzErr, "unknown tokenizer");
}else{
(*ppTok)->pModule = m;
}
@@ -135857,9 +142117,9 @@ static void testFunc(
p = (sqlite3_tokenizer_module *)sqlite3Fts3HashFind(pHash, zName, nName+1);
if( !p ){
- char *zErr = sqlite3_mprintf("unknown tokenizer: %s", zName);
- sqlite3_result_error(context, zErr, -1);
- sqlite3_free(zErr);
+ char *zErr2 = sqlite3_mprintf("unknown tokenizer: %s", zName);
+ sqlite3_result_error(context, zErr2, -1);
+ sqlite3_free(zErr2);
return;
}
@@ -136394,7 +142654,7 @@ static int fts3tokQueryTokenizer(
p = (sqlite3_tokenizer_module *)sqlite3Fts3HashFind(pHash, zName, nName+1);
if( !p ){
- *pzErr = sqlite3_mprintf("unknown tokenizer: %s", zName);
+ sqlite3Fts3ErrMsg(pzErr, "unknown tokenizer: %s", zName);
return SQLITE_ERROR;
}
@@ -136472,7 +142732,7 @@ static int fts3tokConnectMethod(
sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */
char **pzErr /* OUT: sqlite3_malloc'd error message */
){
- Fts3tokTable *pTab;
+ Fts3tokTable *pTab = 0;
const sqlite3_tokenizer_module *pMod = 0;
sqlite3_tokenizer *pTok = 0;
int rc;
@@ -137091,7 +143351,7 @@ static int fts3SqlStmt(
/* 25 */ "",
/* 26 */ "DELETE FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ?",
-/* 27 */ "SELECT DISTINCT level / (1024 * ?) FROM %Q.'%q_segdir'",
+/* 27 */ "SELECT ? UNION SELECT level / (1024 * ?) FROM %Q.'%q_segdir'",
/* This statement is used to determine which level to read the input from
** when performing an incremental merge. It returns the absolute level number
@@ -138390,7 +144650,10 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(
** an array of pending terms by term. This occurs as part of flushing
** the contents of the pending-terms hash table to the database.
*/
-static int fts3CompareElemByTerm(const void *lhs, const void *rhs){
+static int SQLITE_CDECL fts3CompareElemByTerm(
+ const void *lhs,
+ const void *rhs
+){
char *z1 = fts3HashKey(*(Fts3HashElem **)lhs);
char *z2 = fts3HashKey(*(Fts3HashElem **)rhs);
int n1 = fts3HashKeysize(*(Fts3HashElem **)lhs);
@@ -139847,8 +146110,8 @@ static int fts3PromoteSegments(
if( bOk ){
int iIdx = 0;
- sqlite3_stmt *pUpdate1;
- sqlite3_stmt *pUpdate2;
+ sqlite3_stmt *pUpdate1 = 0;
+ sqlite3_stmt *pUpdate2 = 0;
if( rc==SQLITE_OK ){
rc = fts3SqlStmt(p, SQL_UPDATE_LEVEL_IDX, &pUpdate1, 0);
@@ -140206,7 +146469,8 @@ static int fts3DoOptimize(Fts3Table *p, int bReturnDone){
rc = fts3SqlStmt(p, SQL_SELECT_ALL_LANGID, &pAllLangid, 0);
if( rc==SQLITE_OK ){
int rc2;
- sqlite3_bind_int(pAllLangid, 1, p->nIndex);
+ sqlite3_bind_int(pAllLangid, 1, p->iPrevLangid);
+ sqlite3_bind_int(pAllLangid, 2, p->nIndex);
while( sqlite3_step(pAllLangid)==SQLITE_ROW ){
int i;
int iLangid = sqlite3_column_int(pAllLangid, 0);
@@ -141538,7 +147802,7 @@ static int fts3IncrmergeHintPop(Blob *pHint, i64 *piAbsLevel, int *pnInput){
pHint->n = i;
i += sqlite3Fts3GetVarint(&pHint->a[i], piAbsLevel);
i += fts3GetVarint32(&pHint->a[i], pnInput);
- if( i!=nHint ) return SQLITE_CORRUPT_VTAB;
+ if( i!=nHint ) return FTS_CORRUPT_VTAB;
return SQLITE_OK;
}
@@ -141906,7 +148170,8 @@ static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){
rc = fts3SqlStmt(p, SQL_SELECT_ALL_LANGID, &pAllLangid, 0);
if( rc==SQLITE_OK ){
int rc2;
- sqlite3_bind_int(pAllLangid, 1, p->nIndex);
+ sqlite3_bind_int(pAllLangid, 1, p->iPrevLangid);
+ sqlite3_bind_int(pAllLangid, 2, p->nIndex);
while( rc==SQLITE_OK && sqlite3_step(pAllLangid)==SQLITE_ROW ){
int iLangid = sqlite3_column_int(pAllLangid, 0);
int i;
@@ -141919,7 +148184,6 @@ static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){
}
/* This block calculates the checksum according to the %_content table */
- rc = fts3SqlStmt(p, SQL_SELECT_ALL_LANGID, &pAllLangid, 0);
if( rc==SQLITE_OK ){
sqlite3_tokenizer_module const *pModule = p->pTokenizer->pModule;
sqlite3_stmt *pStmt = 0;
@@ -142016,7 +148280,7 @@ static int fts3DoIntegrityCheck(
int rc;
int bOk = 0;
rc = fts3IntegrityCheck(p, &bOk);
- if( rc==SQLITE_OK && bOk==0 ) rc = SQLITE_CORRUPT_VTAB;
+ if( rc==SQLITE_OK && bOk==0 ) rc = FTS_CORRUPT_VTAB;
return rc;
}
@@ -142454,6 +148718,7 @@ SQLITE_PRIVATE int sqlite3Fts3Optimize(Fts3Table *p){
#define FTS3_MATCHINFO_LENGTH 'l' /* nCol values */
#define FTS3_MATCHINFO_LCS 's' /* nCol values */
#define FTS3_MATCHINFO_HITS 'x' /* 3*nCol*nPhrase values */
+#define FTS3_MATCHINFO_LHITS 'y' /* nCol*nPhrase values */
/*
** The default value for the second argument to matchinfo().
@@ -142869,37 +149134,39 @@ static int fts3BestSnippet(
sIter.nSnippet = nSnippet;
sIter.nPhrase = nList;
sIter.iCurrent = -1;
- (void)fts3ExprIterate(pCsr->pExpr, fts3SnippetFindPositions, (void *)&sIter);
+ rc = fts3ExprIterate(pCsr->pExpr, fts3SnippetFindPositions, (void *)&sIter);
+ if( rc==SQLITE_OK ){
- /* Set the *pmSeen output variable. */
- for(i=0; i<nList; i++){
- if( sIter.aPhrase[i].pHead ){
- *pmSeen |= (u64)1 << i;
+ /* Set the *pmSeen output variable. */
+ for(i=0; i<nList; i++){
+ if( sIter.aPhrase[i].pHead ){
+ *pmSeen |= (u64)1 << i;
+ }
}
- }
- /* Loop through all candidate snippets. Store the best snippet in
- ** *pFragment. Store its associated 'score' in iBestScore.
- */
- pFragment->iCol = iCol;
- while( !fts3SnippetNextCandidate(&sIter) ){
- int iPos;
- int iScore;
- u64 mCover;
- u64 mHighlight;
- fts3SnippetDetails(&sIter, mCovered, &iPos, &iScore, &mCover, &mHighlight);
- assert( iScore>=0 );
- if( iScore>iBestScore ){
- pFragment->iPos = iPos;
- pFragment->hlmask = mHighlight;
- pFragment->covered = mCover;
- iBestScore = iScore;
+ /* Loop through all candidate snippets. Store the best snippet in
+ ** *pFragment. Store its associated 'score' in iBestScore.
+ */
+ pFragment->iCol = iCol;
+ while( !fts3SnippetNextCandidate(&sIter) ){
+ int iPos;
+ int iScore;
+ u64 mCover;
+ u64 mHighlite;
+ fts3SnippetDetails(&sIter, mCovered, &iPos, &iScore, &mCover,&mHighlite);
+ assert( iScore>=0 );
+ if( iScore>iBestScore ){
+ pFragment->iPos = iPos;
+ pFragment->hlmask = mHighlite;
+ pFragment->covered = mCover;
+ iBestScore = iScore;
+ }
}
- }
+ *piScore = iBestScore;
+ }
sqlite3_free(sIter.aPhrase);
- *piScore = iBestScore;
- return SQLITE_OK;
+ return rc;
}
@@ -143107,8 +149374,12 @@ static int fts3SnippetText(
** required. They are required if (a) this is not the first fragment,
** or (b) this fragment does not begin at position 0 of its column.
*/
- if( rc==SQLITE_OK && (iPos>0 || iFragment>0) ){
- rc = fts3StringAppend(pOut, zEllipsis, -1);
+ if( rc==SQLITE_OK ){
+ if( iPos>0 || iFragment>0 ){
+ rc = fts3StringAppend(pOut, zEllipsis, -1);
+ }else if( iBegin ){
+ rc = fts3StringAppend(pOut, zDoc, iBegin);
+ }
}
if( rc!=SQLITE_OK || iCurrent<iPos ) continue;
}
@@ -143230,6 +149501,51 @@ static int fts3ExprLocalHitsCb(
return rc;
}
+/*
+** fts3ExprIterate() callback used to gather information for the matchinfo
+** directive 'y'.
+*/
+static int fts3ExprLHitsCb(
+ Fts3Expr *pExpr, /* Phrase expression node */
+ int iPhrase, /* Phrase number */
+ void *pCtx /* Pointer to MatchInfo structure */
+){
+ MatchInfo *p = (MatchInfo *)pCtx;
+ Fts3Table *pTab = (Fts3Table *)p->pCursor->base.pVtab;
+ int rc = SQLITE_OK;
+ int iStart = iPhrase * p->nCol;
+ Fts3Expr *pEof; /* Ancestor node already at EOF */
+
+ /* This must be a phrase */
+ assert( pExpr->pPhrase );
+
+ /* Initialize all output integers to zero. */
+ memset(&p->aMatchinfo[iStart], 0, sizeof(u32) * p->nCol);
+
+ /* Check if this or any parent node is at EOF. If so, then all output
+ ** values are zero. */
+ for(pEof=pExpr; pEof && pEof->bEof==0; pEof=pEof->pParent);
+
+ if( pEof==0 && pExpr->iDocid==p->pCursor->iPrevId ){
+ Fts3Phrase *pPhrase = pExpr->pPhrase;
+ char *pIter = pPhrase->doclist.pList;
+ int iCol = 0;
+
+ while( 1 ){
+ int nHit = fts3ColumnlistCount(&pIter);
+ if( (pPhrase->iColumn>=pTab->nColumn || pPhrase->iColumn==iCol) ){
+ p->aMatchinfo[iStart + iCol] = (u32)nHit;
+ }
+ assert( *pIter==0x00 || *pIter==0x01 );
+ if( *pIter!=0x01 ) break;
+ pIter++;
+ pIter += fts3GetVarint32(pIter, &iCol);
+ }
+ }
+
+ return rc;
+}
+
static int fts3MatchinfoCheck(
Fts3Table *pTab,
char cArg,
@@ -143242,10 +149558,11 @@ static int fts3MatchinfoCheck(
|| (cArg==FTS3_MATCHINFO_LENGTH && pTab->bHasDocsize)
|| (cArg==FTS3_MATCHINFO_LCS)
|| (cArg==FTS3_MATCHINFO_HITS)
+ || (cArg==FTS3_MATCHINFO_LHITS)
){
return SQLITE_OK;
}
- *pzErr = sqlite3_mprintf("unrecognized matchinfo request: %c", cArg);
+ sqlite3Fts3ErrMsg(pzErr, "unrecognized matchinfo request: %c", cArg);
return SQLITE_ERROR;
}
@@ -143265,6 +149582,10 @@ static int fts3MatchinfoSize(MatchInfo *pInfo, char cArg){
nVal = pInfo->nCol;
break;
+ case FTS3_MATCHINFO_LHITS:
+ nVal = pInfo->nCol * pInfo->nPhrase;
+ break;
+
default:
assert( cArg==FTS3_MATCHINFO_HITS );
nVal = pInfo->nCol * pInfo->nPhrase * 3;
@@ -143519,6 +149840,10 @@ static int fts3MatchinfoValues(
}
break;
+ case FTS3_MATCHINFO_LHITS:
+ (void)fts3ExprIterate(pCsr->pExpr, fts3ExprLHitsCb, (void*)pInfo);
+ break;
+
default: {
Fts3Expr *pExpr;
assert( zArg[i]==FTS3_MATCHINFO_HITS );
@@ -143674,7 +149999,7 @@ SQLITE_PRIVATE void sqlite3Fts3Snippet(
*/
for(iRead=0; iRead<pTab->nColumn; iRead++){
SnippetFragment sF = {0, 0, 0, 0};
- int iS;
+ int iS = 0;
if( iCol>=0 && iRead!=iCol ) continue;
/* Find the best snippet of nFToken tokens in column iRead. */
@@ -145080,13 +151405,12 @@ static int readInt16(u8 *p){
return (p[0]<<8) + p[1];
}
static void readCoord(u8 *p, RtreeCoord *pCoord){
- u32 i = (
+ pCoord->u = (
(((u32)p[0]) << 24) +
(((u32)p[1]) << 16) +
(((u32)p[2]) << 8) +
(((u32)p[3]) << 0)
);
- *(u32 *)pCoord = i;
}
static i64 readInt64(u8 *p){
return (
@@ -145115,7 +151439,7 @@ static int writeCoord(u8 *p, RtreeCoord *pCoord){
u32 i;
assert( sizeof(RtreeCoord)==4 );
assert( sizeof(u32)==4 );
- i = *(u32 *)pCoord;
+ i = pCoord->u;
p[0] = (i>>24)&0xFF;
p[1] = (i>>16)&0xFF;
p[2] = (i>> 8)&0xFF;
@@ -145446,14 +151770,13 @@ static void nodeGetCell(
RtreeCell *pCell /* OUT: Write the cell contents here */
){
u8 *pData;
- u8 *pEnd;
RtreeCoord *pCoord;
+ int ii;
pCell->iRowid = nodeGetRowid(pRtree, pNode, iCell);
pData = pNode->zData + (12 + pRtree->nBytesPerCell*iCell);
- pEnd = pData + pRtree->nDim*8;
pCoord = pCell->aCoord;
- for(; pData<pEnd; pData+=4, pCoord++){
- readCoord(pData, pCoord);
+ for(ii=0; ii<pRtree->nDim*2; ii++){
+ readCoord(&pData[ii*4], &pCoord[ii]);
}
}
@@ -145893,7 +152216,7 @@ static RtreeSearchPoint *rtreeEnqueue(
pNew = pCur->aPoint + i;
pNew->rScore = rScore;
pNew->iLevel = iLevel;
- assert( iLevel>=0 && iLevel<=RTREE_MAX_DEPTH );
+ assert( iLevel<=RTREE_MAX_DEPTH );
while( i>0 ){
RtreeSearchPoint *pParent;
j = (i-1)/2;
@@ -147517,6 +153840,8 @@ static int rtreeUpdate(
rtreeReference(pRtree);
assert(nData>=1);
+ cell.iRowid = 0; /* Used only to suppress a compiler warning */
+
/* Constraint handling. A write operation on an r-tree table may return
** SQLITE_CONSTRAINT for two reasons:
**
@@ -147531,11 +153856,19 @@ static int rtreeUpdate(
if( nData>1 ){
int ii;
- /* Populate the cell.aCoord[] array. The first coordinate is azData[3]. */
- assert( nData==(pRtree->nDim*2 + 3) );
+ /* Populate the cell.aCoord[] array. The first coordinate is azData[3].
+ **
+ ** NB: nData can only be less than nDim*2+3 if the rtree is mis-declared
+ ** with "column" that are interpreted as table constraints.
+ ** Example: CREATE VIRTUAL TABLE bad USING rtree(x,y,CHECK(y>5));
+ ** This problem was discovered after years of use, so we silently ignore
+ ** these kinds of misdeclared tables to avoid breaking any legacy.
+ */
+ assert( nData<=(pRtree->nDim*2 + 3) );
+
#ifndef SQLITE_RTREE_INT_ONLY
if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
- for(ii=0; ii<(pRtree->nDim*2); ii+=2){
+ for(ii=0; ii<nData-4; ii+=2){
cell.aCoord[ii].f = rtreeValueDown(azData[ii+3]);
cell.aCoord[ii+1].f = rtreeValueUp(azData[ii+4]);
if( cell.aCoord[ii].f>cell.aCoord[ii+1].f ){
@@ -147546,7 +153879,7 @@ static int rtreeUpdate(
}else
#endif
{
- for(ii=0; ii<(pRtree->nDim*2); ii+=2){
+ for(ii=0; ii<nData-4; ii+=2){
cell.aCoord[ii].i = sqlite3_value_int(azData[ii+3]);
cell.aCoord[ii+1].i = sqlite3_value_int(azData[ii+4]);
if( cell.aCoord[ii].i>cell.aCoord[ii+1].i ){
@@ -148117,7 +154450,7 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
/*
** Register a new geometry function for use with the r-tree MATCH operator.
*/
-SQLITE_API int sqlite3_rtree_geometry_callback(
+SQLITE_API int SQLITE_STDCALL sqlite3_rtree_geometry_callback(
sqlite3 *db, /* Register SQL function on this connection */
const char *zGeom, /* Name of the new SQL function */
int (*xGeom)(sqlite3_rtree_geometry*,int,RtreeDValue*,int*), /* Callback */
@@ -148141,7 +154474,7 @@ SQLITE_API int sqlite3_rtree_geometry_callback(
** Register a new 2nd-generation geometry function for use with the
** r-tree MATCH operator.
*/
-SQLITE_API int sqlite3_rtree_query_callback(
+SQLITE_API int SQLITE_STDCALL sqlite3_rtree_query_callback(
sqlite3 *db, /* Register SQL function on this connection */
const char *zQueryFunc, /* Name of new SQL function */
int (*xQueryFunc)(sqlite3_rtree_query_info*), /* Callback */
@@ -148166,7 +154499,7 @@ SQLITE_API int sqlite3_rtree_query_callback(
#ifdef _WIN32
__declspec(dllexport)
#endif
-SQLITE_API int sqlite3_rtree_init(
+SQLITE_API int SQLITE_STDCALL sqlite3_rtree_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
@@ -148671,7 +155004,7 @@ SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db){
#ifdef _WIN32
__declspec(dllexport)
#endif
-SQLITE_API int sqlite3_icu_init(
+SQLITE_API int SQLITE_STDCALL sqlite3_icu_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
@@ -148946,3 +155279,654 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */
/************** End of fts3_icu.c ********************************************/
+/************** Begin file dbstat.c ******************************************/
+/*
+** 2010 July 12
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This file contains an implementation of the "dbstat" virtual table.
+**
+** The dbstat virtual table is used to extract low-level formatting
+** information from an SQLite database in order to implement the
+** "sqlite3_analyzer" utility. See the ../tool/spaceanal.tcl script
+** for an example implementation.
+*/
+
+#if (defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST)) \
+ && !defined(SQLITE_OMIT_VIRTUALTABLE)
+
+/*
+** Page paths:
+**
+** The value of the 'path' column describes the path taken from the
+** root-node of the b-tree structure to each page. The value of the
+** root-node path is '/'.
+**
+** The value of the path for the left-most child page of the root of
+** a b-tree is '/000/'. (Btrees store content ordered from left to right
+** so the pages to the left have smaller keys than the pages to the right.)
+** The next to left-most child of the root page is
+** '/001', and so on, each sibling page identified by a 3-digit hex
+** value. The children of the 451st left-most sibling have paths such
+** as '/1c2/000/, '/1c2/001/' etc.
+**
+** Overflow pages are specified by appending a '+' character and a
+** six-digit hexadecimal value to the path to the cell they are linked
+** from. For example, the three overflow pages in a chain linked from
+** the left-most cell of the 450th child of the root page are identified
+** by the paths:
+**
+** '/1c2/000+000000' // First page in overflow chain
+** '/1c2/000+000001' // Second page in overflow chain
+** '/1c2/000+000002' // Third page in overflow chain
+**
+** If the paths are sorted using the BINARY collation sequence, then
+** the overflow pages associated with a cell will appear earlier in the
+** sort-order than its child page:
+**
+** '/1c2/000/' // Left-most child of 451st child of root
+*/
+#define VTAB_SCHEMA \
+ "CREATE TABLE xx( " \
+ " name STRING, /* Name of table or index */" \
+ " path INTEGER, /* Path to page from root */" \
+ " pageno INTEGER, /* Page number */" \
+ " pagetype STRING, /* 'internal', 'leaf' or 'overflow' */" \
+ " ncell INTEGER, /* Cells on page (0 for overflow) */" \
+ " payload INTEGER, /* Bytes of payload on this page */" \
+ " unused INTEGER, /* Bytes of unused space on this page */" \
+ " mx_payload INTEGER, /* Largest payload size of all cells */" \
+ " pgoffset INTEGER, /* Offset of page in file */" \
+ " pgsize INTEGER /* Size of the page */" \
+ ");"
+
+
+typedef struct StatTable StatTable;
+typedef struct StatCursor StatCursor;
+typedef struct StatPage StatPage;
+typedef struct StatCell StatCell;
+
+struct StatCell {
+ int nLocal; /* Bytes of local payload */
+ u32 iChildPg; /* Child node (or 0 if this is a leaf) */
+ int nOvfl; /* Entries in aOvfl[] */
+ u32 *aOvfl; /* Array of overflow page numbers */
+ int nLastOvfl; /* Bytes of payload on final overflow page */
+ int iOvfl; /* Iterates through aOvfl[] */
+};
+
+struct StatPage {
+ u32 iPgno;
+ DbPage *pPg;
+ int iCell;
+
+ char *zPath; /* Path to this page */
+
+ /* Variables populated by statDecodePage(): */
+ u8 flags; /* Copy of flags byte */
+ int nCell; /* Number of cells on page */
+ int nUnused; /* Number of unused bytes on page */
+ StatCell *aCell; /* Array of parsed cells */
+ u32 iRightChildPg; /* Right-child page number (or 0) */
+ int nMxPayload; /* Largest payload of any cell on this page */
+};
+
+struct StatCursor {
+ sqlite3_vtab_cursor base;
+ sqlite3_stmt *pStmt; /* Iterates through set of root pages */
+ int isEof; /* After pStmt has returned SQLITE_DONE */
+
+ StatPage aPage[32];
+ int iPage; /* Current entry in aPage[] */
+
+ /* Values to return. */
+ char *zName; /* Value of 'name' column */
+ char *zPath; /* Value of 'path' column */
+ u32 iPageno; /* Value of 'pageno' column */
+ char *zPagetype; /* Value of 'pagetype' column */
+ int nCell; /* Value of 'ncell' column */
+ int nPayload; /* Value of 'payload' column */
+ int nUnused; /* Value of 'unused' column */
+ int nMxPayload; /* Value of 'mx_payload' column */
+ i64 iOffset; /* Value of 'pgOffset' column */
+ int szPage; /* Value of 'pgSize' column */
+};
+
+struct StatTable {
+ sqlite3_vtab base;
+ sqlite3 *db;
+ int iDb; /* Index of database to analyze */
+};
+
+#ifndef get2byte
+# define get2byte(x) ((x)[0]<<8 | (x)[1])
+#endif
+
+/*
+** Connect to or create a statvfs virtual table.
+*/
+static int statConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ StatTable *pTab = 0;
+ int rc = SQLITE_OK;
+ int iDb;
+
+ if( argc>=4 ){
+ iDb = sqlite3FindDbName(db, argv[3]);
+ if( iDb<0 ){
+ *pzErr = sqlite3_mprintf("no such database: %s", argv[3]);
+ return SQLITE_ERROR;
+ }
+ }else{
+ iDb = 0;
+ }
+ rc = sqlite3_declare_vtab(db, VTAB_SCHEMA);
+ if( rc==SQLITE_OK ){
+ pTab = (StatTable *)sqlite3_malloc64(sizeof(StatTable));
+ if( pTab==0 ) rc = SQLITE_NOMEM;
+ }
+
+ assert( rc==SQLITE_OK || pTab==0 );
+ if( rc==SQLITE_OK ){
+ memset(pTab, 0, sizeof(StatTable));
+ pTab->db = db;
+ pTab->iDb = iDb;
+ }
+
+ *ppVtab = (sqlite3_vtab*)pTab;
+ return rc;
+}
+
+/*
+** Disconnect from or destroy a statvfs virtual table.
+*/
+static int statDisconnect(sqlite3_vtab *pVtab){
+ sqlite3_free(pVtab);
+ return SQLITE_OK;
+}
+
+/*
+** There is no "best-index". This virtual table always does a linear
+** scan of the binary VFS log file.
+*/
+static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
+
+ /* Records are always returned in ascending order of (name, path).
+ ** If this will satisfy the client, set the orderByConsumed flag so that
+ ** SQLite does not do an external sort.
+ */
+ if( ( pIdxInfo->nOrderBy==1
+ && pIdxInfo->aOrderBy[0].iColumn==0
+ && pIdxInfo->aOrderBy[0].desc==0
+ ) ||
+ ( pIdxInfo->nOrderBy==2
+ && pIdxInfo->aOrderBy[0].iColumn==0
+ && pIdxInfo->aOrderBy[0].desc==0
+ && pIdxInfo->aOrderBy[1].iColumn==1
+ && pIdxInfo->aOrderBy[1].desc==0
+ )
+ ){
+ pIdxInfo->orderByConsumed = 1;
+ }
+
+ pIdxInfo->estimatedCost = 10.0;
+ return SQLITE_OK;
+}
+
+/*
+** Open a new statvfs cursor.
+*/
+static int statOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
+ StatTable *pTab = (StatTable *)pVTab;
+ StatCursor *pCsr;
+ int rc;
+
+ pCsr = (StatCursor *)sqlite3_malloc64(sizeof(StatCursor));
+ if( pCsr==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ char *zSql;
+ memset(pCsr, 0, sizeof(StatCursor));
+ pCsr->base.pVtab = pVTab;
+
+ zSql = sqlite3_mprintf(
+ "SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type"
+ " UNION ALL "
+ "SELECT name, rootpage, type"
+ " FROM \"%w\".sqlite_master WHERE rootpage!=0"
+ " ORDER BY name", pTab->db->aDb[pTab->iDb].zName);
+ if( zSql==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
+ sqlite3_free(zSql);
+ }
+ if( rc!=SQLITE_OK ){
+ sqlite3_free(pCsr);
+ pCsr = 0;
+ }
+ }
+
+ *ppCursor = (sqlite3_vtab_cursor *)pCsr;
+ return rc;
+}
+
+static void statClearPage(StatPage *p){
+ int i;
+ if( p->aCell ){
+ for(i=0; i<p->nCell; i++){
+ sqlite3_free(p->aCell[i].aOvfl);
+ }
+ sqlite3_free(p->aCell);
+ }
+ sqlite3PagerUnref(p->pPg);
+ sqlite3_free(p->zPath);
+ memset(p, 0, sizeof(StatPage));
+}
+
+static void statResetCsr(StatCursor *pCsr){
+ int i;
+ sqlite3_reset(pCsr->pStmt);
+ for(i=0; i<ArraySize(pCsr->aPage); i++){
+ statClearPage(&pCsr->aPage[i]);
+ }
+ pCsr->iPage = 0;
+ sqlite3_free(pCsr->zPath);
+ pCsr->zPath = 0;
+}
+
+/*
+** Close a statvfs cursor.
+*/
+static int statClose(sqlite3_vtab_cursor *pCursor){
+ StatCursor *pCsr = (StatCursor *)pCursor;
+ statResetCsr(pCsr);
+ sqlite3_finalize(pCsr->pStmt);
+ sqlite3_free(pCsr);
+ return SQLITE_OK;
+}
+
+static void getLocalPayload(
+ int nUsable, /* Usable bytes per page */
+ u8 flags, /* Page flags */
+ int nTotal, /* Total record (payload) size */
+ int *pnLocal /* OUT: Bytes stored locally */
+){
+ int nLocal;
+ int nMinLocal;
+ int nMaxLocal;
+
+ if( flags==0x0D ){ /* Table leaf node */
+ nMinLocal = (nUsable - 12) * 32 / 255 - 23;
+ nMaxLocal = nUsable - 35;
+ }else{ /* Index interior and leaf nodes */
+ nMinLocal = (nUsable - 12) * 32 / 255 - 23;
+ nMaxLocal = (nUsable - 12) * 64 / 255 - 23;
+ }
+
+ nLocal = nMinLocal + (nTotal - nMinLocal) % (nUsable - 4);
+ if( nLocal>nMaxLocal ) nLocal = nMinLocal;
+ *pnLocal = nLocal;
+}
+
+static int statDecodePage(Btree *pBt, StatPage *p){
+ int nUnused;
+ int iOff;
+ int nHdr;
+ int isLeaf;
+ int szPage;
+
+ u8 *aData = sqlite3PagerGetData(p->pPg);
+ u8 *aHdr = &aData[p->iPgno==1 ? 100 : 0];
+
+ p->flags = aHdr[0];
+ p->nCell = get2byte(&aHdr[3]);
+ p->nMxPayload = 0;
+
+ isLeaf = (p->flags==0x0A || p->flags==0x0D);
+ nHdr = 12 - isLeaf*4 + (p->iPgno==1)*100;
+
+ nUnused = get2byte(&aHdr[5]) - nHdr - 2*p->nCell;
+ nUnused += (int)aHdr[7];
+ iOff = get2byte(&aHdr[1]);
+ while( iOff ){
+ nUnused += get2byte(&aData[iOff+2]);
+ iOff = get2byte(&aData[iOff]);
+ }
+ p->nUnused = nUnused;
+ p->iRightChildPg = isLeaf ? 0 : sqlite3Get4byte(&aHdr[8]);
+ szPage = sqlite3BtreeGetPageSize(pBt);
+
+ if( p->nCell ){
+ int i; /* Used to iterate through cells */
+ int nUsable; /* Usable bytes per page */
+
+ sqlite3BtreeEnter(pBt);
+ nUsable = szPage - sqlite3BtreeGetReserveNoMutex(pBt);
+ sqlite3BtreeLeave(pBt);
+ p->aCell = sqlite3_malloc64((p->nCell+1) * sizeof(StatCell));
+ if( p->aCell==0 ) return SQLITE_NOMEM;
+ memset(p->aCell, 0, (p->nCell+1) * sizeof(StatCell));
+
+ for(i=0; i<p->nCell; i++){
+ StatCell *pCell = &p->aCell[i];
+
+ iOff = get2byte(&aData[nHdr+i*2]);
+ if( !isLeaf ){
+ pCell->iChildPg = sqlite3Get4byte(&aData[iOff]);
+ iOff += 4;
+ }
+ if( p->flags==0x05 ){
+ /* A table interior node. nPayload==0. */
+ }else{
+ u32 nPayload; /* Bytes of payload total (local+overflow) */
+ int nLocal; /* Bytes of payload stored locally */
+ iOff += getVarint32(&aData[iOff], nPayload);
+ if( p->flags==0x0D ){
+ u64 dummy;
+ iOff += sqlite3GetVarint(&aData[iOff], &dummy);
+ }
+ if( nPayload>(u32)p->nMxPayload ) p->nMxPayload = nPayload;
+ getLocalPayload(nUsable, p->flags, nPayload, &nLocal);
+ pCell->nLocal = nLocal;
+ assert( nLocal>=0 );
+ assert( nPayload>=(u32)nLocal );
+ assert( nLocal<=(nUsable-35) );
+ if( nPayload>(u32)nLocal ){
+ int j;
+ int nOvfl = ((nPayload - nLocal) + nUsable-4 - 1) / (nUsable - 4);
+ pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4);
+ pCell->nOvfl = nOvfl;
+ pCell->aOvfl = sqlite3_malloc64(sizeof(u32)*nOvfl);
+ if( pCell->aOvfl==0 ) return SQLITE_NOMEM;
+ pCell->aOvfl[0] = sqlite3Get4byte(&aData[iOff+nLocal]);
+ for(j=1; j<nOvfl; j++){
+ int rc;
+ u32 iPrev = pCell->aOvfl[j-1];
+ DbPage *pPg = 0;
+ rc = sqlite3PagerGet(sqlite3BtreePager(pBt), iPrev, &pPg);
+ if( rc!=SQLITE_OK ){
+ assert( pPg==0 );
+ return rc;
+ }
+ pCell->aOvfl[j] = sqlite3Get4byte(sqlite3PagerGetData(pPg));
+ sqlite3PagerUnref(pPg);
+ }
+ }
+ }
+ }
+ }
+
+ return SQLITE_OK;
+}
+
+/*
+** Populate the pCsr->iOffset and pCsr->szPage member variables. Based on
+** the current value of pCsr->iPageno.
+*/
+static void statSizeAndOffset(StatCursor *pCsr){
+ StatTable *pTab = (StatTable *)((sqlite3_vtab_cursor *)pCsr)->pVtab;
+ Btree *pBt = pTab->db->aDb[pTab->iDb].pBt;
+ Pager *pPager = sqlite3BtreePager(pBt);
+ sqlite3_file *fd;
+ sqlite3_int64 x[2];
+
+ /* The default page size and offset */
+ pCsr->szPage = sqlite3BtreeGetPageSize(pBt);
+ pCsr->iOffset = (i64)pCsr->szPage * (pCsr->iPageno - 1);
+
+ /* If connected to a ZIPVFS backend, override the page size and
+ ** offset with actual values obtained from ZIPVFS.
+ */
+ fd = sqlite3PagerFile(pPager);
+ x[0] = pCsr->iPageno;
+ if( fd->pMethods!=0 && sqlite3OsFileControl(fd, 230440, &x)==SQLITE_OK ){
+ pCsr->iOffset = x[0];
+ pCsr->szPage = (int)x[1];
+ }
+}
+
+/*
+** Move a statvfs cursor to the next entry in the file.
+*/
+static int statNext(sqlite3_vtab_cursor *pCursor){
+ int rc;
+ int nPayload;
+ char *z;
+ StatCursor *pCsr = (StatCursor *)pCursor;
+ StatTable *pTab = (StatTable *)pCursor->pVtab;
+ Btree *pBt = pTab->db->aDb[pTab->iDb].pBt;
+ Pager *pPager = sqlite3BtreePager(pBt);
+
+ sqlite3_free(pCsr->zPath);
+ pCsr->zPath = 0;
+
+statNextRestart:
+ if( pCsr->aPage[0].pPg==0 ){
+ rc = sqlite3_step(pCsr->pStmt);
+ if( rc==SQLITE_ROW ){
+ int nPage;
+ u32 iRoot = (u32)sqlite3_column_int64(pCsr->pStmt, 1);
+ sqlite3PagerPagecount(pPager, &nPage);
+ if( nPage==0 ){
+ pCsr->isEof = 1;
+ return sqlite3_reset(pCsr->pStmt);
+ }
+ rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg);
+ pCsr->aPage[0].iPgno = iRoot;
+ pCsr->aPage[0].iCell = 0;
+ pCsr->aPage[0].zPath = z = sqlite3_mprintf("/");
+ pCsr->iPage = 0;
+ if( z==0 ) rc = SQLITE_NOMEM;
+ }else{
+ pCsr->isEof = 1;
+ return sqlite3_reset(pCsr->pStmt);
+ }
+ }else{
+
+ /* Page p itself has already been visited. */
+ StatPage *p = &pCsr->aPage[pCsr->iPage];
+
+ while( p->iCell<p->nCell ){
+ StatCell *pCell = &p->aCell[p->iCell];
+ if( pCell->iOvfl<pCell->nOvfl ){
+ int nUsable;
+ sqlite3BtreeEnter(pBt);
+ nUsable = sqlite3BtreeGetPageSize(pBt) -
+ sqlite3BtreeGetReserveNoMutex(pBt);
+ sqlite3BtreeLeave(pBt);
+ pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0);
+ pCsr->iPageno = pCell->aOvfl[pCell->iOvfl];
+ pCsr->zPagetype = "overflow";
+ pCsr->nCell = 0;
+ pCsr->nMxPayload = 0;
+ pCsr->zPath = z = sqlite3_mprintf(
+ "%s%.3x+%.6x", p->zPath, p->iCell, pCell->iOvfl
+ );
+ if( pCell->iOvfl<pCell->nOvfl-1 ){
+ pCsr->nUnused = 0;
+ pCsr->nPayload = nUsable - 4;
+ }else{
+ pCsr->nPayload = pCell->nLastOvfl;
+ pCsr->nUnused = nUsable - 4 - pCsr->nPayload;
+ }
+ pCell->iOvfl++;
+ statSizeAndOffset(pCsr);
+ return z==0 ? SQLITE_NOMEM : SQLITE_OK;
+ }
+ if( p->iRightChildPg ) break;
+ p->iCell++;
+ }
+
+ if( !p->iRightChildPg || p->iCell>p->nCell ){
+ statClearPage(p);
+ if( pCsr->iPage==0 ) return statNext(pCursor);
+ pCsr->iPage--;
+ goto statNextRestart; /* Tail recursion */
+ }
+ pCsr->iPage++;
+ assert( p==&pCsr->aPage[pCsr->iPage-1] );
+
+ if( p->iCell==p->nCell ){
+ p[1].iPgno = p->iRightChildPg;
+ }else{
+ p[1].iPgno = p->aCell[p->iCell].iChildPg;
+ }
+ rc = sqlite3PagerGet(pPager, p[1].iPgno, &p[1].pPg);
+ p[1].iCell = 0;
+ p[1].zPath = z = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell);
+ p->iCell++;
+ if( z==0 ) rc = SQLITE_NOMEM;
+ }
+
+
+ /* Populate the StatCursor fields with the values to be returned
+ ** by the xColumn() and xRowid() methods.
+ */
+ if( rc==SQLITE_OK ){
+ int i;
+ StatPage *p = &pCsr->aPage[pCsr->iPage];
+ pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0);
+ pCsr->iPageno = p->iPgno;
+
+ rc = statDecodePage(pBt, p);
+ if( rc==SQLITE_OK ){
+ statSizeAndOffset(pCsr);
+
+ switch( p->flags ){
+ case 0x05: /* table internal */
+ case 0x02: /* index internal */
+ pCsr->zPagetype = "internal";
+ break;
+ case 0x0D: /* table leaf */
+ case 0x0A: /* index leaf */
+ pCsr->zPagetype = "leaf";
+ break;
+ default:
+ pCsr->zPagetype = "corrupted";
+ break;
+ }
+ pCsr->nCell = p->nCell;
+ pCsr->nUnused = p->nUnused;
+ pCsr->nMxPayload = p->nMxPayload;
+ pCsr->zPath = z = sqlite3_mprintf("%s", p->zPath);
+ if( z==0 ) rc = SQLITE_NOMEM;
+ nPayload = 0;
+ for(i=0; i<p->nCell; i++){
+ nPayload += p->aCell[i].nLocal;
+ }
+ pCsr->nPayload = nPayload;
+ }
+ }
+
+ return rc;
+}
+
+static int statEof(sqlite3_vtab_cursor *pCursor){
+ StatCursor *pCsr = (StatCursor *)pCursor;
+ return pCsr->isEof;
+}
+
+static int statFilter(
+ sqlite3_vtab_cursor *pCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ StatCursor *pCsr = (StatCursor *)pCursor;
+
+ statResetCsr(pCsr);
+ return statNext(pCursor);
+}
+
+static int statColumn(
+ sqlite3_vtab_cursor *pCursor,
+ sqlite3_context *ctx,
+ int i
+){
+ StatCursor *pCsr = (StatCursor *)pCursor;
+ switch( i ){
+ case 0: /* name */
+ sqlite3_result_text(ctx, pCsr->zName, -1, SQLITE_TRANSIENT);
+ break;
+ case 1: /* path */
+ sqlite3_result_text(ctx, pCsr->zPath, -1, SQLITE_TRANSIENT);
+ break;
+ case 2: /* pageno */
+ sqlite3_result_int64(ctx, pCsr->iPageno);
+ break;
+ case 3: /* pagetype */
+ sqlite3_result_text(ctx, pCsr->zPagetype, -1, SQLITE_STATIC);
+ break;
+ case 4: /* ncell */
+ sqlite3_result_int(ctx, pCsr->nCell);
+ break;
+ case 5: /* payload */
+ sqlite3_result_int(ctx, pCsr->nPayload);
+ break;
+ case 6: /* unused */
+ sqlite3_result_int(ctx, pCsr->nUnused);
+ break;
+ case 7: /* mx_payload */
+ sqlite3_result_int(ctx, pCsr->nMxPayload);
+ break;
+ case 8: /* pgoffset */
+ sqlite3_result_int64(ctx, pCsr->iOffset);
+ break;
+ default: /* pgsize */
+ assert( i==9 );
+ sqlite3_result_int(ctx, pCsr->szPage);
+ break;
+ }
+ return SQLITE_OK;
+}
+
+static int statRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
+ StatCursor *pCsr = (StatCursor *)pCursor;
+ *pRowid = pCsr->iPageno;
+ return SQLITE_OK;
+}
+
+/*
+** Invoke this routine to register the "dbstat" virtual table module
+*/
+SQLITE_API int SQLITE_STDCALL sqlite3_dbstat_register(sqlite3 *db){
+ static sqlite3_module dbstat_module = {
+ 0, /* iVersion */
+ statConnect, /* xCreate */
+ statConnect, /* xConnect */
+ statBestIndex, /* xBestIndex */
+ statDisconnect, /* xDisconnect */
+ statDisconnect, /* xDestroy */
+ statOpen, /* xOpen - open a cursor */
+ statClose, /* xClose - close a cursor */
+ statFilter, /* xFilter - configure scan constraints */
+ statNext, /* xNext - advance a cursor */
+ statEof, /* xEof - check for end of scan */
+ statColumn, /* xColumn - read data */
+ statRowid, /* xRowid - read data */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+ };
+ return sqlite3_create_module(db, "dbstat", &dbstat_module, 0);
+}
+#endif /* SQLITE_ENABLE_DBSTAT_VTAB */
+
+/************** End of dbstat.c **********************************************/
diff --git a/libgda/sqlite/sqlite-src/sqlite3.h b/libgda/sqlite/sqlite-src/sqlite3.h
index 9879f80..d43b63c 100644
--- a/libgda/sqlite/sqlite-src/sqlite3.h
+++ b/libgda/sqlite/sqlite-src/sqlite3.h
@@ -43,21 +43,25 @@ extern "C" {
/*
-** Add the ability to override 'extern'
+** Provide the ability to override linkage features of the interface.
*/
#ifndef SQLITE_EXTERN
# define SQLITE_EXTERN extern
#endif
-
#ifndef SQLITE_API
# define SQLITE_API
#endif
-
+#ifndef SQLITE_CDECL
+# define SQLITE_CDECL
+#endif
+#ifndef SQLITE_STDCALL
+# define SQLITE_STDCALL
+#endif
/*
** These no-op macros are used in front of interfaces to mark those
** interfaces as either deprecated or experimental. New applications
-** should not use deprecated interfaces - they are support for backwards
+** should not use deprecated interfaces - they are supported for backwards
** compatibility only. Application writers should be aware that
** experimental interfaces are subject to change in point releases.
**
@@ -107,9 +111,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.8.6"
-#define SQLITE_VERSION_NUMBER 3008006
-#define SQLITE_SOURCE_ID "2014-08-15 11:46:33 9491ba7d738528f168657adb43a198238abde19e"
+#define SQLITE_VERSION "3.8.10.2"
+#define SQLITE_VERSION_NUMBER 3008010
+#define SQLITE_SOURCE_ID "2015-05-20 18:17:19 2ef4f3a5b1d1d0c4338f8243d40a2452cc1f7fe4"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -142,9 +146,9 @@ extern "C" {
** See also: [sqlite_version()] and [sqlite_source_id()].
*/
SQLITE_API SQLITE_EXTERN const char sqlite3_version[];
-SQLITE_API const char *sqlite3_libversion(void);
-SQLITE_API const char *sqlite3_sourceid(void);
-SQLITE_API int sqlite3_libversion_number(void);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_libversion(void);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_sourceid(void);
+SQLITE_API int SQLITE_STDCALL sqlite3_libversion_number(void);
/*
** CAPI3REF: Run-Time Library Compilation Options Diagnostics
@@ -169,8 +173,8 @@ SQLITE_API int sqlite3_libversion_number(void);
** [sqlite_compileoption_get()] and the [compile_options pragma].
*/
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
-SQLITE_API int sqlite3_compileoption_used(const char *zOptName);
-SQLITE_API const char *sqlite3_compileoption_get(int N);
+SQLITE_API int SQLITE_STDCALL sqlite3_compileoption_used(const char *zOptName);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N);
#endif
/*
@@ -201,7 +205,7 @@ SQLITE_API const char *sqlite3_compileoption_get(int N);
** SQLITE_THREADSAFE=1 or =2 then mutexes are enabled by default but
** can be fully or partially disabled using a call to [sqlite3_config()]
** with the verbs [SQLITE_CONFIG_SINGLETHREAD], [SQLITE_CONFIG_MULTITHREAD],
-** or [SQLITE_CONFIG_MUTEX]. ^(The return value of the
+** or [SQLITE_CONFIG_SERIALIZED]. ^(The return value of the
** sqlite3_threadsafe() function shows only the compile-time setting of
** thread safety, not any run-time changes to that setting made by
** sqlite3_config(). In other words, the return value from sqlite3_threadsafe()
@@ -209,7 +213,7 @@ SQLITE_API const char *sqlite3_compileoption_get(int N);
**
** See the [threading mode] documentation for additional information.
*/
-SQLITE_API int sqlite3_threadsafe(void);
+SQLITE_API int SQLITE_STDCALL sqlite3_threadsafe(void);
/*
** CAPI3REF: Database Connection Handle
@@ -266,6 +270,7 @@ typedef sqlite_uint64 sqlite3_uint64;
/*
** CAPI3REF: Closing A Database Connection
+** DESTRUCTOR: sqlite3
**
** ^The sqlite3_close() and sqlite3_close_v2() routines are destructors
** for the [sqlite3] object.
@@ -305,8 +310,8 @@ typedef sqlite_uint64 sqlite3_uint64;
** ^Calling sqlite3_close() or sqlite3_close_v2() with a NULL pointer
** argument is a harmless no-op.
*/
-SQLITE_API int sqlite3_close(sqlite3*);
-SQLITE_API int sqlite3_close_v2(sqlite3*);
+SQLITE_API int SQLITE_STDCALL sqlite3_close(sqlite3*);
+SQLITE_API int SQLITE_STDCALL sqlite3_close_v2(sqlite3*);
/*
** The type for a callback function.
@@ -317,6 +322,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
/*
** CAPI3REF: One-Step Query Execution Interface
+** METHOD: sqlite3
**
** The sqlite3_exec() interface is a convenience wrapper around
** [sqlite3_prepare_v2()], [sqlite3_step()], and [sqlite3_finalize()],
@@ -376,7 +382,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running.
** </ul>
*/
-SQLITE_API int sqlite3_exec(
+SQLITE_API int SQLITE_STDCALL sqlite3_exec(
sqlite3*, /* An open database */
const char *sql, /* SQL to be evaluated */
int (*callback)(void*,int,char**,char**), /* Callback function */
@@ -497,6 +503,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8))
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8))
+#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8))
/*
** CAPI3REF: Flags For File Open Operations
@@ -755,14 +762,16 @@ struct sqlite3_io_methods {
** of the [sqlite3_io_methods] object and for the [sqlite3_file_control()]
** interface.
**
+** <ul>
+** <li>[[SQLITE_FCNTL_LOCKSTATE]]
** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This
** opcode causes the xFileControl method to write the current state of
** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED],
** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE])
** into an integer that the pArg argument points to. This capability
-** is used during testing and only needs to be supported when SQLITE_TEST
-** is defined.
-** <ul>
+** is used during testing and is only available when the SQLITE_TEST
+** compile-time option is used.
+**
** <li>[[SQLITE_FCNTL_SIZE_HINT]]
** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS
** layer a hint of how large the database file will grow to be during the
@@ -887,7 +896,9 @@ struct sqlite3_io_methods {
** [PRAGMA] processing continues. ^If the [SQLITE_FCNTL_PRAGMA]
** file control returns [SQLITE_OK], then the parser assumes that the
** VFS has handled the PRAGMA itself and the parser generates a no-op
-** prepared statement. ^If the [SQLITE_FCNTL_PRAGMA] file control returns
+** prepared statement if result string is NULL, or that returns a copy
+** of the result string if the string is non-NULL.
+** ^If the [SQLITE_FCNTL_PRAGMA] file control returns
** any result code other than [SQLITE_OK] or [SQLITE_NOTFOUND], that means
** that the VFS encountered an error while handling the [PRAGMA] and the
** compilation of the PRAGMA fails with an error. ^The [SQLITE_FCNTL_PRAGMA]
@@ -945,12 +956,19 @@ struct sqlite3_io_methods {
** pointed to by the pArg argument. This capability is used during testing
** and only needs to be supported when SQLITE_TEST is defined.
**
+** <li>[[SQLITE_FCNTL_WAL_BLOCK]]
+** The [SQLITE_FCNTL_WAL_BLOCK] is a signal to the VFS layer that it might
+** be advantageous to block on the next WAL lock if the lock is not immediately
+** available. The WAL subsystem issues this signal during rare
+** circumstances in order to fix a problem with priority inversion.
+** Applications should <em>not</em> use this file-control.
+**
** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE 1
-#define SQLITE_GET_LOCKPROXYFILE 2
-#define SQLITE_SET_LOCKPROXYFILE 3
-#define SQLITE_LAST_ERRNO 4
+#define SQLITE_FCNTL_GET_LOCKPROXYFILE 2
+#define SQLITE_FCNTL_SET_LOCKPROXYFILE 3
+#define SQLITE_FCNTL_LAST_ERRNO 4
#define SQLITE_FCNTL_SIZE_HINT 5
#define SQLITE_FCNTL_CHUNK_SIZE 6
#define SQLITE_FCNTL_FILE_POINTER 7
@@ -969,6 +987,13 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_SYNC 21
#define SQLITE_FCNTL_COMMIT_PHASETWO 22
#define SQLITE_FCNTL_WIN32_SET_HANDLE 23
+#define SQLITE_FCNTL_WAL_BLOCK 24
+
+/* deprecated names */
+#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
+#define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE
+#define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO
+
/*
** CAPI3REF: Mutex Handle
@@ -1220,7 +1245,7 @@ struct sqlite3_vfs {
** </ul>
**
** When unlocking, the same SHARED or EXCLUSIVE flag must be supplied as
-** was given no the corresponding lock.
+** was given on the corresponding lock.
**
** The xShmLock method can transition between unlocked and SHARED or
** between unlocked and EXCLUSIVE. It cannot transition between SHARED
@@ -1317,10 +1342,10 @@ struct sqlite3_vfs {
** must return [SQLITE_OK] on success and some other [error code] upon
** failure.
*/
-SQLITE_API int sqlite3_initialize(void);
-SQLITE_API int sqlite3_shutdown(void);
-SQLITE_API int sqlite3_os_init(void);
-SQLITE_API int sqlite3_os_end(void);
+SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void);
+SQLITE_API int SQLITE_STDCALL sqlite3_shutdown(void);
+SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void);
+SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void);
/*
** CAPI3REF: Configuring The SQLite Library
@@ -1351,10 +1376,11 @@ SQLITE_API int sqlite3_os_end(void);
** ^If the option is unknown or SQLite is unable to set the option
** then this routine returns a non-zero [error code].
*/
-SQLITE_API int sqlite3_config(int, ...);
+SQLITE_API int SQLITE_CDECL sqlite3_config(int, ...);
/*
** CAPI3REF: Configure database connections
+** METHOD: sqlite3
**
** The sqlite3_db_config() interface is used to make configuration
** changes to a [database connection]. The interface is similar to
@@ -1369,7 +1395,7 @@ SQLITE_API int sqlite3_config(int, ...);
** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if
** the call is considered successful.
*/
-SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
+SQLITE_API int SQLITE_CDECL sqlite3_db_config(sqlite3*, int op, ...);
/*
** CAPI3REF: Memory Allocation Routines
@@ -1503,31 +1529,33 @@ struct sqlite3_mem_methods {
** SQLITE_CONFIG_SERIALIZED configuration option.</dd>
**
** [[SQLITE_CONFIG_MALLOC]] <dt>SQLITE_CONFIG_MALLOC</dt>
-** <dd> ^(This option takes a single argument which is a pointer to an
-** instance of the [sqlite3_mem_methods] structure. The argument specifies
+** <dd> ^(The SQLITE_CONFIG_MALLOC option takes a single argument which is
+** a pointer to an instance of the [sqlite3_mem_methods] structure.
+** The argument specifies
** alternative low-level memory allocation routines to be used in place of
** the memory allocation routines built into SQLite.)^ ^SQLite makes
** its own private copy of the content of the [sqlite3_mem_methods] structure
** before the [sqlite3_config()] call returns.</dd>
**
** [[SQLITE_CONFIG_GETMALLOC]] <dt>SQLITE_CONFIG_GETMALLOC</dt>
-** <dd> ^(This option takes a single argument which is a pointer to an
-** instance of the [sqlite3_mem_methods] structure. The [sqlite3_mem_methods]
+** <dd> ^(The SQLITE_CONFIG_GETMALLOC option takes a single argument which
+** is a pointer to an instance of the [sqlite3_mem_methods] structure.
+** The [sqlite3_mem_methods]
** structure is filled with the currently defined memory allocation routines.)^
** This option can be used to overload the default memory allocation
** routines with a wrapper that simulations memory allocation failure or
** tracks memory usage, for example. </dd>
**
** [[SQLITE_CONFIG_MEMSTATUS]] <dt>SQLITE_CONFIG_MEMSTATUS</dt>
-** <dd> ^This option takes single argument of type int, interpreted as a
-** boolean, which enables or disables the collection of memory allocation
-** statistics. ^(When memory allocation statistics are disabled, the
-** following SQLite interfaces become non-operational:
+** <dd> ^The SQLITE_CONFIG_MEMSTATUS option takes single argument of type int,
+** interpreted as a boolean, which enables or disables the collection of
+** memory allocation statistics. ^(When memory allocation statistics are
+** disabled, the following SQLite interfaces become non-operational:
** <ul>
** <li> [sqlite3_memory_used()]
** <li> [sqlite3_memory_highwater()]
** <li> [sqlite3_soft_heap_limit64()]
-** <li> [sqlite3_status()]
+** <li> [sqlite3_status64()]
** </ul>)^
** ^Memory allocation statistics are enabled by default unless SQLite is
** compiled with [SQLITE_DEFAULT_MEMSTATUS]=0 in which case memory
@@ -1535,53 +1563,67 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_CONFIG_SCRATCH]] <dt>SQLITE_CONFIG_SCRATCH</dt>
-** <dd> ^This option specifies a static memory buffer that SQLite can use for
-** scratch memory. There are three arguments: A pointer an 8-byte
+** <dd> ^The SQLITE_CONFIG_SCRATCH option specifies a static memory buffer
+** that SQLite can use for scratch memory. ^(There are three arguments
+** to SQLITE_CONFIG_SCRATCH: A pointer an 8-byte
** aligned memory buffer from which the scratch allocations will be
** drawn, the size of each scratch allocation (sz),
-** and the maximum number of scratch allocations (N). The sz
-** argument must be a multiple of 16.
+** and the maximum number of scratch allocations (N).)^
** The first argument must be a pointer to an 8-byte aligned buffer
** of at least sz*N bytes of memory.
-** ^SQLite will use no more than two scratch buffers per thread. So
-** N should be set to twice the expected maximum number of threads.
-** ^SQLite will never require a scratch buffer that is more than 6
-** times the database page size. ^If SQLite needs needs additional
+** ^SQLite will not use more than one scratch buffers per thread.
+** ^SQLite will never request a scratch buffer that is more than 6
+** times the database page size.
+** ^If SQLite needs needs additional
** scratch memory beyond what is provided by this configuration option, then
-** [sqlite3_malloc()] will be used to obtain the memory needed.</dd>
+** [sqlite3_malloc()] will be used to obtain the memory needed.<p>
+** ^When the application provides any amount of scratch memory using
+** SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary large
+** [sqlite3_malloc|heap allocations].
+** This can help [Robson proof|prevent memory allocation failures] due to heap
+** fragmentation in low-memory embedded systems.
+** </dd>
**
** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt>
-** <dd> ^This option specifies a static memory buffer that SQLite can use for
-** the database page cache with the default page cache implementation.
+** <dd> ^The SQLITE_CONFIG_PAGECACHE option specifies a static memory buffer
+** that SQLite can use for the database page cache with the default page
+** cache implementation.
** This configuration should not be used if an application-define page
-** cache implementation is loaded using the SQLITE_CONFIG_PCACHE2 option.
-** There are three arguments to this option: A pointer to 8-byte aligned
+** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2]
+** configuration option.
+** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to
+** 8-byte aligned
** memory, the size of each page buffer (sz), and the number of pages (N).
** The sz argument should be the size of the largest database page
-** (a power of two between 512 and 32768) plus a little extra for each
-** page header. ^The page header size is 20 to 40 bytes depending on
-** the host architecture. ^It is harmless, apart from the wasted memory,
-** to make sz a little too large. The first
-** argument should point to an allocation of at least sz*N bytes of memory.
+** (a power of two between 512 and 65536) plus some extra bytes for each
+** page header. ^The number of extra bytes needed by the page header
+** can be determined using the [SQLITE_CONFIG_PCACHE_HDRSZ] option
+** to [sqlite3_config()].
+** ^It is harmless, apart from the wasted memory,
+** for the sz parameter to be larger than necessary. The first
+** argument should pointer to an 8-byte aligned block of memory that
+** is at least sz*N bytes of memory, otherwise subsequent behavior is
+** undefined.
** ^SQLite will use the memory provided by the first argument to satisfy its
** memory needs for the first N pages that it adds to cache. ^If additional
** page cache memory is needed beyond what is provided by this option, then
-** SQLite goes to [sqlite3_malloc()] for the additional storage space.
-** The pointer in the first argument must
-** be aligned to an 8-byte boundary or subsequent behavior of SQLite
-** will be undefined.</dd>
+** SQLite goes to [sqlite3_malloc()] for the additional storage space.</dd>
**
** [[SQLITE_CONFIG_HEAP]] <dt>SQLITE_CONFIG_HEAP</dt>
-** <dd> ^This option specifies a static memory buffer that SQLite will use
-** for all of its dynamic memory allocation needs beyond those provided
-** for by [SQLITE_CONFIG_SCRATCH] and [SQLITE_CONFIG_PAGECACHE].
-** There are three arguments: An 8-byte aligned pointer to the memory,
+** <dd> ^The SQLITE_CONFIG_HEAP option specifies a static memory buffer
+** that SQLite will use for all of its dynamic memory allocation needs
+** beyond those provided for by [SQLITE_CONFIG_SCRATCH] and
+** [SQLITE_CONFIG_PAGECACHE].
+** ^The SQLITE_CONFIG_HEAP option is only available if SQLite is compiled
+** with either [SQLITE_ENABLE_MEMSYS3] or [SQLITE_ENABLE_MEMSYS5] and returns
+** [SQLITE_ERROR] if invoked otherwise.
+** ^There are three arguments to SQLITE_CONFIG_HEAP:
+** An 8-byte aligned pointer to the memory,
** the number of bytes in the memory buffer, and the minimum allocation size.
** ^If the first pointer (the memory pointer) is NULL, then SQLite reverts
** to using its default memory allocator (the system malloc() implementation),
** undoing any prior invocation of [SQLITE_CONFIG_MALLOC]. ^If the
-** memory pointer is not NULL and either [SQLITE_ENABLE_MEMSYS3] or
-** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory
+** memory pointer is not NULL then the alternative memory
** allocator is engaged to handle all of SQLites memory allocation needs.
** The first pointer (the memory pointer) must be aligned to an 8-byte
** boundary or subsequent behavior of SQLite will be undefined.
@@ -1589,11 +1631,11 @@ struct sqlite3_mem_methods {
** for the minimum allocation size are 2**5 through 2**8.</dd>
**
** [[SQLITE_CONFIG_MUTEX]] <dt>SQLITE_CONFIG_MUTEX</dt>
-** <dd> ^(This option takes a single argument which is a pointer to an
-** instance of the [sqlite3_mutex_methods] structure. The argument specifies
-** alternative low-level mutex routines to be used in place
-** the mutex routines built into SQLite.)^ ^SQLite makes a copy of the
-** content of the [sqlite3_mutex_methods] structure before the call to
+** <dd> ^(The SQLITE_CONFIG_MUTEX option takes a single argument which is a
+** pointer to an instance of the [sqlite3_mutex_methods] structure.
+** The argument specifies alternative low-level mutex routines to be used
+** in place the mutex routines built into SQLite.)^ ^SQLite makes a copy of
+** the content of the [sqlite3_mutex_methods] structure before the call to
** [sqlite3_config()] returns. ^If SQLite is compiled with
** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then
** the entire mutexing subsystem is omitted from the build and hence calls to
@@ -1601,8 +1643,8 @@ struct sqlite3_mem_methods {
** return [SQLITE_ERROR].</dd>
**
** [[SQLITE_CONFIG_GETMUTEX]] <dt>SQLITE_CONFIG_GETMUTEX</dt>
-** <dd> ^(This option takes a single argument which is a pointer to an
-** instance of the [sqlite3_mutex_methods] structure. The
+** <dd> ^(The SQLITE_CONFIG_GETMUTEX option takes a single argument which
+** is a pointer to an instance of the [sqlite3_mutex_methods] structure. The
** [sqlite3_mutex_methods]
** structure is filled with the currently defined mutex routines.)^
** This option can be used to overload the default mutex allocation
@@ -1614,25 +1656,25 @@ struct sqlite3_mem_methods {
** return [SQLITE_ERROR].</dd>
**
** [[SQLITE_CONFIG_LOOKASIDE]] <dt>SQLITE_CONFIG_LOOKASIDE</dt>
-** <dd> ^(This option takes two arguments that determine the default
-** memory allocation for the lookaside memory allocator on each
-** [database connection]. The first argument is the
+** <dd> ^(The SQLITE_CONFIG_LOOKASIDE option takes two arguments that determine
+** the default size of lookaside memory on each [database connection].
+** The first argument is the
** size of each lookaside buffer slot and the second is the number of
-** slots allocated to each database connection.)^ ^(This option sets the
-** <i>default</i> lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE]
-** verb to [sqlite3_db_config()] can be used to change the lookaside
+** slots allocated to each database connection.)^ ^(SQLITE_CONFIG_LOOKASIDE
+** sets the <i>default</i> lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE]
+** option to [sqlite3_db_config()] can be used to change the lookaside
** configuration on individual connections.)^ </dd>
**
** [[SQLITE_CONFIG_PCACHE2]] <dt>SQLITE_CONFIG_PCACHE2</dt>
-** <dd> ^(This option takes a single argument which is a pointer to
-** an [sqlite3_pcache_methods2] object. This object specifies the interface
-** to a custom page cache implementation.)^ ^SQLite makes a copy of the
-** object and uses it for page cache memory allocations.</dd>
+** <dd> ^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is
+** a pointer to an [sqlite3_pcache_methods2] object. This object specifies
+** the interface to a custom page cache implementation.)^
+** ^SQLite makes a copy of the [sqlite3_pcache_methods2] object.</dd>
**
** [[SQLITE_CONFIG_GETPCACHE2]] <dt>SQLITE_CONFIG_GETPCACHE2</dt>
-** <dd> ^(This option takes a single argument which is a pointer to an
-** [sqlite3_pcache_methods2] object. SQLite copies of the current
-** page cache implementation into that object.)^ </dd>
+** <dd> ^(The SQLITE_CONFIG_GETPCACHE2 option takes a single argument which
+** is a pointer to an [sqlite3_pcache_methods2] object. SQLite copies of
+** the current page cache implementation into that object.)^ </dd>
**
** [[SQLITE_CONFIG_LOG]] <dt>SQLITE_CONFIG_LOG</dt>
** <dd> The SQLITE_CONFIG_LOG option is used to configure the SQLite
@@ -1655,10 +1697,11 @@ struct sqlite3_mem_methods {
** function must be threadsafe. </dd>
**
** [[SQLITE_CONFIG_URI]] <dt>SQLITE_CONFIG_URI
-** <dd>^(This option takes a single argument of type int. If non-zero, then
-** URI handling is globally enabled. If the parameter is zero, then URI handling
-** is globally disabled.)^ ^If URI handling is globally enabled, all filenames
-** passed to [sqlite3_open()], [sqlite3_open_v2()], [sqlite3_open16()] or
+** <dd>^(The SQLITE_CONFIG_URI option takes a single argument of type int.
+** If non-zero, then URI handling is globally enabled. If the parameter is zero,
+** then URI handling is globally disabled.)^ ^If URI handling is globally
+** enabled, all filenames passed to [sqlite3_open()], [sqlite3_open_v2()],
+** [sqlite3_open16()] or
** specified as part of [ATTACH] commands are interpreted as URIs, regardless
** of whether or not the [SQLITE_OPEN_URI] flag is set when the database
** connection is opened. ^If it is globally disabled, filenames are
@@ -1668,9 +1711,10 @@ struct sqlite3_mem_methods {
** [SQLITE_USE_URI] symbol defined.)^
**
** [[SQLITE_CONFIG_COVERING_INDEX_SCAN]] <dt>SQLITE_CONFIG_COVERING_INDEX_SCAN
-** <dd>^This option takes a single integer argument which is interpreted as
-** a boolean in order to enable or disable the use of covering indices for
-** full table scans in the query optimizer. ^The default setting is determined
+** <dd>^The SQLITE_CONFIG_COVERING_INDEX_SCAN option takes a single integer
+** argument which is interpreted as a boolean in order to enable or disable
+** the use of covering indices for full table scans in the query optimizer.
+** ^The default setting is determined
** by the [SQLITE_ALLOW_COVERING_INDEX_SCAN] compile-time option, or is "on"
** if that compile-time option is omitted.
** The ability to disable the use of covering indices for full table scans
@@ -1710,18 +1754,37 @@ struct sqlite3_mem_methods {
** ^The default setting can be overridden by each database connection using
** either the [PRAGMA mmap_size] command, or by using the
** [SQLITE_FCNTL_MMAP_SIZE] file control. ^(The maximum allowed mmap size
-** cannot be changed at run-time. Nor may the maximum allowed mmap size
-** exceed the compile-time maximum mmap size set by the
+** will be silently truncated if necessary so that it does not exceed the
+** compile-time maximum mmap size set by the
** [SQLITE_MAX_MMAP_SIZE] compile-time option.)^
** ^If either argument to this option is negative, then that argument is
** changed to its compile-time default.
**
** [[SQLITE_CONFIG_WIN32_HEAPSIZE]]
** <dt>SQLITE_CONFIG_WIN32_HEAPSIZE
-** <dd>^This option is only available if SQLite is compiled for Windows
-** with the [SQLITE_WIN32_MALLOC] pre-processor macro defined.
-** SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value
+** <dd>^The SQLITE_CONFIG_WIN32_HEAPSIZE option is only available if SQLite is
+** compiled for Windows with the [SQLITE_WIN32_MALLOC] pre-processor macro
+** defined. ^SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value
** that specifies the maximum size of the created heap.
+**
+** [[SQLITE_CONFIG_PCACHE_HDRSZ]]
+** <dt>SQLITE_CONFIG_PCACHE_HDRSZ
+** <dd>^The SQLITE_CONFIG_PCACHE_HDRSZ option takes a single parameter which
+** is a pointer to an integer and writes into that integer the number of extra
+** bytes per page required for each page in [SQLITE_CONFIG_PAGECACHE].
+** The amount of extra space required can change depending on the compiler,
+** target platform, and SQLite version.
+**
+** [[SQLITE_CONFIG_PMASZ]]
+** <dt>SQLITE_CONFIG_PMASZ
+** <dd>^The SQLITE_CONFIG_PMASZ option takes a single parameter which
+** is an unsigned integer and sets the "Minimum PMA Size" for the multithreaded
+** sorter to that integer. The default minimum PMA Size is set by the
+** [SQLITE_SORTER_PMASZ] compile-time option. New threads are launched
+** to help with sort operations when multithreaded sorting
+** is enabled (using the [PRAGMA threads] command) and the amount of content
+** to be sorted exceeds the page size times the minimum of the
+** [PRAGMA cache_size] setting and this value.
** </dl>
*/
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
@@ -1747,6 +1810,8 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */
#define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */
+#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */
+#define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */
/*
** CAPI3REF: Database Connection Configuration Options
@@ -1813,15 +1878,17 @@ struct sqlite3_mem_methods {
/*
** CAPI3REF: Enable Or Disable Extended Result Codes
+** METHOD: sqlite3
**
** ^The sqlite3_extended_result_codes() routine enables or disables the
** [extended result codes] feature of SQLite. ^The extended result
** codes are disabled by default for historical compatibility.
*/
-SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff);
+SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3*, int onoff);
/*
** CAPI3REF: Last Insert Rowid
+** METHOD: sqlite3
**
** ^Each entry in most SQLite tables (except for [WITHOUT ROWID] tables)
** has a unique 64-bit signed
@@ -1869,52 +1936,51 @@ SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff);
** unpredictable and might not equal either the old or the new
** last insert [rowid].
*/
-SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_last_insert_rowid(sqlite3*);
/*
** CAPI3REF: Count The Number Of Rows Modified
+** METHOD: sqlite3
**
-** ^This function returns the number of database rows that were changed
-** or inserted or deleted by the most recently completed SQL statement
-** on the [database connection] specified by the first parameter.
-** ^(Only changes that are directly specified by the [INSERT], [UPDATE],
-** or [DELETE] statement are counted. Auxiliary changes caused by
-** triggers or [foreign key actions] are not counted.)^ Use the
-** [sqlite3_total_changes()] function to find the total number of changes
-** including changes caused by triggers and foreign key actions.
-**
-** ^Changes to a view that are simulated by an [INSTEAD OF trigger]
-** are not counted. Only real table changes are counted.
-**
-** ^(A "row change" is a change to a single row of a single table
-** caused by an INSERT, DELETE, or UPDATE statement. Rows that
-** are changed as side effects of [REPLACE] constraint resolution,
-** rollback, ABORT processing, [DROP TABLE], or by any other
-** mechanisms do not count as direct row changes.)^
-**
-** A "trigger context" is a scope of execution that begins and
-** ends with the script of a [CREATE TRIGGER | trigger].
-** Most SQL statements are
-** evaluated outside of any trigger. This is the "top level"
-** trigger context. If a trigger fires from the top level, a
-** new trigger context is entered for the duration of that one
-** trigger. Subtriggers create subcontexts for their duration.
-**
-** ^Calling [sqlite3_exec()] or [sqlite3_step()] recursively does
-** not create a new trigger context.
-**
-** ^This function returns the number of direct row changes in the
-** most recent INSERT, UPDATE, or DELETE statement within the same
-** trigger context.
-**
-** ^Thus, when called from the top level, this function returns the
-** number of changes in the most recent INSERT, UPDATE, or DELETE
-** that also occurred at the top level. ^(Within the body of a trigger,
-** the sqlite3_changes() interface can be called to find the number of
-** changes in the most recently completed INSERT, UPDATE, or DELETE
-** statement within the body of the same trigger.
-** However, the number returned does not include changes
-** caused by subtriggers since those have their own context.)^
+** ^This function returns the number of rows modified, inserted or
+** deleted by the most recently completed INSERT, UPDATE or DELETE
+** statement on the database connection specified by the only parameter.
+** ^Executing any other type of SQL statement does not modify the value
+** returned by this function.
+**
+** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are
+** considered - auxiliary changes caused by [CREATE TRIGGER | triggers],
+** [foreign key actions] or [REPLACE] constraint resolution are not counted.
+**
+** Changes to a view that are intercepted by
+** [INSTEAD OF trigger | INSTEAD OF triggers] are not counted. ^The value
+** returned by sqlite3_changes() immediately after an INSERT, UPDATE or
+** DELETE statement run on a view is always zero. Only changes made to real
+** tables are counted.
+**
+** Things are more complicated if the sqlite3_changes() function is
+** executed while a trigger program is running. This may happen if the
+** program uses the [changes() SQL function], or if some other callback
+** function invokes sqlite3_changes() directly. Essentially:
+**
+** <ul>
+** <li> ^(Before entering a trigger program the value returned by
+** sqlite3_changes() function is saved. After the trigger program
+** has finished, the original value is restored.)^
+**
+** <li> ^(Within a trigger program each INSERT, UPDATE and DELETE
+** statement sets the value returned by sqlite3_changes()
+** upon completion as normal. Of course, this value will not include
+** any changes performed by sub-triggers, as the sqlite3_changes()
+** value will be saved and restored after each sub-trigger has run.)^
+** </ul>
+**
+** ^This means that if the changes() SQL function (or similar) is used
+** by the first INSERT, UPDATE or DELETE statement within a trigger, it
+** returns the value as set when the calling statement began executing.
+** ^If it is used by the second or subsequent such statement within a trigger
+** program, the value returned reflects the number of rows modified by the
+** previous INSERT, UPDATE or DELETE statement within the same trigger.
**
** See also the [sqlite3_total_changes()] interface, the
** [count_changes pragma], and the [changes() SQL function].
@@ -1923,25 +1989,23 @@ SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
** while [sqlite3_changes()] is running then the value returned
** is unpredictable and not meaningful.
*/
-SQLITE_API int sqlite3_changes(sqlite3*);
+SQLITE_API int SQLITE_STDCALL sqlite3_changes(sqlite3*);
/*
** CAPI3REF: Total Number Of Rows Modified
+** METHOD: sqlite3
**
-** ^This function returns the number of row changes caused by [INSERT],
-** [UPDATE] or [DELETE] statements since the [database connection] was opened.
-** ^(The count returned by sqlite3_total_changes() includes all changes
-** from all [CREATE TRIGGER | trigger] contexts and changes made by
-** [foreign key actions]. However,
-** the count does not include changes used to implement [REPLACE] constraints,
-** do rollbacks or ABORT processing, or [DROP TABLE] processing. The
-** count does not include rows of views that fire an [INSTEAD OF trigger],
-** though if the INSTEAD OF trigger makes changes of its own, those changes
-** are counted.)^
-** ^The sqlite3_total_changes() function counts the changes as soon as
-** the statement that makes them is completed (when the statement handle
-** is passed to [sqlite3_reset()] or [sqlite3_finalize()]).
-**
+** ^This function returns the total number of rows inserted, modified or
+** deleted by all [INSERT], [UPDATE] or [DELETE] statements completed
+** since the database connection was opened, including those executed as
+** part of trigger programs. ^Executing any other type of SQL statement
+** does not affect the value returned by sqlite3_total_changes().
+**
+** ^Changes made as part of [foreign key actions] are included in the
+** count, but those made as part of REPLACE constraint resolution are
+** not. ^Changes to a view that are intercepted by INSTEAD OF triggers
+** are not counted.
+**
** See also the [sqlite3_changes()] interface, the
** [count_changes pragma], and the [total_changes() SQL function].
**
@@ -1949,10 +2013,11 @@ SQLITE_API int sqlite3_changes(sqlite3*);
** while [sqlite3_total_changes()] is running then the value
** returned is unpredictable and not meaningful.
*/
-SQLITE_API int sqlite3_total_changes(sqlite3*);
+SQLITE_API int SQLITE_STDCALL sqlite3_total_changes(sqlite3*);
/*
** CAPI3REF: Interrupt A Long-Running Query
+** METHOD: sqlite3
**
** ^This function causes any pending database operation to abort and
** return at its earliest opportunity. This routine is typically
@@ -1988,7 +2053,7 @@ SQLITE_API int sqlite3_total_changes(sqlite3*);
** If the database connection closes while [sqlite3_interrupt()]
** is running then bad things will likely happen.
*/
-SQLITE_API void sqlite3_interrupt(sqlite3*);
+SQLITE_API void SQLITE_STDCALL sqlite3_interrupt(sqlite3*);
/*
** CAPI3REF: Determine If An SQL Statement Is Complete
@@ -2023,11 +2088,13 @@ SQLITE_API void sqlite3_interrupt(sqlite3*);
** The input to [sqlite3_complete16()] must be a zero-terminated
** UTF-16 string in native byte order.
*/
-SQLITE_API int sqlite3_complete(const char *sql);
-SQLITE_API int sqlite3_complete16(const void *sql);
+SQLITE_API int SQLITE_STDCALL sqlite3_complete(const char *sql);
+SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *sql);
/*
** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors
+** KEYWORDS: {busy-handler callback} {busy handler}
+** METHOD: sqlite3
**
** ^The sqlite3_busy_handler(D,X,P) routine sets a callback function X
** that might be invoked with argument P whenever
@@ -2044,7 +2111,7 @@ SQLITE_API int sqlite3_complete16(const void *sql);
** ^The first argument to the busy handler is a copy of the void* pointer which
** is the third argument to sqlite3_busy_handler(). ^The second argument to
** the busy handler callback is the number of times that the busy handler has
-** been invoked for the same locking event. ^If the
+** been invoked previously for the same locking event. ^If the
** busy callback returns 0, then no additional attempts are made to
** access the database and [SQLITE_BUSY] is returned
** to the application.
@@ -2083,10 +2150,11 @@ SQLITE_API int sqlite3_complete16(const void *sql);
** A busy handler must not close the database connection
** or [prepared statement] that invoked the busy handler.
*/
-SQLITE_API int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
+SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
/*
** CAPI3REF: Set A Busy Timeout
+** METHOD: sqlite3
**
** ^This routine sets a [sqlite3_busy_handler | busy handler] that sleeps
** for a specified amount of time when a table is locked. ^The handler
@@ -2099,16 +2167,17 @@ SQLITE_API int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
** turns off all busy handlers.
**
** ^(There can only be a single busy handler for a particular
-** [database connection] any any given moment. If another busy handler
+** [database connection] at any given moment. If another busy handler
** was defined (using [sqlite3_busy_handler()]) prior to calling
** this routine, that other busy handler is cleared.)^
**
** See also: [PRAGMA busy_timeout]
*/
-SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
+SQLITE_API int SQLITE_STDCALL sqlite3_busy_timeout(sqlite3*, int ms);
/*
** CAPI3REF: Convenience Routines For Running Queries
+** METHOD: sqlite3
**
** This is a legacy interface that is preserved for backwards compatibility.
** Use of this interface is not recommended.
@@ -2179,7 +2248,7 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
** reflected in subsequent calls to [sqlite3_errcode()] or
** [sqlite3_errmsg()].
*/
-SQLITE_API int sqlite3_get_table(
+SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
sqlite3 *db, /* An open database */
const char *zSql, /* SQL to be evaluated */
char ***pazResult, /* Results of the query */
@@ -2187,13 +2256,17 @@ SQLITE_API int sqlite3_get_table(
int *pnColumn, /* Number of result columns written here */
char **pzErrmsg /* Error msg written here */
);
-SQLITE_API void sqlite3_free_table(char **result);
+SQLITE_API void SQLITE_STDCALL sqlite3_free_table(char **result);
/*
** CAPI3REF: Formatted String Printing Functions
**
** These routines are work-alikes of the "printf()" family of functions
** from the standard C library.
+** These routines understand most of the common K&R formatting options,
+** plus some additional non-standard formats, detailed below.
+** Note that some of the more obscure formatting options from recent
+** C-library standards are omitted from this implementation.
**
** ^The sqlite3_mprintf() and sqlite3_vmprintf() routines write their
** results into memory obtained from [sqlite3_malloc()].
@@ -2226,7 +2299,7 @@ SQLITE_API void sqlite3_free_table(char **result);
** These routines all implement some additional formatting
** options that are useful for constructing SQL statements.
** All of the usual printf() formatting options apply. In addition, there
-** is are "%q", "%Q", and "%z" options.
+** is are "%q", "%Q", "%w" and "%z" options.
**
** ^(The %q option works like %s in that it substitutes a nul-terminated
** string from the argument list. But %q also doubles every '\'' character.
@@ -2279,14 +2352,20 @@ SQLITE_API void sqlite3_free_table(char **result);
** The code above will render a correct SQL statement in the zSQL
** variable even if the zText variable is a NULL pointer.
**
+** ^(The "%w" formatting option is like "%q" except that it expects to
+** be contained within double-quotes instead of single quotes, and it
+** escapes the double-quote character instead of the single-quote
+** character.)^ The "%w" formatting option is intended for safely inserting
+** table and column names into a constructed SQL statement.
+**
** ^(The "%z" formatting option works like "%s" but with the
** addition that after the string has been read and copied into
** the result, [sqlite3_free()] is called on the input string.)^
*/
-SQLITE_API char *sqlite3_mprintf(const char*,...);
-SQLITE_API char *sqlite3_vmprintf(const char*, va_list);
-SQLITE_API char *sqlite3_snprintf(int,char*,const char*, ...);
-SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
+SQLITE_API char *SQLITE_CDECL sqlite3_mprintf(const char*,...);
+SQLITE_API char *SQLITE_STDCALL sqlite3_vmprintf(const char*, va_list);
+SQLITE_API char *SQLITE_CDECL sqlite3_snprintf(int,char*,const char*, ...);
+SQLITE_API char *SQLITE_STDCALL sqlite3_vsnprintf(int,char*,const char*, va_list);
/*
** CAPI3REF: Memory Allocation Subsystem
@@ -2303,6 +2382,10 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
** sqlite3_malloc() is zero or negative then sqlite3_malloc() returns
** a NULL pointer.
**
+** ^The sqlite3_malloc64(N) routine works just like
+** sqlite3_malloc(N) except that N is an unsigned 64-bit integer instead
+** of a signed 32-bit integer.
+**
** ^Calling sqlite3_free() with a pointer previously returned
** by sqlite3_malloc() or sqlite3_realloc() releases that memory so
** that it might be reused. ^The sqlite3_free() routine is
@@ -2314,24 +2397,38 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
** might result if sqlite3_free() is called with a non-NULL pointer that
** was not obtained from sqlite3_malloc() or sqlite3_realloc().
**
-** ^(The sqlite3_realloc() interface attempts to resize a
-** prior memory allocation to be at least N bytes, where N is the
-** second parameter. The memory allocation to be resized is the first
-** parameter.)^ ^ If the first parameter to sqlite3_realloc()
+** ^The sqlite3_realloc(X,N) interface attempts to resize a
+** prior memory allocation X to be at least N bytes.
+** ^If the X parameter to sqlite3_realloc(X,N)
** is a NULL pointer then its behavior is identical to calling
-** sqlite3_malloc(N) where N is the second parameter to sqlite3_realloc().
-** ^If the second parameter to sqlite3_realloc() is zero or
+** sqlite3_malloc(N).
+** ^If the N parameter to sqlite3_realloc(X,N) is zero or
** negative then the behavior is exactly the same as calling
-** sqlite3_free(P) where P is the first parameter to sqlite3_realloc().
-** ^sqlite3_realloc() returns a pointer to a memory allocation
-** of at least N bytes in size or NULL if sufficient memory is unavailable.
+** sqlite3_free(X).
+** ^sqlite3_realloc(X,N) returns a pointer to a memory allocation
+** of at least N bytes in size or NULL if insufficient memory is available.
** ^If M is the size of the prior allocation, then min(N,M) bytes
** of the prior allocation are copied into the beginning of buffer returned
-** by sqlite3_realloc() and the prior allocation is freed.
-** ^If sqlite3_realloc() returns NULL, then the prior allocation
-** is not freed.
-**
-** ^The memory returned by sqlite3_malloc() and sqlite3_realloc()
+** by sqlite3_realloc(X,N) and the prior allocation is freed.
+** ^If sqlite3_realloc(X,N) returns NULL and N is positive, then the
+** prior allocation is not freed.
+**
+** ^The sqlite3_realloc64(X,N) interfaces works the same as
+** sqlite3_realloc(X,N) except that N is a 64-bit unsigned integer instead
+** of a 32-bit signed integer.
+**
+** ^If X is a memory allocation previously obtained from sqlite3_malloc(),
+** sqlite3_malloc64(), sqlite3_realloc(), or sqlite3_realloc64(), then
+** sqlite3_msize(X) returns the size of that memory allocation in bytes.
+** ^The value returned by sqlite3_msize(X) might be larger than the number
+** of bytes requested when X was allocated. ^If X is a NULL pointer then
+** sqlite3_msize(X) returns zero. If X points to something that is not
+** the beginning of memory allocation, or if it points to a formerly
+** valid memory allocation that has now been freed, then the behavior
+** of sqlite3_msize(X) is undefined and possibly harmful.
+**
+** ^The memory returned by sqlite3_malloc(), sqlite3_realloc(),
+** sqlite3_malloc64(), and sqlite3_realloc64()
** is always aligned to at least an 8 byte boundary, or to a
** 4 byte boundary if the [SQLITE_4_BYTE_ALIGNED_MALLOC] compile-time
** option is used.
@@ -2358,9 +2455,12 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
** a block of memory after it has been released using
** [sqlite3_free()] or [sqlite3_realloc()].
*/
-SQLITE_API void *sqlite3_malloc(int);
-SQLITE_API void *sqlite3_realloc(void*, int);
-SQLITE_API void sqlite3_free(void*);
+SQLITE_API void *SQLITE_STDCALL sqlite3_malloc(int);
+SQLITE_API void *SQLITE_STDCALL sqlite3_malloc64(sqlite3_uint64);
+SQLITE_API void *SQLITE_STDCALL sqlite3_realloc(void*, int);
+SQLITE_API void *SQLITE_STDCALL sqlite3_realloc64(void*, sqlite3_uint64);
+SQLITE_API void SQLITE_STDCALL sqlite3_free(void*);
+SQLITE_API sqlite3_uint64 SQLITE_STDCALL sqlite3_msize(void*);
/*
** CAPI3REF: Memory Allocator Statistics
@@ -2385,8 +2485,8 @@ SQLITE_API void sqlite3_free(void*);
** by [sqlite3_memory_highwater(1)] is the high-water mark
** prior to the reset.
*/
-SQLITE_API sqlite3_int64 sqlite3_memory_used(void);
-SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag);
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_used(void);
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_highwater(int resetFlag);
/*
** CAPI3REF: Pseudo-Random Number Generator
@@ -2398,20 +2498,22 @@ SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag);
** applications to access the same PRNG for other purposes.
**
** ^A call to this routine stores N bytes of randomness into buffer P.
-** ^If N is less than one, then P can be a NULL pointer.
+** ^The P parameter can be a NULL pointer.
**
** ^If this routine has not been previously called or if the previous
-** call had N less than one, then the PRNG is seeded using randomness
-** obtained from the xRandomness method of the default [sqlite3_vfs] object.
-** ^If the previous call to this routine had an N of 1 or more then
-** the pseudo-randomness is generated
+** call had N less than one or a NULL pointer for P, then the PRNG is
+** seeded using randomness obtained from the xRandomness method of
+** the default [sqlite3_vfs] object.
+** ^If the previous call to this routine had an N of 1 or more and a
+** non-NULL P then the pseudo-randomness is generated
** internally and without recourse to the [sqlite3_vfs] xRandomness
** method.
*/
-SQLITE_API void sqlite3_randomness(int N, void *P);
+SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *P);
/*
** CAPI3REF: Compile-Time Authorization Callbacks
+** METHOD: sqlite3
**
** ^This routine registers an authorizer callback with a particular
** [database connection], supplied in the first argument.
@@ -2490,7 +2592,7 @@ SQLITE_API void sqlite3_randomness(int N, void *P);
** as stated in the previous paragraph, sqlite3_step() invokes
** sqlite3_prepare_v2() to reprepare a statement after a schema change.
*/
-SQLITE_API int sqlite3_set_authorizer(
+SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer(
sqlite3*,
int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
void *pUserData
@@ -2568,6 +2670,7 @@ SQLITE_API int sqlite3_set_authorizer(
/*
** CAPI3REF: Tracing And Profiling Functions
+** METHOD: sqlite3
**
** These routines register callback functions that can be used for
** tracing and profiling the execution of SQL statements.
@@ -2594,12 +2697,13 @@ SQLITE_API int sqlite3_set_authorizer(
** sqlite3_profile() function is considered experimental and is
** subject to change in future versions of SQLite.
*/
-SQLITE_API void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
-SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_profile(sqlite3*,
+SQLITE_API void *SQLITE_STDCALL sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
+SQLITE_API SQLITE_EXPERIMENTAL void *SQLITE_STDCALL sqlite3_profile(sqlite3*,
void(*xProfile)(void*,const char*,sqlite3_uint64), void*);
/*
** CAPI3REF: Query Progress Callbacks
+** METHOD: sqlite3
**
** ^The sqlite3_progress_handler(D,N,X,P) interface causes the callback
** function X to be invoked periodically during long running calls to
@@ -2629,10 +2733,11 @@ SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_profile(sqlite3*,
** database connections for the meaning of "modify" in this paragraph.
**
*/
-SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
+SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
/*
** CAPI3REF: Opening A New Database Connection
+** CONSTRUCTOR: sqlite3
**
** ^These routines open an SQLite database file as specified by the
** filename argument. ^The filename argument is interpreted as UTF-8 for
@@ -2647,9 +2752,9 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** an English language description of the error following a failure of any
** of the sqlite3_open() routines.
**
-** ^The default encoding for the database will be UTF-8 if
-** sqlite3_open() or sqlite3_open_v2() is called and
-** UTF-16 in the native byte order if sqlite3_open16() is used.
+** ^The default encoding will be UTF-8 for databases created using
+** sqlite3_open() or sqlite3_open_v2(). ^The default encoding for databases
+** created using sqlite3_open16() will be UTF-16 in the native byte order.
**
** Whether or not an error occurs when it is opened, resources
** associated with the [database connection] handle should be released by
@@ -2737,13 +2842,14 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** then it is interpreted as an absolute path. ^If the path does not begin
** with a '/' (meaning that the authority section is omitted from the URI)
** then the path is interpreted as a relative path.
-** ^On windows, the first component of an absolute path
-** is a drive specification (e.g. "C:").
+** ^(On windows, the first component of an absolute path
+** is a drive specification (e.g. "C:").)^
**
** [[core URI query parameters]]
** The query component of a URI may contain parameters that are interpreted
** either by SQLite itself, or by a [VFS | custom VFS implementation].
-** SQLite interprets the following three query parameters:
+** SQLite and its built-in [VFSes] interpret the
+** following query parameters:
**
** <ul>
** <li> <b>vfs</b>: ^The "vfs" parameter may be used to specify the name of
@@ -2778,11 +2884,9 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** a URI filename, its value overrides any behavior requested by setting
** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag.
**
-** <li> <b>psow</b>: ^The psow parameter may be "true" (or "on" or "yes" or
-** "1") or "false" (or "off" or "no" or "0") to indicate that the
+** <li> <b>psow</b>: ^The psow parameter indicates whether or not the
** [powersafe overwrite] property does or does not apply to the
-** storage media on which the database file resides. ^The psow query
-** parameter only works for the built-in unix and Windows VFSes.
+** storage media on which the database file resides.
**
** <li> <b>nolock</b>: ^The nolock parameter is a boolean query parameter
** which if set disables file locking in rollback journal modes. This
@@ -2858,15 +2962,15 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
**
** See also: [sqlite3_temp_directory]
*/
-SQLITE_API int sqlite3_open(
+SQLITE_API int SQLITE_STDCALL sqlite3_open(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb /* OUT: SQLite db handle */
);
-SQLITE_API int sqlite3_open16(
+SQLITE_API int SQLITE_STDCALL sqlite3_open16(
const void *filename, /* Database filename (UTF-16) */
sqlite3 **ppDb /* OUT: SQLite db handle */
);
-SQLITE_API int sqlite3_open_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_open_v2(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb, /* OUT: SQLite db handle */
int flags, /* Flags */
@@ -2912,19 +3016,22 @@ SQLITE_API int sqlite3_open_v2(
** VFS method, then the behavior of this routine is undefined and probably
** undesirable.
*/
-SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam);
-SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
-SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_uri_parameter(const char *zFilename, const char *zParam);
+SQLITE_API int SQLITE_STDCALL sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
/*
** CAPI3REF: Error Codes And Messages
-**
-** ^The sqlite3_errcode() interface returns the numeric [result code] or
-** [extended result code] for the most recent failed sqlite3_* API call
-** associated with a [database connection]. If a prior API call failed
-** but the most recent API call succeeded, the return value from
-** sqlite3_errcode() is undefined. ^The sqlite3_extended_errcode()
+** METHOD: sqlite3
+**
+** ^If the most recent sqlite3_* API call associated with
+** [database connection] D failed, then the sqlite3_errcode(D) interface
+** returns the numeric [result code] or [extended result code] for that
+** API call.
+** If the most recent API call was successful,
+** then the return value from sqlite3_errcode() is undefined.
+** ^The sqlite3_extended_errcode()
** interface is the same except that it always returns the
** [extended result code] even when extended result codes are
** disabled.
@@ -2955,40 +3062,41 @@ SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int
** was invoked incorrectly by the application. In that case, the
** error code and message may or may not be set.
*/
-SQLITE_API int sqlite3_errcode(sqlite3 *db);
-SQLITE_API int sqlite3_extended_errcode(sqlite3 *db);
-SQLITE_API const char *sqlite3_errmsg(sqlite3*);
-SQLITE_API const void *sqlite3_errmsg16(sqlite3*);
-SQLITE_API const char *sqlite3_errstr(int);
+SQLITE_API int SQLITE_STDCALL sqlite3_errcode(sqlite3 *db);
+SQLITE_API int SQLITE_STDCALL sqlite3_extended_errcode(sqlite3 *db);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_errmsg(sqlite3*);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_errmsg16(sqlite3*);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_errstr(int);
/*
-** CAPI3REF: SQL Statement Object
+** CAPI3REF: Prepared Statement Object
** KEYWORDS: {prepared statement} {prepared statements}
**
-** An instance of this object represents a single SQL statement.
-** This object is variously known as a "prepared statement" or a
-** "compiled SQL statement" or simply as a "statement".
+** An instance of this object represents a single SQL statement that
+** has been compiled into binary form and is ready to be evaluated.
+**
+** Think of each SQL statement as a separate computer program. The
+** original SQL text is source code. A prepared statement object
+** is the compiled object code. All SQL must be converted into a
+** prepared statement before it can be run.
**
-** The life of a statement object goes something like this:
+** The life-cycle of a prepared statement object usually goes like this:
**
** <ol>
-** <li> Create the object using [sqlite3_prepare_v2()] or a related
-** function.
-** <li> Bind values to [host parameters] using the sqlite3_bind_*()
+** <li> Create the prepared statement object using [sqlite3_prepare_v2()].
+** <li> Bind values to [parameters] using the sqlite3_bind_*()
** interfaces.
** <li> Run the SQL by calling [sqlite3_step()] one or more times.
-** <li> Reset the statement using [sqlite3_reset()] then go back
+** <li> Reset the prepared statement using [sqlite3_reset()] then go back
** to step 2. Do this zero or more times.
** <li> Destroy the object using [sqlite3_finalize()].
** </ol>
-**
-** Refer to documentation on individual methods above for additional
-** information.
*/
typedef struct sqlite3_stmt sqlite3_stmt;
/*
** CAPI3REF: Run-time Limits
+** METHOD: sqlite3
**
** ^(This interface allows the size of various constructs to be limited
** on a connection by connection basis. The first parameter is the
@@ -3026,7 +3134,7 @@ typedef struct sqlite3_stmt sqlite3_stmt;
**
** New run-time limit categories may be added in future releases.
*/
-SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
+SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal);
/*
** CAPI3REF: Run-Time Limit Categories
@@ -3078,6 +3186,10 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
**
** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(<dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt>
** <dd>The maximum depth of recursion for triggers.</dd>)^
+**
+** [[SQLITE_LIMIT_WORKER_THREADS]] ^(<dt>SQLITE_LIMIT_WORKER_THREADS</dt>
+** <dd>The maximum number of auxiliary worker threads that a single
+** [prepared statement] may start.</dd>)^
** </dl>
*/
#define SQLITE_LIMIT_LENGTH 0
@@ -3091,10 +3203,13 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
#define SQLITE_LIMIT_LIKE_PATTERN_LENGTH 8
#define SQLITE_LIMIT_VARIABLE_NUMBER 9
#define SQLITE_LIMIT_TRIGGER_DEPTH 10
+#define SQLITE_LIMIT_WORKER_THREADS 11
/*
** CAPI3REF: Compiling An SQL Statement
** KEYWORDS: {SQL statement compiler}
+** METHOD: sqlite3
+** CONSTRUCTOR: sqlite3_stmt
**
** To execute an SQL query, it must first be compiled into a byte-code
** program using one of these routines.
@@ -3108,16 +3223,14 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** interfaces use UTF-8, and sqlite3_prepare16() and sqlite3_prepare16_v2()
** use UTF-16.
**
-** ^If the nByte argument is less than zero, then zSql is read up to the
-** first zero terminator. ^If nByte is non-negative, then it is the maximum
-** number of bytes read from zSql. ^When nByte is non-negative, the
-** zSql string ends at either the first '\000' or '\u0000' character or
-** the nByte-th byte, whichever comes first. If the caller knows
-** that the supplied string is nul-terminated, then there is a small
-** performance advantage to be gained by passing an nByte parameter that
-** is equal to the number of bytes in the input string <i>including</i>
-** the nul-terminator bytes as this saves SQLite from having to
-** make a copy of the input string.
+** ^If the nByte argument is negative, then zSql is read up to the
+** first zero terminator. ^If nByte is positive, then it is the
+** number of bytes read from zSql. ^If nByte is zero, then no prepared
+** statement is generated.
+** If the caller knows that the supplied string is nul-terminated, then
+** there is a small performance advantage to passing an nByte parameter that
+** is the number of bytes in the input string <i>including</i>
+** the nul-terminator.
**
** ^If pzTail is not NULL then *pzTail is made to point to the first byte
** past the end of the first SQL statement in zSql. These routines only
@@ -3173,28 +3286,28 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** </li>
** </ol>
*/
-SQLITE_API int sqlite3_prepare(
+SQLITE_API int SQLITE_STDCALL sqlite3_prepare(
sqlite3 *db, /* Database handle */
const char *zSql, /* SQL statement, UTF-8 encoded */
int nByte, /* Maximum length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const char **pzTail /* OUT: Pointer to unused portion of zSql */
);
-SQLITE_API int sqlite3_prepare_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_prepare_v2(
sqlite3 *db, /* Database handle */
const char *zSql, /* SQL statement, UTF-8 encoded */
int nByte, /* Maximum length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const char **pzTail /* OUT: Pointer to unused portion of zSql */
);
-SQLITE_API int sqlite3_prepare16(
+SQLITE_API int SQLITE_STDCALL sqlite3_prepare16(
sqlite3 *db, /* Database handle */
const void *zSql, /* SQL statement, UTF-16 encoded */
int nByte, /* Maximum length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const void **pzTail /* OUT: Pointer to unused portion of zSql */
);
-SQLITE_API int sqlite3_prepare16_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_prepare16_v2(
sqlite3 *db, /* Database handle */
const void *zSql, /* SQL statement, UTF-16 encoded */
int nByte, /* Maximum length of zSql in bytes. */
@@ -3204,15 +3317,17 @@ SQLITE_API int sqlite3_prepare16_v2(
/*
** CAPI3REF: Retrieving Statement SQL
+** METHOD: sqlite3_stmt
**
** ^This interface can be used to retrieve a saved copy of the original
** SQL text used to create a [prepared statement] if that statement was
** compiled using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()].
*/
-SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Determine If An SQL Statement Writes The Database
+** METHOD: sqlite3_stmt
**
** ^The sqlite3_stmt_readonly(X) interface returns true (non-zero) if
** and only if the [prepared statement] X makes no direct changes to
@@ -3240,10 +3355,11 @@ SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt);
** change the configuration of a database connection, they do not make
** changes to the content of the database files on disk.
*/
-SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
+SQLITE_API int SQLITE_STDCALL sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Determine If A Prepared Statement Has Been Reset
+** METHOD: sqlite3_stmt
**
** ^The sqlite3_stmt_busy(S) interface returns true (non-zero) if the
** [prepared statement] S has been stepped at least once using
@@ -3259,7 +3375,7 @@ SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
** for example, in diagnostic routines to search for prepared
** statements that are holding a transaction open.
*/
-SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
+SQLITE_API int SQLITE_STDCALL sqlite3_stmt_busy(sqlite3_stmt*);
/*
** CAPI3REF: Dynamically Typed Value Object
@@ -3318,6 +3434,7 @@ typedef struct sqlite3_context sqlite3_context;
** CAPI3REF: Binding Values To Prepared Statements
** KEYWORDS: {host parameter} {host parameters} {host parameter name}
** KEYWORDS: {SQL parameter} {SQL parameters} {parameter binding}
+** METHOD: sqlite3_stmt
**
** ^(In the SQL statement text input to [sqlite3_prepare_v2()] and its variants,
** literals may be replaced by a [parameter] that matches one of following
@@ -3364,18 +3481,18 @@ typedef struct sqlite3_context sqlite3_context;
** If the fourth parameter to sqlite3_bind_blob() is negative, then
** the behavior is undefined.
** If a non-negative fourth parameter is provided to sqlite3_bind_text()
-** or sqlite3_bind_text16() then that parameter must be the byte offset
+** 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
** 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.
**
-** ^The fifth argument to sqlite3_bind_blob(), sqlite3_bind_text(), and
-** sqlite3_bind_text16() is a destructor used to dispose of the BLOB or
+** ^The fifth argument to the BLOB and string binding interfaces
+** is a destructor used to dispose of the BLOB or
** string after SQLite has finished with it. ^The destructor is called
-** to dispose of the BLOB or string even if the call to sqlite3_bind_blob(),
-** sqlite3_bind_text(), or sqlite3_bind_text16() fails.
+** to dispose of the BLOB or string even if the call to bind API fails.
** ^If the fifth argument is
** the special value [SQLITE_STATIC], then SQLite assumes that the
** information is in static, unmanaged space and does not need to be freed.
@@ -3383,6 +3500,14 @@ typedef struct sqlite3_context sqlite3_context;
** SQLite makes its own private copy of the data immediately, before
** the sqlite3_bind_*() routine returns.
**
+** ^The sixth argument to sqlite3_bind_text64() must be one of
+** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]
+** to specify the encoding of the text in the third parameter. If
+** the sixth argument to sqlite3_bind_text64() is not one of the
+** allowed values shown above, or if the text encoding is different
+** from the encoding specified by the sixth parameter, then the behavior
+** is undefined.
+**
** ^The sqlite3_bind_zeroblob() routine binds a BLOB of length N that
** is filled with zeroes. ^A zeroblob uses a fixed amount of memory
** (just an integer to hold its size) while it is being processed.
@@ -3403,24 +3528,32 @@ typedef struct sqlite3_context sqlite3_context;
**
** ^The sqlite3_bind_* routines return [SQLITE_OK] on success or an
** [error code] if anything goes wrong.
+** ^[SQLITE_TOOBIG] might be returned if the size of a string or BLOB
+** exceeds limits imposed by [sqlite3_limit]([SQLITE_LIMIT_LENGTH]) or
+** [SQLITE_MAX_LENGTH].
** ^[SQLITE_RANGE] is returned if the parameter
** index is out of range. ^[SQLITE_NOMEM] is returned if malloc() fails.
**
** See also: [sqlite3_bind_parameter_count()],
** [sqlite3_bind_parameter_name()], and [sqlite3_bind_parameter_index()].
*/
-SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
-SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double);
-SQLITE_API int sqlite3_bind_int(sqlite3_stmt*, int, int);
-SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
-SQLITE_API int sqlite3_bind_null(sqlite3_stmt*, int);
-SQLITE_API int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*));
-SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
-SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
-SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64,
+ void(*)(void*));
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_double(sqlite3_stmt*, int, double);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_int(sqlite3_stmt*, int, int);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_null(sqlite3_stmt*, int);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*));
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64,
+ void(*)(void*), unsigned char encoding);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
/*
** CAPI3REF: Number Of SQL Parameters
+** METHOD: sqlite3_stmt
**
** ^This routine can be used to find the number of [SQL parameters]
** in a [prepared statement]. SQL parameters are tokens of the
@@ -3437,10 +3570,11 @@ SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
** [sqlite3_bind_parameter_name()], and
** [sqlite3_bind_parameter_index()].
*/
-SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_count(sqlite3_stmt*);
/*
** CAPI3REF: Name Of A Host Parameter
+** METHOD: sqlite3_stmt
**
** ^The sqlite3_bind_parameter_name(P,N) interface returns
** the name of the N-th [SQL parameter] in the [prepared statement] P.
@@ -3464,10 +3598,11 @@ SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*);
** [sqlite3_bind_parameter_count()], and
** [sqlite3_bind_parameter_index()].
*/
-SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt*, int);
/*
** CAPI3REF: Index Of A Parameter With A Given Name
+** METHOD: sqlite3_stmt
**
** ^Return the index of an SQL parameter given its name. ^The
** index value returned is suitable for use as the second
@@ -3480,19 +3615,21 @@ SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int);
** [sqlite3_bind_parameter_count()], and
** [sqlite3_bind_parameter_index()].
*/
-SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
/*
** CAPI3REF: Reset All Bindings On A Prepared Statement
+** METHOD: sqlite3_stmt
**
** ^Contrary to the intuition of many, [sqlite3_reset()] does not reset
** the [sqlite3_bind_blob | bindings] on a [prepared statement].
** ^Use this routine to reset all host parameters to NULL.
*/
-SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*);
+SQLITE_API int SQLITE_STDCALL sqlite3_clear_bindings(sqlite3_stmt*);
/*
** CAPI3REF: Number Of Columns In A Result Set
+** METHOD: sqlite3_stmt
**
** ^Return the number of columns in the result set returned by the
** [prepared statement]. ^This routine returns 0 if pStmt is an SQL
@@ -3500,10 +3637,11 @@ SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*);
**
** See also: [sqlite3_data_count()]
*/
-SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt);
+SQLITE_API int SQLITE_STDCALL sqlite3_column_count(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Column Names In A Result Set
+** METHOD: sqlite3_stmt
**
** ^These routines return the name assigned to a particular column
** in the result set of a [SELECT] statement. ^The sqlite3_column_name()
@@ -3528,11 +3666,12 @@ SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt);
** then the name of the column is unspecified and may change from
** one release of SQLite to the next.
*/
-SQLITE_API const char *sqlite3_column_name(sqlite3_stmt*, int N);
-SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_column_name(sqlite3_stmt*, int N);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_name16(sqlite3_stmt*, int N);
/*
** CAPI3REF: Source Of Data In A Query Result
+** METHOD: sqlite3_stmt
**
** ^These routines provide a means to determine the database, table, and
** table column that is the origin of a particular result column in
@@ -3576,15 +3715,16 @@ SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N);
** for the same [prepared statement] and result column
** at the same time then the results are undefined.
*/
-SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt*,int);
-SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt*,int);
-SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt*,int);
-SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt*,int);
-SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt*,int);
-SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt*,int);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_column_database_name(sqlite3_stmt*,int);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_database_name16(sqlite3_stmt*,int);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_column_table_name(sqlite3_stmt*,int);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_table_name16(sqlite3_stmt*,int);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_column_origin_name(sqlite3_stmt*,int);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_origin_name16(sqlite3_stmt*,int);
/*
** CAPI3REF: Declared Datatype Of A Query Result
+** METHOD: sqlite3_stmt
**
** ^(The first parameter is a [prepared statement].
** If this statement is a [SELECT] statement and the Nth column of the
@@ -3612,11 +3752,12 @@ SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt*,int);
** is associated with individual values, not with the containers
** used to hold those values.
*/
-SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt*,int);
-SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_column_decltype(sqlite3_stmt*,int);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt*,int);
/*
** CAPI3REF: Evaluate An SQL Statement
+** METHOD: sqlite3_stmt
**
** After a [prepared statement] has been prepared using either
** [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] or one of the legacy
@@ -3692,10 +3833,11 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
** then the more specific [error codes] are returned directly
** by sqlite3_step(). The use of the "v2" interface is recommended.
*/
-SQLITE_API int sqlite3_step(sqlite3_stmt*);
+SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt*);
/*
** CAPI3REF: Number of columns in a result set
+** METHOD: sqlite3_stmt
**
** ^The sqlite3_data_count(P) interface returns the number of columns in the
** current row of the result set of [prepared statement] P.
@@ -3712,7 +3854,7 @@ SQLITE_API int sqlite3_step(sqlite3_stmt*);
**
** See also: [sqlite3_column_count()]
*/
-SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
+SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Fundamental Datatypes
@@ -3749,6 +3891,7 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Result Values From A Query
** KEYWORDS: {column access functions}
+** METHOD: sqlite3_stmt
**
** These routines form the "result set" interface.
**
@@ -3908,19 +4051,20 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
** pointer. Subsequent calls to [sqlite3_errcode()] will return
** [SQLITE_NOMEM].)^
*/
-SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
-SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
-SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
-SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol);
-SQLITE_API int sqlite3_column_int(sqlite3_stmt*, int iCol);
-SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
-SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
-SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
-SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol);
-SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_blob(sqlite3_stmt*, int iCol);
+SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes(sqlite3_stmt*, int iCol);
+SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
+SQLITE_API double SQLITE_STDCALL sqlite3_column_double(sqlite3_stmt*, int iCol);
+SQLITE_API int SQLITE_STDCALL sqlite3_column_int(sqlite3_stmt*, int iCol);
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_column_int64(sqlite3_stmt*, int iCol);
+SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_column_text(sqlite3_stmt*, int iCol);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_text16(sqlite3_stmt*, int iCol);
+SQLITE_API int SQLITE_STDCALL sqlite3_column_type(sqlite3_stmt*, int iCol);
+SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_column_value(sqlite3_stmt*, int iCol);
/*
** CAPI3REF: Destroy A Prepared Statement Object
+** DESTRUCTOR: sqlite3_stmt
**
** ^The sqlite3_finalize() function is called to delete a [prepared statement].
** ^If the most recent evaluation of the statement encountered no errors
@@ -3944,10 +4088,11 @@ SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
** statement after it has been finalized can result in undefined and
** undesirable behavior such as segfaults and heap corruption.
*/
-SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt);
+SQLITE_API int SQLITE_STDCALL sqlite3_finalize(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Reset A Prepared Statement Object
+** METHOD: sqlite3_stmt
**
** The sqlite3_reset() function is called to reset a [prepared statement]
** object back to its initial state, ready to be re-executed.
@@ -3970,13 +4115,14 @@ SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt);
** ^The [sqlite3_reset(S)] interface does not change the values
** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S.
*/
-SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
+SQLITE_API int SQLITE_STDCALL sqlite3_reset(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Create Or Redefine SQL Functions
** KEYWORDS: {function creation routines}
** KEYWORDS: {application-defined SQL function}
** KEYWORDS: {application-defined SQL functions}
+** METHOD: sqlite3
**
** ^These functions (collectively known as "function creation routines")
** are used to add SQL functions or aggregates or to redefine the behavior
@@ -4069,7 +4215,7 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
** close the database connection nor finalize or reset the prepared
** statement in which the function is running.
*/
-SQLITE_API int sqlite3_create_function(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_function(
sqlite3 *db,
const char *zFunctionName,
int nArg,
@@ -4079,7 +4225,7 @@ SQLITE_API int sqlite3_create_function(
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*)
);
-SQLITE_API int sqlite3_create_function16(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_function16(
sqlite3 *db,
const void *zFunctionName,
int nArg,
@@ -4089,7 +4235,7 @@ SQLITE_API int sqlite3_create_function16(
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*)
);
-SQLITE_API int sqlite3_create_function_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2(
sqlite3 *db,
const char *zFunctionName,
int nArg,
@@ -4107,9 +4253,9 @@ SQLITE_API int sqlite3_create_function_v2(
** These constant define integer codes that represent the various
** text encodings supported by SQLite.
*/
-#define SQLITE_UTF8 1
-#define SQLITE_UTF16LE 2
-#define SQLITE_UTF16BE 3
+#define SQLITE_UTF8 1 /* IMP: R-37514-35566 */
+#define SQLITE_UTF16LE 2 /* IMP: R-03371-37637 */
+#define SQLITE_UTF16BE 3 /* IMP: R-51971-34154 */
#define SQLITE_UTF16 4 /* Use native byte order */
#define SQLITE_ANY 5 /* Deprecated */
#define SQLITE_UTF16_ALIGNED 8 /* sqlite3_create_collation only */
@@ -4131,21 +4277,22 @@ SQLITE_API int sqlite3_create_function_v2(
** These functions are [deprecated]. In order to maintain
** backwards compatibility with older code, these functions continue
** to be supported. However, new applications should avoid
-** the use of these functions. To help encourage people to avoid
-** using these functions, we are not going to tell you what they do.
+** the use of these functions. To encourage programmers to avoid
+** these functions, we will not explain what they do.
*/
#ifndef SQLITE_OMIT_DEPRECATED
-SQLITE_API SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*);
-SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*);
-SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*);
-SQLITE_API SQLITE_DEPRECATED int sqlite3_global_recover(void);
-SQLITE_API SQLITE_DEPRECATED void sqlite3_thread_cleanup(void);
-SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
+SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_aggregate_count(sqlite3_context*);
+SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_expired(sqlite3_stmt*);
+SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*);
+SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_global_recover(void);
+SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_thread_cleanup(void);
+SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
void*,sqlite3_int64);
#endif
/*
** CAPI3REF: Obtaining SQL Function Parameter Values
+** METHOD: sqlite3_value
**
** The C-language implementation of SQL functions and aggregates uses
** this set of interface routines to access the parameter values on
@@ -4164,7 +4311,7 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6
** object results in undefined behavior.
**
** ^These routines work just like the corresponding [column access functions]
-** except that these routines take a single [protected sqlite3_value] object
+** except that these routines take a single [protected sqlite3_value] object
** pointer instead of a [sqlite3_stmt*] pointer and an integer column number.
**
** ^The sqlite3_value_text16() interface extracts a UTF-16 string
@@ -4189,21 +4336,22 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6
** These routines must be called from the same thread as
** the SQL function that supplied the [sqlite3_value*] parameters.
*/
-SQLITE_API const void *sqlite3_value_blob(sqlite3_value*);
-SQLITE_API int sqlite3_value_bytes(sqlite3_value*);
-SQLITE_API int sqlite3_value_bytes16(sqlite3_value*);
-SQLITE_API double sqlite3_value_double(sqlite3_value*);
-SQLITE_API int sqlite3_value_int(sqlite3_value*);
-SQLITE_API sqlite3_int64 sqlite3_value_int64(sqlite3_value*);
-SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value*);
-SQLITE_API const void *sqlite3_value_text16(sqlite3_value*);
-SQLITE_API const void *sqlite3_value_text16le(sqlite3_value*);
-SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*);
-SQLITE_API int sqlite3_value_type(sqlite3_value*);
-SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_value_blob(sqlite3_value*);
+SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes(sqlite3_value*);
+SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes16(sqlite3_value*);
+SQLITE_API double SQLITE_STDCALL sqlite3_value_double(sqlite3_value*);
+SQLITE_API int SQLITE_STDCALL sqlite3_value_int(sqlite3_value*);
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_value_int64(sqlite3_value*);
+SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_value_text(sqlite3_value*);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16(sqlite3_value*);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16le(sqlite3_value*);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16be(sqlite3_value*);
+SQLITE_API int SQLITE_STDCALL sqlite3_value_type(sqlite3_value*);
+SQLITE_API int SQLITE_STDCALL sqlite3_value_numeric_type(sqlite3_value*);
/*
** CAPI3REF: Obtain Aggregate Function Context
+** METHOD: sqlite3_context
**
** Implementations of aggregate SQL functions use this
** routine to allocate memory for storing their state.
@@ -4244,10 +4392,11 @@ SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
** This routine must be called from the same thread in which
** the aggregate SQL function is running.
*/
-SQLITE_API void *sqlite3_aggregate_context(sqlite3_context*, int nBytes);
+SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context*, int nBytes);
/*
** CAPI3REF: User Data For Functions
+** METHOD: sqlite3_context
**
** ^The sqlite3_user_data() interface returns a copy of
** the pointer that was the pUserData parameter (the 5th parameter)
@@ -4258,10 +4407,11 @@ SQLITE_API void *sqlite3_aggregate_context(sqlite3_context*, int nBytes);
** This routine must be called from the same thread in which
** the application-defined function is running.
*/
-SQLITE_API void *sqlite3_user_data(sqlite3_context*);
+SQLITE_API void *SQLITE_STDCALL sqlite3_user_data(sqlite3_context*);
/*
** CAPI3REF: Database Connection For Functions
+** METHOD: sqlite3_context
**
** ^The sqlite3_context_db_handle() interface returns a copy of
** the pointer to the [database connection] (the 1st parameter)
@@ -4269,10 +4419,11 @@ SQLITE_API void *sqlite3_user_data(sqlite3_context*);
** and [sqlite3_create_function16()] routines that originally
** registered the application defined function.
*/
-SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
+SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*);
/*
** CAPI3REF: Function Auxiliary Data
+** METHOD: sqlite3_context
**
** These functions may be used by (non-aggregate) SQL functions to
** associate metadata with argument values. If the same value is passed to
@@ -4321,8 +4472,8 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
** These routines must be called from the same thread in which
** the SQL function is running.
*/
-SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N);
-SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
+SQLITE_API void *SQLITE_STDCALL sqlite3_get_auxdata(sqlite3_context*, int N);
+SQLITE_API void SQLITE_STDCALL sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
/*
@@ -4345,6 +4496,7 @@ typedef void (*sqlite3_destructor_type)(void*);
/*
** CAPI3REF: Setting The Result Of An SQL Function
+** METHOD: sqlite3_context
**
** These routines are used by the xFunc or xFinal callbacks that
** implement SQL functions and aggregates. See
@@ -4411,6 +4563,10 @@ typedef void (*sqlite3_destructor_type)(void*);
** set the return value of the application-defined function to be
** a text string which is represented as UTF-8, UTF-16 native byte order,
** UTF-16 little endian, or UTF-16 big endian, respectively.
+** ^The sqlite3_result_text64() interface sets the return value of an
+** application-defined function to be a text string in an encoding
+** specified by the fifth (and last) parameter, which must be one
+** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE].
** ^SQLite takes the text result from the application from
** the 2nd parameter of the sqlite3_result_text* interfaces.
** ^If the 3rd parameter to the sqlite3_result_text* interfaces
@@ -4453,25 +4609,30 @@ typedef void (*sqlite3_destructor_type)(void*);
** than the one containing the application-defined function that received
** the [sqlite3_context] pointer, the results are undefined.
*/
-SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
-SQLITE_API void sqlite3_result_double(sqlite3_context*, double);
-SQLITE_API void sqlite3_result_error(sqlite3_context*, const char*, int);
-SQLITE_API void sqlite3_result_error16(sqlite3_context*, const void*, int);
-SQLITE_API void sqlite3_result_error_toobig(sqlite3_context*);
-SQLITE_API void sqlite3_result_error_nomem(sqlite3_context*);
-SQLITE_API void sqlite3_result_error_code(sqlite3_context*, int);
-SQLITE_API void sqlite3_result_int(sqlite3_context*, int);
-SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
-SQLITE_API void sqlite3_result_null(sqlite3_context*);
-SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
-SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*));
-SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
-SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
-SQLITE_API void sqlite3_result_value(sqlite3_context*, sqlite3_value*);
-SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
+SQLITE_API void SQLITE_STDCALL sqlite3_result_blob64(sqlite3_context*,const void*,
+ sqlite3_uint64,void(*)(void*));
+SQLITE_API void SQLITE_STDCALL sqlite3_result_double(sqlite3_context*, double);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_error(sqlite3_context*, const char*, int);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_error16(sqlite3_context*, const void*, int);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_error_toobig(sqlite3_context*);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_error_nomem(sqlite3_context*);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_error_code(sqlite3_context*, int);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_int(sqlite3_context*, int);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_null(sqlite3_context*);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
+SQLITE_API void SQLITE_STDCALL sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64,
+ void(*)(void*), unsigned char encoding);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*));
+SQLITE_API void SQLITE_STDCALL sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
+SQLITE_API void SQLITE_STDCALL sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
+SQLITE_API void SQLITE_STDCALL sqlite3_result_value(sqlite3_context*, sqlite3_value*);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_zeroblob(sqlite3_context*, int n);
/*
** CAPI3REF: Define New Collating Sequences
+** METHOD: sqlite3
**
** ^These functions add, remove, or modify a [collation] associated
** with the [database connection] specified as the first argument.
@@ -4549,14 +4710,14 @@ SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n);
**
** See also: [sqlite3_collation_needed()] and [sqlite3_collation_needed16()].
*/
-SQLITE_API int sqlite3_create_collation(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_collation(
sqlite3*,
const char *zName,
int eTextRep,
void *pArg,
int(*xCompare)(void*,int,const void*,int,const void*)
);
-SQLITE_API int sqlite3_create_collation_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_collation_v2(
sqlite3*,
const char *zName,
int eTextRep,
@@ -4564,7 +4725,7 @@ SQLITE_API int sqlite3_create_collation_v2(
int(*xCompare)(void*,int,const void*,int,const void*),
void(*xDestroy)(void*)
);
-SQLITE_API int sqlite3_create_collation16(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_collation16(
sqlite3*,
const void *zName,
int eTextRep,
@@ -4574,6 +4735,7 @@ SQLITE_API int sqlite3_create_collation16(
/*
** CAPI3REF: Collation Needed Callbacks
+** METHOD: sqlite3
**
** ^To avoid having to register all collation sequences before a database
** can be used, a single callback function may be registered with the
@@ -4598,12 +4760,12 @@ SQLITE_API int sqlite3_create_collation16(
** [sqlite3_create_collation()], [sqlite3_create_collation16()], or
** [sqlite3_create_collation_v2()].
*/
-SQLITE_API int sqlite3_collation_needed(
+SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed(
sqlite3*,
void*,
void(*)(void*,sqlite3*,int eTextRep,const char*)
);
-SQLITE_API int sqlite3_collation_needed16(
+SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed16(
sqlite3*,
void*,
void(*)(void*,sqlite3*,int eTextRep,const void*)
@@ -4617,11 +4779,11 @@ SQLITE_API int sqlite3_collation_needed16(
** The code to implement this API is not available in the public release
** of SQLite.
*/
-SQLITE_API int sqlite3_key(
+SQLITE_API int SQLITE_STDCALL sqlite3_key(
sqlite3 *db, /* Database to be rekeyed */
const void *pKey, int nKey /* The key */
);
-SQLITE_API int sqlite3_key_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_key_v2(
sqlite3 *db, /* Database to be rekeyed */
const char *zDbName, /* Name of the database */
const void *pKey, int nKey /* The key */
@@ -4635,11 +4797,11 @@ SQLITE_API int sqlite3_key_v2(
** The code to implement this API is not available in the public release
** of SQLite.
*/
-SQLITE_API int sqlite3_rekey(
+SQLITE_API int SQLITE_STDCALL sqlite3_rekey(
sqlite3 *db, /* Database to be rekeyed */
const void *pKey, int nKey /* The new key */
);
-SQLITE_API int sqlite3_rekey_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_rekey_v2(
sqlite3 *db, /* Database to be rekeyed */
const char *zDbName, /* Name of the database */
const void *pKey, int nKey /* The new key */
@@ -4649,7 +4811,7 @@ SQLITE_API int sqlite3_rekey_v2(
** Specify the activation key for a SEE database. Unless
** activated, none of the SEE routines will work.
*/
-SQLITE_API void sqlite3_activate_see(
+SQLITE_API void SQLITE_STDCALL sqlite3_activate_see(
const char *zPassPhrase /* Activation phrase */
);
#endif
@@ -4659,7 +4821,7 @@ SQLITE_API void sqlite3_activate_see(
** Specify the activation key for a CEROD database. Unless
** activated, none of the CEROD routines will work.
*/
-SQLITE_API void sqlite3_activate_cerod(
+SQLITE_API void SQLITE_STDCALL sqlite3_activate_cerod(
const char *zPassPhrase /* Activation phrase */
);
#endif
@@ -4681,7 +4843,7 @@ SQLITE_API void sqlite3_activate_cerod(
** all, then the behavior of sqlite3_sleep() may deviate from the description
** in the previous paragraphs.
*/
-SQLITE_API int sqlite3_sleep(int);
+SQLITE_API int SQLITE_STDCALL sqlite3_sleep(int);
/*
** CAPI3REF: Name Of The Folder Holding Temporary Files
@@ -4781,6 +4943,7 @@ SQLITE_API SQLITE_EXTERN char *sqlite3_data_directory;
/*
** CAPI3REF: Test For Auto-Commit Mode
** KEYWORDS: {autocommit mode}
+** METHOD: sqlite3
**
** ^The sqlite3_get_autocommit() interface returns non-zero or
** zero if the given database connection is or is not in autocommit mode,
@@ -4799,10 +4962,11 @@ SQLITE_API SQLITE_EXTERN char *sqlite3_data_directory;
** connection while this routine is running, then the return value
** is undefined.
*/
-SQLITE_API int sqlite3_get_autocommit(sqlite3*);
+SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3*);
/*
** CAPI3REF: Find The Database Handle Of A Prepared Statement
+** METHOD: sqlite3_stmt
**
** ^The sqlite3_db_handle interface returns the [database connection] handle
** to which a [prepared statement] belongs. ^The [database connection]
@@ -4811,10 +4975,11 @@ SQLITE_API int sqlite3_get_autocommit(sqlite3*);
** to the [sqlite3_prepare_v2()] call (or its variants) that was used to
** create the statement in the first place.
*/
-SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
+SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_db_handle(sqlite3_stmt*);
/*
** CAPI3REF: Return The Filename For A Database Connection
+** METHOD: sqlite3
**
** ^The sqlite3_db_filename(D,N) interface returns a pointer to a filename
** associated with database N of connection D. ^The main database file
@@ -4827,19 +4992,21 @@ SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
** will be an absolute pathname, even if the filename used
** to open the database originally was a URI or relative pathname.
*/
-SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_db_filename(sqlite3 *db, const char *zDbName);
/*
** CAPI3REF: Determine if a database is read-only
+** METHOD: sqlite3
**
** ^The sqlite3_db_readonly(D,N) interface returns 1 if the database N
** of connection D is read-only, 0 if it is read/write, or -1 if N is not
** the name of a database on connection D.
*/
-SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
+SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
/*
** CAPI3REF: Find the next prepared statement
+** METHOD: sqlite3
**
** ^This interface returns a pointer to the next [prepared statement] after
** pStmt associated with the [database connection] pDb. ^If pStmt is NULL
@@ -4851,10 +5018,11 @@ SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
** [sqlite3_next_stmt(D,S)] must refer to an open database
** connection and in particular must not be a NULL pointer.
*/
-SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
+SQLITE_API sqlite3_stmt *SQLITE_STDCALL sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
/*
** CAPI3REF: Commit And Rollback Notification Callbacks
+** METHOD: sqlite3
**
** ^The sqlite3_commit_hook() interface registers a callback
** function to be invoked whenever a transaction is [COMMIT | committed].
@@ -4899,11 +5067,12 @@ SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
**
** See also the [sqlite3_update_hook()] interface.
*/
-SQLITE_API void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
-SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
+SQLITE_API void *SQLITE_STDCALL sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
+SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
/*
** CAPI3REF: Data Change Notification Callbacks
+** METHOD: sqlite3
**
** ^The sqlite3_update_hook() interface registers a callback function
** with the [database connection] identified by the first argument
@@ -4950,7 +5119,7 @@ SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
** See also the [sqlite3_commit_hook()] and [sqlite3_rollback_hook()]
** interfaces.
*/
-SQLITE_API void *sqlite3_update_hook(
+SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook(
sqlite3*,
void(*)(void *,int ,char const *,char const *,sqlite3_int64),
void*
@@ -4980,12 +5149,17 @@ SQLITE_API void *sqlite3_update_hook(
** future releases of SQLite. Applications that care about shared
** cache setting should set it explicitly.
**
+** Note: This method is disabled on MacOS X 10.7 and iOS version 5.0
+** and will always return SQLITE_MISUSE. On those systems,
+** shared cache mode should be enabled per-database connection via
+** [sqlite3_open_v2()] with [SQLITE_OPEN_SHAREDCACHE].
+**
** This interface is threadsafe on processors where writing a
** 32-bit integer is atomic.
**
** See Also: [SQLite Shared-Cache Mode]
*/
-SQLITE_API int sqlite3_enable_shared_cache(int);
+SQLITE_API int SQLITE_STDCALL sqlite3_enable_shared_cache(int);
/*
** CAPI3REF: Attempt To Free Heap Memory
@@ -5001,10 +5175,11 @@ SQLITE_API int sqlite3_enable_shared_cache(int);
**
** See also: [sqlite3_db_release_memory()]
*/
-SQLITE_API int sqlite3_release_memory(int);
+SQLITE_API int SQLITE_STDCALL sqlite3_release_memory(int);
/*
** CAPI3REF: Free Memory Used By A Database Connection
+** METHOD: sqlite3
**
** ^The sqlite3_db_release_memory(D) interface attempts to free as much heap
** memory as possible from database connection D. Unlike the
@@ -5014,7 +5189,7 @@ SQLITE_API int sqlite3_release_memory(int);
**
** See also: [sqlite3_release_memory()]
*/
-SQLITE_API int sqlite3_db_release_memory(sqlite3*);
+SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3*);
/*
** CAPI3REF: Impose A Limit On Heap Size
@@ -5066,7 +5241,7 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*);
** The circumstances under which SQLite will enforce the soft heap limit may
** changes in future releases of SQLite.
*/
-SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N);
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_soft_heap_limit64(sqlite3_int64 N);
/*
** CAPI3REF: Deprecated Soft Heap Limit Interface
@@ -5077,26 +5252,34 @@ SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N);
** only. All new applications should use the
** [sqlite3_soft_heap_limit64()] interface rather than this one.
*/
-SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
+SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_soft_heap_limit(int N);
/*
** CAPI3REF: Extract Metadata About A Column Of A Table
-**
-** ^This routine returns metadata about a specific column of a specific
-** database table accessible using the [database connection] handle
-** passed as the first function argument.
+** METHOD: sqlite3
+**
+** ^(The sqlite3_table_column_metadata(X,D,T,C,....) routine returns
+** information about column C of table T in database D
+** on [database connection] X.)^ ^The sqlite3_table_column_metadata()
+** interface returns SQLITE_OK and fills in the non-NULL pointers in
+** the final five arguments with appropriate values if the specified
+** column exists. ^The sqlite3_table_column_metadata() interface returns
+** SQLITE_ERROR and if the specified column does not exist.
+** ^If the column-name parameter to sqlite3_table_column_metadata() is a
+** NULL pointer, then this routine simply checks for the existance of the
+** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it
+** does not.
**
** ^The column is identified by the second, third and fourth parameters to
-** this function. ^The second parameter is either the name of the database
+** this function. ^(The second parameter is either the name of the database
** (i.e. "main", "temp", or an attached database) containing the specified
-** table or NULL. ^If it is NULL, then all attached databases are searched
+** table or NULL.)^ ^If it is NULL, then all attached databases are searched
** for the table using the same algorithm used by the database engine to
** resolve unqualified table references.
**
** ^The third and fourth parameters to this function are the table and column
-** name of the desired column, respectively. Neither of these parameters
-** may be NULL.
+** name of the desired column, respectively.
**
** ^Metadata is returned by writing to the memory locations passed as the 5th
** and subsequent parameters to this function. ^Any of these arguments may be
@@ -5115,16 +5298,17 @@ SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
** </blockquote>)^
**
** ^The memory pointed to by the character pointers returned for the
-** declaration type and collation sequence is valid only until the next
+** declaration type and collation sequence is valid until the next
** call to any SQLite API function.
**
** ^If the specified table is actually a view, an [error code] is returned.
**
-** ^If the specified column is "rowid", "oid" or "_rowid_" and an
+** ^If the specified column is "rowid", "oid" or "_rowid_" and the table
+** is not a [WITHOUT ROWID] table and an
** [INTEGER PRIMARY KEY] column has been explicitly declared, then the output
** parameters are set for the explicitly declared column. ^(If there is no
-** explicitly declared [INTEGER PRIMARY KEY] column, then the output
-** parameters are set as follows:
+** [INTEGER PRIMARY KEY] column, then the outputs
+** for the [rowid] are set as follows:
**
** <pre>
** data type: "INTEGER"
@@ -5134,15 +5318,11 @@ SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
** auto increment: 0
** </pre>)^
**
-** ^(This function may load one or more schemas from database files. If an
-** error occurs during this process, or if the requested table or column
-** cannot be found, an [error code] is returned and an error message left
-** in the [database connection] (to be retrieved using sqlite3_errmsg()).)^
-**
-** ^This API is only available if the library was compiled with the
-** [SQLITE_ENABLE_COLUMN_METADATA] C-preprocessor symbol defined.
+** ^This function causes all database schemas to be read from disk and
+** parsed, if that has not already been done, and returns an error if
+** any errors are encountered while loading the schema.
*/
-SQLITE_API int sqlite3_table_column_metadata(
+SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata(
sqlite3 *db, /* Connection handle */
const char *zDbName, /* Database name or NULL */
const char *zTableName, /* Table name */
@@ -5156,6 +5336,7 @@ SQLITE_API int sqlite3_table_column_metadata(
/*
** CAPI3REF: Load An Extension
+** METHOD: sqlite3
**
** ^This interface loads an SQLite extension library from the named file.
**
@@ -5188,7 +5369,7 @@ SQLITE_API int sqlite3_table_column_metadata(
**
** See also the [load_extension() SQL function].
*/
-SQLITE_API int sqlite3_load_extension(
+SQLITE_API int SQLITE_STDCALL sqlite3_load_extension(
sqlite3 *db, /* Load the extension into this database connection */
const char *zFile, /* Name of the shared library containing extension */
const char *zProc, /* Entry point. Derived from zFile if 0 */
@@ -5197,6 +5378,7 @@ SQLITE_API int sqlite3_load_extension(
/*
** CAPI3REF: Enable Or Disable Extension Loading
+** METHOD: sqlite3
**
** ^So as not to open security holes in older applications that are
** unprepared to deal with [extension loading], and as a means of disabling
@@ -5208,7 +5390,7 @@ SQLITE_API int sqlite3_load_extension(
** to turn extension loading on and call it with onoff==0 to turn
** it back off again.
*/
-SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
+SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int onoff);
/*
** CAPI3REF: Automatically Load Statically Linked Extensions
@@ -5246,7 +5428,7 @@ SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
** See also: [sqlite3_reset_auto_extension()]
** and [sqlite3_cancel_auto_extension()]
*/
-SQLITE_API int sqlite3_auto_extension(void (*xEntryPoint)(void));
+SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xEntryPoint)(void));
/*
** CAPI3REF: Cancel Automatic Extension Loading
@@ -5258,7 +5440,7 @@ SQLITE_API int sqlite3_auto_extension(void (*xEntryPoint)(void));
** unregistered and it returns 0 if X was not on the list of initialization
** routines.
*/
-SQLITE_API int sqlite3_cancel_auto_extension(void (*xEntryPoint)(void));
+SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xEntryPoint)(void));
/*
** CAPI3REF: Reset Automatic Extension Loading
@@ -5266,7 +5448,7 @@ SQLITE_API int sqlite3_cancel_auto_extension(void (*xEntryPoint)(void));
** ^This interface disables all automatic extensions previously
** registered using [sqlite3_auto_extension()].
*/
-SQLITE_API void sqlite3_reset_auto_extension(void);
+SQLITE_API void SQLITE_STDCALL sqlite3_reset_auto_extension(void);
/*
** The interface to the virtual-table mechanism is currently considered
@@ -5446,6 +5628,7 @@ struct sqlite3_index_info {
/*
** CAPI3REF: Register A Virtual Table Implementation
+** METHOD: sqlite3
**
** ^These routines are used to register a new [virtual table module] name.
** ^Module names must be registered before
@@ -5469,13 +5652,13 @@ struct sqlite3_index_info {
** interface is equivalent to sqlite3_create_module_v2() with a NULL
** destructor.
*/
-SQLITE_API int sqlite3_create_module(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_module(
sqlite3 *db, /* SQLite connection to register module with */
const char *zName, /* Name of the module */
const sqlite3_module *p, /* Methods for the module */
void *pClientData /* Client data for xCreate/xConnect */
);
-SQLITE_API int sqlite3_create_module_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_module_v2(
sqlite3 *db, /* SQLite connection to register module with */
const char *zName, /* Name of the module */
const sqlite3_module *p, /* Methods for the module */
@@ -5503,7 +5686,7 @@ SQLITE_API int sqlite3_create_module_v2(
*/
struct sqlite3_vtab {
const sqlite3_module *pModule; /* The module for this virtual table */
- int nRef; /* NO LONGER USED */
+ int nRef; /* Number of open cursors */
char *zErrMsg; /* Error message from sqlite3_mprintf() */
/* Virtual table implementations will typically add additional fields */
};
@@ -5538,10 +5721,11 @@ struct sqlite3_vtab_cursor {
** to declare the format (the names and datatypes of the columns) of
** the virtual tables they implement.
*/
-SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
+SQLITE_API int SQLITE_STDCALL sqlite3_declare_vtab(sqlite3*, const char *zSQL);
/*
** CAPI3REF: Overload A Function For A Virtual Table
+** METHOD: sqlite3
**
** ^(Virtual tables can provide alternative implementations of functions
** using the [xFindFunction] method of the [virtual table module].
@@ -5556,7 +5740,7 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
** purpose is to be a placeholder function that can be overloaded
** by a [virtual table].
*/
-SQLITE_API int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
+SQLITE_API int SQLITE_STDCALL sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
/*
** The interface to the virtual-table mechanism defined above (back up
@@ -5584,6 +5768,8 @@ typedef struct sqlite3_blob sqlite3_blob;
/*
** CAPI3REF: Open A BLOB For Incremental I/O
+** METHOD: sqlite3
+** CONSTRUCTOR: sqlite3_blob
**
** ^(This interfaces opens a [BLOB handle | handle] to the BLOB located
** in row iRow, column zColumn, table zTable in database zDb;
@@ -5593,26 +5779,42 @@ typedef struct sqlite3_blob sqlite3_blob;
** SELECT zColumn FROM zDb.zTable WHERE [rowid] = iRow;
** </pre>)^
**
+** ^(Parameter zDb is not the filename that contains the database, but
+** rather the symbolic name of the database. For attached databases, this is
+** the name that appears after the AS keyword in the [ATTACH] statement.
+** For the main database file, the database name is "main". For TEMP
+** tables, the database name is "temp".)^
+**
** ^If the flags parameter is non-zero, then the BLOB is opened for read
-** and write access. ^If it is zero, the BLOB is opened for read access.
-** ^It is not possible to open a column that is part of an index or primary
-** key for writing. ^If [foreign key constraints] are enabled, it is
-** not possible to open a column that is part of a [child key] for writing.
-**
-** ^Note that the database name is not the filename that contains
-** the database but rather the symbolic name of the database that
-** appears after the AS keyword when the database is connected using [ATTACH].
-** ^For the main database file, the database name is "main".
-** ^For TEMP tables, the database name is "temp".
-**
-** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is written
-** to *ppBlob. Otherwise an [error code] is returned and *ppBlob is set
-** to be a null pointer.)^
-** ^This function sets the [database connection] error code and message
-** accessible via [sqlite3_errcode()] and [sqlite3_errmsg()] and related
-** functions. ^Note that the *ppBlob variable is always initialized in a
-** way that makes it safe to invoke [sqlite3_blob_close()] on *ppBlob
-** regardless of the success or failure of this routine.
+** and write access. ^If the flags parameter is zero, the BLOB is opened for
+** read-only access.
+**
+** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is stored
+** in *ppBlob. Otherwise an [error code] is returned and, unless the error
+** code is SQLITE_MISUSE, *ppBlob is set to NULL.)^ ^This means that, provided
+** the API is not misused, it is always safe to call [sqlite3_blob_close()]
+** on *ppBlob after this function it returns.
+**
+** This function fails with SQLITE_ERROR if any of the following are true:
+** <ul>
+** <li> ^(Database zDb does not exist)^,
+** <li> ^(Table zTable does not exist within database zDb)^,
+** <li> ^(Table zTable is a WITHOUT ROWID table)^,
+** <li> ^(Column zColumn does not exist)^,
+** <li> ^(Row iRow is not present in the table)^,
+** <li> ^(The specified column of row iRow contains a value that is not
+** a TEXT or BLOB value)^,
+** <li> ^(Column zColumn is part of an index, PRIMARY KEY or UNIQUE
+** constraint and the blob is being opened for read/write access)^,
+** <li> ^([foreign key constraints | Foreign key constraints] are enabled,
+** column zColumn is part of a [child key] definition and the blob is
+** being opened for read/write access)^.
+** </ul>
+**
+** ^Unless it returns SQLITE_MISUSE, this function sets the
+** [database connection] error code and message accessible via
+** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions.
+**
**
** ^(If the row that a BLOB handle points to is modified by an
** [UPDATE], [DELETE], or by [ON CONFLICT] side-effects
@@ -5630,18 +5832,14 @@ typedef struct sqlite3_blob sqlite3_blob;
** interface. Use the [UPDATE] SQL command to change the size of a
** blob.
**
-** ^The [sqlite3_blob_open()] interface will fail for a [WITHOUT ROWID]
-** table. Incremental BLOB I/O is not possible on [WITHOUT ROWID] tables.
-**
** ^The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces
-** and the built-in [zeroblob] SQL function can be used, if desired,
-** to create an empty, zero-filled blob in which to read or write using
-** this interface.
+** and the built-in [zeroblob] SQL function may be used to create a
+** zero-filled blob to read or write using the incremental-blob interface.
**
** To avoid a resource leak, every open [BLOB handle] should eventually
** be released by a call to [sqlite3_blob_close()].
*/
-SQLITE_API int sqlite3_blob_open(
+SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
sqlite3*,
const char *zDb,
const char *zTable,
@@ -5653,6 +5851,7 @@ SQLITE_API int sqlite3_blob_open(
/*
** CAPI3REF: Move a BLOB Handle to a New Row
+** METHOD: sqlite3_blob
**
** ^This function is used to move an existing blob handle so that it points
** to a different row of the same database table. ^The new row is identified
@@ -5673,34 +5872,34 @@ SQLITE_API int sqlite3_blob_open(
**
** ^This function sets the database handle error code and message.
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
+SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
/*
** CAPI3REF: Close A BLOB Handle
+** DESTRUCTOR: sqlite3_blob
**
-** ^Closes an open [BLOB handle].
-**
-** ^Closing a BLOB shall cause the current transaction to commit
-** if there are no other BLOBs, no pending prepared statements, and the
-** database connection is in [autocommit mode].
-** ^If any writes were made to the BLOB, they might be held in cache
-** until the close operation if they will fit.
-**
-** ^(Closing the BLOB often forces the changes
-** out to disk and so if any I/O errors occur, they will likely occur
-** at the time when the BLOB is closed. Any errors that occur during
-** closing are reported as a non-zero return value.)^
+** ^This function closes an open [BLOB handle]. ^(The BLOB handle is closed
+** unconditionally. Even if this routine returns an error code, the
+** handle is still closed.)^
**
-** ^(The BLOB is closed unconditionally. Even if this routine returns
-** an error code, the BLOB is still closed.)^
+** ^If the blob handle being closed was opened for read-write access, and if
+** the database is in auto-commit mode and there are no other open read-write
+** blob handles or active write statements, the current transaction is
+** committed. ^If an error occurs while committing the transaction, an error
+** code is returned and the transaction rolled back.
**
-** ^Calling this routine with a null pointer (such as would be returned
-** by a failed call to [sqlite3_blob_open()]) is a harmless no-op.
+** Calling this function with an argument that is not a NULL pointer or an
+** open blob handle results in undefined behaviour. ^Calling this routine
+** with a null pointer (such as would be returned by a failed call to
+** [sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function
+** is passed a valid open blob handle, the values returned by the
+** sqlite3_errcode() and sqlite3_errmsg() functions are set before returning.
*/
-SQLITE_API int sqlite3_blob_close(sqlite3_blob *);
+SQLITE_API int SQLITE_STDCALL sqlite3_blob_close(sqlite3_blob *);
/*
** CAPI3REF: Return The Size Of An Open BLOB
+** METHOD: sqlite3_blob
**
** ^Returns the size in bytes of the BLOB accessible via the
** successfully opened [BLOB handle] in its only argument. ^The
@@ -5712,10 +5911,11 @@ SQLITE_API int sqlite3_blob_close(sqlite3_blob *);
** been closed by [sqlite3_blob_close()]. Passing any other pointer in
** to this routine results in undefined and probably undesirable behavior.
*/
-SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *);
+SQLITE_API int SQLITE_STDCALL sqlite3_blob_bytes(sqlite3_blob *);
/*
** CAPI3REF: Read Data From A BLOB Incrementally
+** METHOD: sqlite3_blob
**
** ^(This function is used to read data from an open [BLOB handle] into a
** caller-supplied buffer. N bytes of data are copied into buffer Z
@@ -5740,26 +5940,33 @@ SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *);
**
** See also: [sqlite3_blob_write()].
*/
-SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
+SQLITE_API int SQLITE_STDCALL sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
/*
** CAPI3REF: Write Data Into A BLOB Incrementally
+** METHOD: sqlite3_blob
**
-** ^This function is used to write data into an open [BLOB handle] from a
-** caller-supplied buffer. ^N bytes of data are copied from the buffer Z
-** into the open BLOB, starting at offset iOffset.
+** ^(This function is used to write data into an open [BLOB handle] from a
+** caller-supplied buffer. N bytes of data are copied from the buffer Z
+** into the open BLOB, starting at offset iOffset.)^
+**
+** ^(On success, sqlite3_blob_write() returns SQLITE_OK.
+** Otherwise, an [error code] or an [extended error code] is returned.)^
+** ^Unless SQLITE_MISUSE is returned, this function sets the
+** [database connection] error code and message accessible via
+** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions.
**
** ^If the [BLOB handle] passed as the first argument was not opened for
** writing (the flags parameter to [sqlite3_blob_open()] was zero),
** this function returns [SQLITE_READONLY].
**
-** ^This function may only modify the contents of the BLOB; it is
+** This function may only modify the contents of the BLOB; it is
** not possible to increase the size of a BLOB using this API.
** ^If offset iOffset is less than N bytes from the end of the BLOB,
-** [SQLITE_ERROR] is returned and no data is written. ^If N is
-** less than zero [SQLITE_ERROR] is returned and no data is written.
-** The size of the BLOB (and hence the maximum value of N+iOffset)
-** can be determined using the [sqlite3_blob_bytes()] interface.
+** [SQLITE_ERROR] is returned and no data is written. The size of the
+** BLOB (and hence the maximum value of N+iOffset) can be determined
+** using the [sqlite3_blob_bytes()] interface. ^If N or iOffset are less
+** than zero [SQLITE_ERROR] is returned and no data is written.
**
** ^An attempt to write to an expired [BLOB handle] fails with an
** error code of [SQLITE_ABORT]. ^Writes to the BLOB that occurred
@@ -5768,9 +5975,6 @@ SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
** have been overwritten by the statement that expired the BLOB handle
** or by other independent statements.
**
-** ^(On success, sqlite3_blob_write() returns SQLITE_OK.
-** Otherwise, an [error code] or an [extended error code] is returned.)^
-**
** This routine only works on a [BLOB handle] which has been created
** by a prior successful call to [sqlite3_blob_open()] and which has not
** been closed by [sqlite3_blob_close()]. Passing any other pointer in
@@ -5778,7 +5982,7 @@ SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
**
** See also: [sqlite3_blob_read()].
*/
-SQLITE_API int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset);
+SQLITE_API int SQLITE_STDCALL sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset);
/*
** CAPI3REF: Virtual File System Objects
@@ -5809,9 +6013,9 @@ SQLITE_API int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOff
** ^(If the default VFS is unregistered, another VFS is chosen as
** the default. The choice for the new VFS is arbitrary.)^
*/
-SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName);
-SQLITE_API int sqlite3_vfs_register(sqlite3_vfs*, int makeDflt);
-SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
+SQLITE_API sqlite3_vfs *SQLITE_STDCALL sqlite3_vfs_find(const char *zVfsName);
+SQLITE_API int SQLITE_STDCALL sqlite3_vfs_register(sqlite3_vfs*, int makeDflt);
+SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs*);
/*
** CAPI3REF: Mutexes
@@ -5823,34 +6027,34 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
**
** The SQLite source code contains multiple implementations
** of these mutex routines. An appropriate implementation
-** is selected automatically at compile-time. ^(The following
+** is selected automatically at compile-time. The following
** implementations are available in the SQLite core:
**
** <ul>
** <li> SQLITE_MUTEX_PTHREADS
** <li> SQLITE_MUTEX_W32
** <li> SQLITE_MUTEX_NOOP
-** </ul>)^
+** </ul>
**
-** ^The SQLITE_MUTEX_NOOP implementation is a set of routines
+** The SQLITE_MUTEX_NOOP implementation is a set of routines
** that does no real locking and is appropriate for use in
-** a single-threaded application. ^The SQLITE_MUTEX_PTHREADS and
+** a single-threaded application. The SQLITE_MUTEX_PTHREADS and
** SQLITE_MUTEX_W32 implementations are appropriate for use on Unix
** and Windows.
**
-** ^(If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor
+** If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor
** macro defined (with "-DSQLITE_MUTEX_APPDEF=1"), then no mutex
** implementation is included with the library. In this case the
** application must supply a custom mutex implementation using the
** [SQLITE_CONFIG_MUTEX] option of the sqlite3_config() function
** before calling sqlite3_initialize() or any other public sqlite3_
-** function that calls sqlite3_initialize().)^
+** function that calls sqlite3_initialize().
**
** ^The sqlite3_mutex_alloc() routine allocates a new
-** mutex and returns a pointer to it. ^If it returns NULL
-** that means that a mutex could not be allocated. ^SQLite
-** will unwind its stack and return an error. ^(The argument
-** to sqlite3_mutex_alloc() is one of these integer constants:
+** mutex and returns a pointer to it. ^The sqlite3_mutex_alloc()
+** routine returns NULL if it is unable to allocate the requested
+** mutex. The argument to sqlite3_mutex_alloc() must one of these
+** integer constants:
**
** <ul>
** <li> SQLITE_MUTEX_FAST
@@ -5863,7 +6067,8 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
** <li> SQLITE_MUTEX_STATIC_PMEM
** <li> SQLITE_MUTEX_STATIC_APP1
** <li> SQLITE_MUTEX_STATIC_APP2
-** </ul>)^
+** <li> SQLITE_MUTEX_STATIC_APP3
+** </ul>
**
** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE)
** cause sqlite3_mutex_alloc() to create
@@ -5871,14 +6076,14 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
** is used but not necessarily so when SQLITE_MUTEX_FAST is used.
** The mutex implementation does not need to make a distinction
** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does
-** not want to. ^SQLite will only request a recursive mutex in
-** cases where it really needs one. ^If a faster non-recursive mutex
+** not want to. SQLite will only request a recursive mutex in
+** cases where it really needs one. If a faster non-recursive mutex
** implementation is available on the host platform, the mutex subsystem
** might return such a mutex in response to SQLITE_MUTEX_FAST.
**
** ^The other allowed parameters to sqlite3_mutex_alloc() (anything other
** than SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) each return
-** a pointer to a static preexisting mutex. ^Six static mutexes are
+** a pointer to a static preexisting mutex. ^Nine static mutexes are
** used by the current version of SQLite. Future versions of SQLite
** may add additional static mutexes. Static mutexes are for internal
** use by SQLite only. Applications that use SQLite mutexes should
@@ -5887,16 +6092,13 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
**
** ^Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST
** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc()
-** returns a different mutex on every call. ^But for the static
+** returns a different mutex on every call. ^For the static
** mutex types, the same mutex is returned on every call that has
** the same type number.
**
** ^The sqlite3_mutex_free() routine deallocates a previously
-** allocated dynamic mutex. ^SQLite is careful to deallocate every
-** dynamic mutex that it allocates. The dynamic mutexes must not be in
-** use when they are deallocated. Attempting to deallocate a static
-** mutex results in undefined behavior. ^SQLite never deallocates
-** a static mutex.
+** allocated dynamic mutex. Attempting to deallocate a static
+** mutex results in undefined behavior.
**
** ^The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
** to enter a mutex. ^If another thread is already within the mutex,
@@ -5904,23 +6106,21 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
** SQLITE_BUSY. ^The sqlite3_mutex_try() interface returns [SQLITE_OK]
** upon successful entry. ^(Mutexes created using
** SQLITE_MUTEX_RECURSIVE can be entered multiple times by the same thread.
-** In such cases the,
+** In such cases, the
** mutex must be exited an equal number of times before another thread
-** can enter.)^ ^(If the same thread tries to enter any other
-** kind of mutex more than once, the behavior is undefined.
-** SQLite will never exhibit
-** such behavior in its own use of mutexes.)^
+** can enter.)^ If the same thread tries to enter any mutex other
+** than an SQLITE_MUTEX_RECURSIVE more than once, the behavior is undefined.
**
** ^(Some systems (for example, Windows 95) do not support the operation
** implemented by sqlite3_mutex_try(). On those systems, sqlite3_mutex_try()
-** will always return SQLITE_BUSY. The SQLite core only ever uses
-** sqlite3_mutex_try() as an optimization so this is acceptable behavior.)^
+** will always return SQLITE_BUSY. The SQLite core only ever uses
+** sqlite3_mutex_try() as an optimization so this is acceptable
+** behavior.)^
**
** ^The sqlite3_mutex_leave() routine exits a mutex that was
-** previously entered by the same thread. ^(The behavior
+** previously entered by the same thread. The behavior
** is undefined if the mutex is not currently entered by the
-** calling thread or is not currently allocated. SQLite will
-** never do either.)^
+** calling thread or is not currently allocated.
**
** ^If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(), or
** sqlite3_mutex_leave() is a NULL pointer, then all three routines
@@ -5928,11 +6128,11 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
**
** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()].
*/
-SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int);
-SQLITE_API void sqlite3_mutex_free(sqlite3_mutex*);
-SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex*);
-SQLITE_API int sqlite3_mutex_try(sqlite3_mutex*);
-SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*);
+SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_mutex_alloc(int);
+SQLITE_API void SQLITE_STDCALL sqlite3_mutex_free(sqlite3_mutex*);
+SQLITE_API void SQLITE_STDCALL sqlite3_mutex_enter(sqlite3_mutex*);
+SQLITE_API int SQLITE_STDCALL sqlite3_mutex_try(sqlite3_mutex*);
+SQLITE_API void SQLITE_STDCALL sqlite3_mutex_leave(sqlite3_mutex*);
/*
** CAPI3REF: Mutex Methods Object
@@ -5941,9 +6141,9 @@ SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*);
** used to allocate and use mutexes.
**
** Usually, the default mutex implementations provided by SQLite are
-** sufficient, however the user has the option of substituting a custom
+** sufficient, however the application has the option of substituting a custom
** implementation for specialized deployments or systems for which SQLite
-** does not provide a suitable implementation. In this case, the user
+** does not provide a suitable implementation. In this case, the application
** creates and populates an instance of this structure to pass
** to sqlite3_config() along with the [SQLITE_CONFIG_MUTEX] option.
** Additionally, an instance of this structure can be used as an
@@ -5984,13 +6184,13 @@ SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*);
** (i.e. it is acceptable to provide an implementation that segfaults if
** it is passed a NULL pointer).
**
-** The xMutexInit() method must be threadsafe. ^It must be harmless to
+** The xMutexInit() method must be threadsafe. It must be harmless to
** invoke xMutexInit() multiple times within the same process and without
** intervening calls to xMutexEnd(). Second and subsequent calls to
** xMutexInit() must be no-ops.
**
-** ^xMutexInit() must not use SQLite memory allocation ([sqlite3_malloc()]
-** and its associates). ^Similarly, xMutexAlloc() must not use SQLite memory
+** xMutexInit() must not use SQLite memory allocation ([sqlite3_malloc()]
+** and its associates). Similarly, xMutexAlloc() must not use SQLite memory
** allocation for a static mutex. ^However xMutexAlloc() may use SQLite
** memory allocation for a fast or recursive mutex.
**
@@ -6016,34 +6216,34 @@ struct sqlite3_mutex_methods {
** CAPI3REF: Mutex Verification Routines
**
** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routines
-** are intended for use inside assert() statements. ^The SQLite core
+** are intended for use inside assert() statements. The SQLite core
** never uses these routines except inside an assert() and applications
-** are advised to follow the lead of the core. ^The SQLite core only
+** are advised to follow the lead of the core. The SQLite core only
** provides implementations for these routines when it is compiled
-** with the SQLITE_DEBUG flag. ^External mutex implementations
+** with the SQLITE_DEBUG flag. External mutex implementations
** are only required to provide these routines if SQLITE_DEBUG is
** defined and if NDEBUG is not defined.
**
-** ^These routines should return true if the mutex in their argument
+** These routines should return true if the mutex in their argument
** is held or not held, respectively, by the calling thread.
**
-** ^The implementation is not required to provide versions of these
+** The implementation is not required to provide versions of these
** routines that actually work. If the implementation does not provide working
** versions of these routines, it should at least provide stubs that always
** return true so that one does not get spurious assertion failures.
**
-** ^If the argument to sqlite3_mutex_held() is a NULL pointer then
+** If the argument to sqlite3_mutex_held() is a NULL pointer then
** the routine should return 1. This seems counter-intuitive since
** clearly the mutex cannot be held if it does not exist. But
** the reason the mutex does not exist is because the build is not
** using mutexes. And we do not want the assert() containing the
** call to sqlite3_mutex_held() to fail, so a non-zero return is
-** the appropriate thing to do. ^The sqlite3_mutex_notheld()
+** the appropriate thing to do. The sqlite3_mutex_notheld()
** interface should also return 1 when given a NULL pointer.
*/
#ifndef NDEBUG
-SQLITE_API int sqlite3_mutex_held(sqlite3_mutex*);
-SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
+SQLITE_API int SQLITE_STDCALL sqlite3_mutex_held(sqlite3_mutex*);
+SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex*);
#endif
/*
@@ -6072,6 +6272,7 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
/*
** CAPI3REF: Retrieve the mutex for a database connection
+** METHOD: sqlite3
**
** ^This interface returns a pointer the [sqlite3_mutex] object that
** serializes access to the [database connection] given in the argument
@@ -6079,10 +6280,11 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
** ^If the [threading mode] is Single-thread or Multi-thread then this
** routine returns a NULL pointer.
*/
-SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
+SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3*);
/*
** CAPI3REF: Low-Level Control Of Database Files
+** METHOD: sqlite3
**
** ^The [sqlite3_file_control()] interface makes a direct call to the
** xFileControl method for the [sqlite3_io_methods] object associated
@@ -6113,7 +6315,7 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
**
** See also: [SQLITE_FCNTL_LOCKSTATE]
*/
-SQLITE_API int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
+SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
/*
** CAPI3REF: Testing Interface
@@ -6132,7 +6334,7 @@ SQLITE_API int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*
** Unlike most of the SQLite API, this function is not guaranteed to
** operate consistently from one release to the next.
*/
-SQLITE_API int sqlite3_test_control(int op, ...);
+SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...);
/*
** CAPI3REF: Testing Interface Operation Codes
@@ -6160,17 +6362,19 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_ISKEYWORD 16
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
-#define SQLITE_TESTCTRL_EXPLAIN_STMT 19
+#define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */
#define SQLITE_TESTCTRL_NEVER_CORRUPT 20
#define SQLITE_TESTCTRL_VDBE_COVERAGE 21
#define SQLITE_TESTCTRL_BYTEORDER 22
#define SQLITE_TESTCTRL_ISINIT 23
-#define SQLITE_TESTCTRL_LAST 23
+#define SQLITE_TESTCTRL_SORTER_MMAP 24
+#define SQLITE_TESTCTRL_IMPOSTER 25
+#define SQLITE_TESTCTRL_LAST 25
/*
** CAPI3REF: SQLite Runtime Status
**
-** ^This interface is used to retrieve runtime status information
+** ^These interfaces are used to retrieve runtime status information
** about the performance of SQLite, and optionally to reset various
** highwater marks. ^The first argument is an integer code for
** the specific parameter to measure. ^(Recognized integer codes
@@ -6184,19 +6388,22 @@ SQLITE_API int sqlite3_test_control(int op, ...);
** ^(Other parameters record only the highwater mark and not the current
** value. For these latter parameters nothing is written into *pCurrent.)^
**
-** ^The sqlite3_status() routine returns SQLITE_OK on success and a
-** non-zero [error code] on failure.
+** ^The sqlite3_status() and sqlite3_status64() routines return
+** SQLITE_OK on success and a non-zero [error code] on failure.
**
-** This routine is threadsafe but is not atomic. This routine can be
-** called while other threads are running the same or different SQLite
-** interfaces. However the values returned in *pCurrent and
-** *pHighwater reflect the status of SQLite at different points in time
-** and it is possible that another thread might change the parameter
-** in between the times when *pCurrent and *pHighwater are written.
+** If either the current value or the highwater mark is too large to
+** be represented by a 32-bit integer, then the values returned by
+** sqlite3_status() are undefined.
**
** See also: [sqlite3_db_status()]
*/
-SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
+SQLITE_API int SQLITE_STDCALL sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
+SQLITE_API int SQLITE_STDCALL sqlite3_status64(
+ int op,
+ sqlite3_int64 *pCurrent,
+ sqlite3_int64 *pHighwater,
+ int resetFlag
+);
/*
@@ -6294,6 +6501,7 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
/*
** CAPI3REF: Database Connection Status
+** METHOD: sqlite3
**
** ^This interface is used to retrieve runtime status information
** about a single [database connection]. ^The first argument is the
@@ -6314,7 +6522,7 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
**
** See also: [sqlite3_status()] and [sqlite3_stmt_status()].
*/
-SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
+SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
/*
** CAPI3REF: Status Parameters for database connections
@@ -6356,12 +6564,12 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
** the current value is always zero.)^
**
** [[SQLITE_DBSTATUS_CACHE_USED]] ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt>
-** <dd>This parameter returns the approximate number of of bytes of heap
+** <dd>This parameter returns the approximate number of bytes of heap
** memory used by all pager caches associated with the database connection.)^
** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
**
** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt>
-** <dd>This parameter returns the approximate number of of bytes of heap
+** <dd>This parameter returns the approximate number of bytes of heap
** memory used to store the schema for all databases associated
** with the connection - main, temp, and any [ATTACH]-ed databases.)^
** ^The full amount of memory used by the schemas is reported, even if the
@@ -6370,7 +6578,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0.
**
** [[SQLITE_DBSTATUS_STMT_USED]] ^(<dt>SQLITE_DBSTATUS_STMT_USED</dt>
-** <dd>This parameter returns the approximate number of of bytes of heap
+** <dd>This parameter returns the approximate number of bytes of heap
** and lookaside memory used by all prepared statements associated with
** the database connection.)^
** ^The highwater mark associated with SQLITE_DBSTATUS_STMT_USED is always 0.
@@ -6422,6 +6630,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
/*
** CAPI3REF: Prepared Statement Status
+** METHOD: sqlite3_stmt
**
** ^(Each prepared statement maintains various
** [SQLITE_STMTSTATUS counters] that measure the number
@@ -6443,7 +6652,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
**
** See also: [sqlite3_status()] and [sqlite3_db_status()].
*/
-SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
+SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
/*
** CAPI3REF: Status Parameters for prepared statements
@@ -6770,6 +6979,10 @@ typedef struct sqlite3_backup sqlite3_backup;
** must be different or else sqlite3_backup_init(D,N,S,M) will fail with
** an error.
**
+** ^A call to sqlite3_backup_init() will fail, returning SQLITE_ERROR, if
+** there is already a read or read-write transaction open on the
+** destination database.
+**
** ^If an error occurs within sqlite3_backup_init(D,N,S,M), then NULL is
** returned and an error code and error message are stored in the
** destination [database connection] D.
@@ -6862,20 +7075,20 @@ typedef struct sqlite3_backup sqlite3_backup;
** is not a permanent error and does not affect the return value of
** sqlite3_backup_finish().
**
-** [[sqlite3_backup__remaining()]] [[sqlite3_backup_pagecount()]]
+** [[sqlite3_backup_remaining()]] [[sqlite3_backup_pagecount()]]
** <b>sqlite3_backup_remaining() and sqlite3_backup_pagecount()</b>
**
-** ^Each call to sqlite3_backup_step() sets two values inside
-** the [sqlite3_backup] object: the number of pages still to be backed
-** up and the total number of pages in the source database file.
-** The sqlite3_backup_remaining() and sqlite3_backup_pagecount() interfaces
-** retrieve these two values, respectively.
-**
-** ^The values returned by these functions are only updated by
-** sqlite3_backup_step(). ^If the source database is modified during a backup
-** operation, then the values are not updated to account for any extra
-** pages that need to be updated or the size of the source database file
-** changing.
+** ^The sqlite3_backup_remaining() routine returns the number of pages still
+** to be backed up at the conclusion of the most recent sqlite3_backup_step().
+** ^The sqlite3_backup_pagecount() routine returns the total number of pages
+** in the source database at the conclusion of the most recent
+** sqlite3_backup_step().
+** ^(The values returned by these functions are only updated by
+** sqlite3_backup_step(). If the source database is modified in a way that
+** changes the size of the source database or the number of pages remaining,
+** those changes are not reflected in the output of sqlite3_backup_pagecount()
+** and sqlite3_backup_remaining() until after the next
+** sqlite3_backup_step().)^
**
** <b>Concurrent Usage of Database Handles</b>
**
@@ -6908,19 +7121,20 @@ typedef struct sqlite3_backup sqlite3_backup;
** same time as another thread is invoking sqlite3_backup_step() it is
** possible that they return invalid values.
*/
-SQLITE_API sqlite3_backup *sqlite3_backup_init(
+SQLITE_API sqlite3_backup *SQLITE_STDCALL sqlite3_backup_init(
sqlite3 *pDest, /* Destination database handle */
const char *zDestName, /* Destination database name */
sqlite3 *pSource, /* Source database handle */
const char *zSourceName /* Source database name */
);
-SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage);
-SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p);
-SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p);
-SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
+SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage);
+SQLITE_API int SQLITE_STDCALL sqlite3_backup_finish(sqlite3_backup *p);
+SQLITE_API int SQLITE_STDCALL sqlite3_backup_remaining(sqlite3_backup *p);
+SQLITE_API int SQLITE_STDCALL sqlite3_backup_pagecount(sqlite3_backup *p);
/*
** CAPI3REF: Unlock Notification
+** METHOD: sqlite3
**
** ^When running in shared-cache mode, a database operation may fail with
** an [SQLITE_LOCKED] error if the required locks on the shared-cache or
@@ -7033,7 +7247,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
** the special "DROP TABLE/INDEX" case, the extended error code is just
** SQLITE_LOCKED.)^
*/
-SQLITE_API int sqlite3_unlock_notify(
+SQLITE_API int SQLITE_STDCALL sqlite3_unlock_notify(
sqlite3 *pBlocked, /* Waiting connection */
void (*xNotify)(void **apArg, int nArg), /* Callback function to invoke */
void *pNotifyArg /* Argument to pass to xNotify */
@@ -7048,8 +7262,8 @@ SQLITE_API int sqlite3_unlock_notify(
** strings in a case-independent fashion, using the same definition of "case
** independence" that SQLite uses internally when comparing identifiers.
*/
-SQLITE_API int sqlite3_stricmp(const char *, const char *);
-SQLITE_API int sqlite3_strnicmp(const char *, const char *, int);
+SQLITE_API int SQLITE_STDCALL sqlite3_stricmp(const char *, const char *);
+SQLITE_API int SQLITE_STDCALL sqlite3_strnicmp(const char *, const char *, int);
/*
** CAPI3REF: String Globbing
@@ -7064,7 +7278,7 @@ SQLITE_API int sqlite3_strnicmp(const char *, const char *, int);
** Note that this routine returns zero on a match and non-zero if the strings
** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()].
*/
-SQLITE_API int sqlite3_strglob(const char *zGlob, const char *zStr);
+SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlob, const char *zStr);
/*
** CAPI3REF: Error Logging Interface
@@ -7087,18 +7301,17 @@ SQLITE_API int sqlite3_strglob(const char *zGlob, const char *zStr);
** a few hundred characters, it will be truncated to the length of the
** buffer.
*/
-SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
+SQLITE_API void SQLITE_CDECL sqlite3_log(int iErrCode, const char *zFormat, ...);
/*
** CAPI3REF: Write-Ahead Log Commit Hook
+** METHOD: sqlite3
**
** ^The [sqlite3_wal_hook()] function is used to register a callback that
-** will be invoked each time a database connection commits data to a
-** [write-ahead log] (i.e. whenever a transaction is committed in
-** [journal_mode | journal_mode=WAL mode]).
+** is invoked each time data is committed to a database in wal mode.
**
-** ^The callback is invoked by SQLite after the commit has taken place and
-** the associated write-lock on the database released, so the implementation
+** ^(The callback is invoked by SQLite after the commit has taken place and
+** the associated write-lock on the database released)^, so the implementation
** may read, write or [checkpoint] the database as required.
**
** ^The first parameter passed to the callback function when it is invoked
@@ -7124,7 +7337,7 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will
** those overwrite any prior [sqlite3_wal_hook()] settings.
*/
-SQLITE_API void *sqlite3_wal_hook(
+SQLITE_API void *SQLITE_STDCALL sqlite3_wal_hook(
sqlite3*,
int(*)(void *,sqlite3*,const char*,int),
void*
@@ -7132,6 +7345,7 @@ SQLITE_API void *sqlite3_wal_hook(
/*
** CAPI3REF: Configure an auto-checkpoint
+** METHOD: sqlite3
**
** ^The [sqlite3_wal_autocheckpoint(D,N)] is a wrapper around
** [sqlite3_wal_hook()] that causes any database on [database connection] D
@@ -7158,104 +7372,123 @@ SQLITE_API void *sqlite3_wal_hook(
** is only necessary if the default setting is found to be suboptimal
** for a particular application.
*/
-SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
+SQLITE_API int SQLITE_STDCALL sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
/*
** CAPI3REF: Checkpoint a database
+** METHOD: sqlite3
**
-** ^The [sqlite3_wal_checkpoint(D,X)] interface causes database named X
-** on [database connection] D to be [checkpointed]. ^If X is NULL or an
-** empty string, then a checkpoint is run on all databases of
-** connection D. ^If the database connection D is not in
-** [WAL | write-ahead log mode] then this interface is a harmless no-op.
-** ^The [sqlite3_wal_checkpoint(D,X)] interface initiates a
-** [sqlite3_wal_checkpoint_v2|PASSIVE] checkpoint.
-** Use the [sqlite3_wal_checkpoint_v2()] interface to get a FULL
-** or RESET checkpoint.
+** ^(The sqlite3_wal_checkpoint(D,X) is equivalent to
+** [sqlite3_wal_checkpoint_v2](D,X,[SQLITE_CHECKPOINT_PASSIVE],0,0).)^
**
-** ^The [wal_checkpoint pragma] can be used to invoke this interface
-** from SQL. ^The [sqlite3_wal_autocheckpoint()] interface and the
-** [wal_autocheckpoint pragma] can be used to cause this interface to be
-** run whenever the WAL reaches a certain size threshold.
+** In brief, sqlite3_wal_checkpoint(D,X) causes the content in the
+** [write-ahead log] for database X on [database connection] D to be
+** transferred into the database file and for the write-ahead log to
+** be reset. See the [checkpointing] documentation for addition
+** information.
**
-** See also: [sqlite3_wal_checkpoint_v2()]
+** This interface used to be the only way to cause a checkpoint to
+** occur. But then the newer and more powerful [sqlite3_wal_checkpoint_v2()]
+** interface was added. This interface is retained for backwards
+** compatibility and as a convenience for applications that need to manually
+** start a callback but which do not need the full power (and corresponding
+** complication) of [sqlite3_wal_checkpoint_v2()].
*/
-SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
+SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
/*
** CAPI3REF: Checkpoint a database
+** METHOD: sqlite3
**
-** Run a checkpoint operation on WAL database zDb attached to database
-** handle db. The specific operation is determined by the value of the
-** eMode parameter:
+** ^(The sqlite3_wal_checkpoint_v2(D,X,M,L,C) interface runs a checkpoint
+** operation on database X of [database connection] D in mode M. Status
+** information is written back into integers pointed to by L and C.)^
+** ^(The M parameter must be a valid [checkpoint mode]:)^
**
** <dl>
** <dt>SQLITE_CHECKPOINT_PASSIVE<dd>
-** Checkpoint as many frames as possible without waiting for any database
-** readers or writers to finish. Sync the db file if all frames in the log
-** are checkpointed. This mode is the same as calling
-** sqlite3_wal_checkpoint(). The [sqlite3_busy_handler|busy-handler callback]
-** is never invoked.
+** ^Checkpoint as many frames as possible without waiting for any database
+** readers or writers to finish, then sync the database file if all frames
+** in the log were checkpointed. ^The [busy-handler callback]
+** is never invoked in the SQLITE_CHECKPOINT_PASSIVE mode.
+** ^On the other hand, passive mode might leave the checkpoint unfinished
+** if there are concurrent readers or writers.
**
** <dt>SQLITE_CHECKPOINT_FULL<dd>
-** This mode blocks (it invokes the
+** ^This mode blocks (it invokes the
** [sqlite3_busy_handler|busy-handler callback]) until there is no
** database writer and all readers are reading from the most recent database
-** snapshot. It then checkpoints all frames in the log file and syncs the
-** database file. This call blocks database writers while it is running,
-** but not database readers.
+** snapshot. ^It then checkpoints all frames in the log file and syncs the
+** database file. ^This mode blocks new database writers while it is pending,
+** but new database readers are allowed to continue unimpeded.
**
** <dt>SQLITE_CHECKPOINT_RESTART<dd>
-** This mode works the same way as SQLITE_CHECKPOINT_FULL, except after
-** checkpointing the log file it blocks (calls the
-** [sqlite3_busy_handler|busy-handler callback])
-** until all readers are reading from the database file only. This ensures
-** that the next client to write to the database file restarts the log file
-** from the beginning. This call blocks database writers while it is running,
-** but not database readers.
+** ^This mode works the same way as SQLITE_CHECKPOINT_FULL with the addition
+** that after checkpointing the log file it blocks (calls the
+** [busy-handler callback])
+** until all readers are reading from the database file only. ^This ensures
+** that the next writer will restart the log file from the beginning.
+** ^Like SQLITE_CHECKPOINT_FULL, this mode blocks new
+** database writer attempts while it is pending, but does not impede readers.
+**
+** <dt>SQLITE_CHECKPOINT_TRUNCATE<dd>
+** ^This mode works the same way as SQLITE_CHECKPOINT_RESTART with the
+** addition that it also truncates the log file to zero bytes just prior
+** to a successful return.
** </dl>
**
-** If pnLog is not NULL, then *pnLog is set to the total number of frames in
-** the log file before returning. If pnCkpt is not NULL, then *pnCkpt is set to
-** the total number of checkpointed frames (including any that were already
-** checkpointed when this function is called). *pnLog and *pnCkpt may be
-** populated even if sqlite3_wal_checkpoint_v2() returns other than SQLITE_OK.
-** If no values are available because of an error, they are both set to -1
-** before returning to communicate this to the caller.
-**
-** All calls obtain an exclusive "checkpoint" lock on the database file. If
+** ^If pnLog is not NULL, then *pnLog is set to the total number of frames in
+** the log file or to -1 if the checkpoint could not run because
+** of an error or because the database is not in [WAL mode]. ^If pnCkpt is not
+** NULL,then *pnCkpt is set to the total number of checkpointed frames in the
+** log file (including any that were already checkpointed before the function
+** was called) or to -1 if the checkpoint could not run due to an error or
+** because the database is not in WAL mode. ^Note that upon successful
+** completion of an SQLITE_CHECKPOINT_TRUNCATE, the log file will have been
+** truncated to zero bytes and so both *pnLog and *pnCkpt will be set to zero.
+**
+** ^All calls obtain an exclusive "checkpoint" lock on the database file. ^If
** any other process is running a checkpoint operation at the same time, the
-** lock cannot be obtained and SQLITE_BUSY is returned. Even if there is a
+** lock cannot be obtained and SQLITE_BUSY is returned. ^Even if there is a
** busy-handler configured, it will not be invoked in this case.
**
-** The SQLITE_CHECKPOINT_FULL and RESTART modes also obtain the exclusive
-** "writer" lock on the database file. If the writer lock cannot be obtained
-** immediately, and a busy-handler is configured, it is invoked and the writer
-** lock retried until either the busy-handler returns 0 or the lock is
-** successfully obtained. The busy-handler is also invoked while waiting for
-** database readers as described above. If the busy-handler returns 0 before
+** ^The SQLITE_CHECKPOINT_FULL, RESTART and TRUNCATE modes also obtain the
+** exclusive "writer" lock on the database file. ^If the writer lock cannot be
+** obtained immediately, and a busy-handler is configured, it is invoked and
+** the writer lock retried until either the busy-handler returns 0 or the lock
+** is successfully obtained. ^The busy-handler is also invoked while waiting for
+** database readers as described above. ^If the busy-handler returns 0 before
** the writer lock is obtained or while waiting for database readers, the
** checkpoint operation proceeds from that point in the same way as
** SQLITE_CHECKPOINT_PASSIVE - checkpointing as many frames as possible
-** without blocking any further. SQLITE_BUSY is returned in this case.
+** without blocking any further. ^SQLITE_BUSY is returned in this case.
**
-** If parameter zDb is NULL or points to a zero length string, then the
-** specified operation is attempted on all WAL databases. In this case the
-** values written to output parameters *pnLog and *pnCkpt are undefined. If
+** ^If parameter zDb is NULL or points to a zero length string, then the
+** specified operation is attempted on all WAL databases [attached] to
+** [database connection] db. In this case the
+** values written to output parameters *pnLog and *pnCkpt are undefined. ^If
** an SQLITE_BUSY error is encountered when processing one or more of the
** attached WAL databases, the operation is still attempted on any remaining
-** attached databases and SQLITE_BUSY is returned to the caller. If any other
+** attached databases and SQLITE_BUSY is returned at the end. ^If any other
** error occurs while processing an attached database, processing is abandoned
-** and the error code returned to the caller immediately. If no error
+** and the error code is returned to the caller immediately. ^If no error
** (SQLITE_BUSY or otherwise) is encountered while processing the attached
** databases, SQLITE_OK is returned.
**
-** If database zDb is the name of an attached database that is not in WAL
-** mode, SQLITE_OK is returned and both *pnLog and *pnCkpt set to -1. If
+** ^If database zDb is the name of an attached database that is not in WAL
+** mode, SQLITE_OK is returned and both *pnLog and *pnCkpt set to -1. ^If
** zDb is not NULL (or a zero length string) and is not the name of any
** attached database, SQLITE_ERROR is returned to the caller.
+**
+** ^Unless it returns SQLITE_MISUSE,
+** the sqlite3_wal_checkpoint_v2() interface
+** sets the error information that is queried by
+** [sqlite3_errcode()] and [sqlite3_errmsg()].
+**
+** ^The [PRAGMA wal_checkpoint] command can be used to invoke this interface
+** from SQL.
*/
-SQLITE_API int sqlite3_wal_checkpoint_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2(
sqlite3 *db, /* Database handle */
const char *zDb, /* Name of attached database (or NULL) */
int eMode, /* SQLITE_CHECKPOINT_* value */
@@ -7264,16 +7497,18 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
);
/*
-** CAPI3REF: Checkpoint operation parameters
+** CAPI3REF: Checkpoint Mode Values
+** KEYWORDS: {checkpoint mode}
**
-** These constants can be used as the 3rd parameter to
-** [sqlite3_wal_checkpoint_v2()]. See the [sqlite3_wal_checkpoint_v2()]
-** documentation for additional information about the meaning and use of
-** each of these values.
+** These constants define all valid values for the "checkpoint mode" passed
+** as the third parameter to the [sqlite3_wal_checkpoint_v2()] interface.
+** See the [sqlite3_wal_checkpoint_v2()] documentation for details on the
+** meaning of each of these checkpoint modes.
*/
-#define SQLITE_CHECKPOINT_PASSIVE 0
-#define SQLITE_CHECKPOINT_FULL 1
-#define SQLITE_CHECKPOINT_RESTART 2
+#define SQLITE_CHECKPOINT_PASSIVE 0 /* Do as much as possible w/o blocking */
+#define SQLITE_CHECKPOINT_FULL 1 /* Wait for writers, then checkpoint */
+#define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for for readers */
+#define SQLITE_CHECKPOINT_TRUNCATE 3 /* Like RESTART but also truncate WAL */
/*
** CAPI3REF: Virtual Table Interface Configuration
@@ -7289,7 +7524,7 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
** this function. (See [SQLITE_VTAB_CONSTRAINT_SUPPORT].) Further options
** may be added in the future.
*/
-SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
+SQLITE_API int SQLITE_CDECL sqlite3_vtab_config(sqlite3*, int op, ...);
/*
** CAPI3REF: Virtual Table Configuration Options
@@ -7342,7 +7577,7 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
** of the SQL statement that triggered the call to the [xUpdate] method of the
** [virtual table].
*/
-SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
+SQLITE_API int SQLITE_STDCALL sqlite3_vtab_on_conflict(sqlite3 *);
/*
** CAPI3REF: Conflict resolution modes
@@ -7362,6 +7597,108 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
/* #define SQLITE_ABORT 4 // Also an error code */
#define SQLITE_REPLACE 5
+/*
+** CAPI3REF: Prepared Statement Scan Status Opcodes
+** KEYWORDS: {scanstatus options}
+**
+** The following constants can be used for the T parameter to the
+** [sqlite3_stmt_scanstatus(S,X,T,V)] interface. Each constant designates a
+** different metric for sqlite3_stmt_scanstatus() to return.
+**
+** When the value returned to V is a string, space to hold that string is
+** managed by the prepared statement S and will be automatically freed when
+** S is finalized.
+**
+** <dl>
+** [[SQLITE_SCANSTAT_NLOOP]] <dt>SQLITE_SCANSTAT_NLOOP</dt>
+** <dd>^The [sqlite3_int64] variable pointed to by the T parameter will be
+** set to the total number of times that the X-th loop has run.</dd>
+**
+** [[SQLITE_SCANSTAT_NVISIT]] <dt>SQLITE_SCANSTAT_NVISIT</dt>
+** <dd>^The [sqlite3_int64] variable pointed to by the T parameter will be set
+** to the total number of rows examined by all iterations of the X-th loop.</dd>
+**
+** [[SQLITE_SCANSTAT_EST]] <dt>SQLITE_SCANSTAT_EST</dt>
+** <dd>^The "double" variable pointed to by the T parameter will be set to the
+** query planner's estimate for the average number of rows output from each
+** iteration of the X-th loop. If the query planner's estimates was accurate,
+** then this value will approximate the quotient NVISIT/NLOOP and the
+** product of this value for all prior loops with the same SELECTID will
+** be the NLOOP value for the current loop.
+**
+** [[SQLITE_SCANSTAT_NAME]] <dt>SQLITE_SCANSTAT_NAME</dt>
+** <dd>^The "const char *" variable pointed to by the T parameter will be set
+** to a zero-terminated UTF-8 string containing the name of the index or table
+** used for the X-th loop.
+**
+** [[SQLITE_SCANSTAT_EXPLAIN]] <dt>SQLITE_SCANSTAT_EXPLAIN</dt>
+** <dd>^The "const char *" variable pointed to by the T parameter will be set
+** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN]
+** description for the X-th loop.
+**
+** [[SQLITE_SCANSTAT_SELECTID]] <dt>SQLITE_SCANSTAT_SELECT</dt>
+** <dd>^The "int" variable pointed to by the T parameter will be set to the
+** "select-id" for the X-th loop. The select-id identifies which query or
+** subquery the loop is part of. The main query has a select-id of zero.
+** The select-id is the same value as is output in the first column
+** of an [EXPLAIN QUERY PLAN] query.
+** </dl>
+*/
+#define SQLITE_SCANSTAT_NLOOP 0
+#define SQLITE_SCANSTAT_NVISIT 1
+#define SQLITE_SCANSTAT_EST 2
+#define SQLITE_SCANSTAT_NAME 3
+#define SQLITE_SCANSTAT_EXPLAIN 4
+#define SQLITE_SCANSTAT_SELECTID 5
+
+/*
+** CAPI3REF: Prepared Statement Scan Status
+** METHOD: sqlite3_stmt
+**
+** This interface returns information about the predicted and measured
+** performance for pStmt. Advanced applications can use this
+** interface to compare the predicted and the measured performance and
+** issue warnings and/or rerun [ANALYZE] if discrepancies are found.
+**
+** Since this interface is expected to be rarely used, it is only
+** available if SQLite is compiled using the [SQLITE_ENABLE_STMT_SCANSTATUS]
+** compile-time option.
+**
+** The "iScanStatusOp" parameter determines which status information to return.
+** The "iScanStatusOp" must be one of the [scanstatus options] or the behavior
+** of this interface is undefined.
+** ^The requested measurement is written into a variable pointed to by
+** the "pOut" parameter.
+** Parameter "idx" identifies the specific loop to retrieve statistics for.
+** Loops are numbered starting from zero. ^If idx is out of range - less than
+** zero or greater than or equal to the total number of loops used to implement
+** the statement - a non-zero value is returned and the variable that pOut
+** points to is unchanged.
+**
+** ^Statistics might not be available for all loops in all statements. ^In cases
+** where there exist loops with no available statistics, this function behaves
+** as if the loop did not exist - it returns non-zero and leave the variable
+** that pOut points to unchanged.
+**
+** See also: [sqlite3_stmt_scanstatus_reset()]
+*/
+SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_stmt_scanstatus(
+ sqlite3_stmt *pStmt, /* Prepared statement for which info desired */
+ int idx, /* Index of loop to report on */
+ int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */
+ void *pOut /* Result written here */
+);
+
+/*
+** CAPI3REF: Zero Scan-Status Counters
+** METHOD: sqlite3_stmt
+**
+** ^Zero all [sqlite3_stmt_scanstatus()] related event counters.
+**
+** This API is only available if the library is built with pre-processor
+** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined.
+*/
+SQLITE_API SQLITE_EXPERIMENTAL void SQLITE_STDCALL sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
/*
@@ -7416,7 +7753,7 @@ typedef struct sqlite3_rtree_query_info sqlite3_rtree_query_info;
**
** SELECT ... FROM <rtree> WHERE <rtree col> MATCH $zGeom(... params ...)
*/
-SQLITE_API int sqlite3_rtree_geometry_callback(
+SQLITE_API int SQLITE_STDCALL sqlite3_rtree_geometry_callback(
sqlite3 *db,
const char *zGeom,
int (*xGeom)(sqlite3_rtree_geometry*, int, sqlite3_rtree_dbl*,int*),
@@ -7442,7 +7779,7 @@ struct sqlite3_rtree_geometry {
**
** SELECT ... FROM <rtree> WHERE <rtree col> MATCH $zQueryFunc(... params ...)
*/
-SQLITE_API int sqlite3_rtree_query_callback(
+SQLITE_API int SQLITE_STDCALL sqlite3_rtree_query_callback(
sqlite3 *db,
const char *zQueryFunc,
int (*xQueryFunc)(sqlite3_rtree_query_info*),
diff --git a/providers/sqlcipher/sqlcipher.patch b/providers/sqlcipher/sqlcipher.patch
index 5d419a4..d47cdf4 100644
--- a/providers/sqlcipher/sqlcipher.patch
+++ b/providers/sqlcipher/sqlcipher.patch
@@ -1,6 +1,6 @@
---- sqlite3.c.sqlite 2014-11-08 15:18:19.125321039 +0100
-+++ sqlite3.c 2014-11-08 15:17:59.107894171 +0100
-@@ -13182,9 +13182,45 @@
+--- sqlite3.c.sqlite 2016-03-09 15:41:25.053136000 +0100
++++ sqlite3.c 2016-03-09 15:41:16.424942202 +0100
+@@ -13786,9 +13786,45 @@
#endif /* _SQLITEINT_H_ */
/************** End of sqliteInt.h *******************************************/
@@ -48,14 +48,14 @@
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
-@@ -13194,261 +13230,3776 @@
+@@ -13798,2674 +13834,3856 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
-+** This file implements a external (disk-based) database using BTrees.
++** This file implements an external (disk-based) database using BTrees.
+** For a detailed discussion of BTrees, refer to
**
--** This file contains definitions of global variables and contants.
+-** This file contains definitions of global variables and constants.
-*/
-
-/* An array to map all upper-case characters into their corresponding
@@ -93,16 +93,16 @@
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 3x */
- 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, /* 4x */
- 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, /* 5x */
-- 96, 97, 66, 67, 68, 69, 70, 71, 72, 73,106,107,108,109,110,111, /* 6x */
-- 112, 81, 82, 83, 84, 85, 86, 87, 88, 89,122,123,124,125,126,127, /* 7x */
+- 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, /* 6x */
+- 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, /* 7x */
- 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, /* 8x */
-- 144,145,146,147,148,149,150,151,152,153,154,155,156,157,156,159, /* 9x */
+- 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, /* 9x */
- 160,161,162,163,164,165,166,167,168,169,170,171,140,141,142,175, /* Ax */
- 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, /* Bx */
- 192,129,130,131,132,133,134,135,136,137,202,203,204,205,206,207, /* Cx */
- 208,145,146,147,148,149,150,151,152,153,218,219,220,221,222,223, /* Dx */
-- 224,225,162,163,164,165,166,167,168,169,232,203,204,205,206,207, /* Ex */
-- 239,240,241,242,243,244,245,246,247,248,249,219,220,221,222,255, /* Fx */
+- 224,225,162,163,164,165,166,167,168,169,234,235,236,237,238,239, /* Ex */
+- 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, /* Fx */
-#endif
-};
-
@@ -157,16 +157,65 @@
**
-** SQLite's versions are identical to the standard versions assuming a
-** locale of "C". They are implemented as macros in sqliteInt.h.
+-*/
+-#ifdef SQLITE_ASCII
+-SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
+- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00..07 ........ */
+- 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, /* 08..0f ........ */
+- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10..17 ........ */
+- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 18..1f ........ */
+- 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, /* 20..27 !"#$%&' */
+- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 28..2f ()*+,-./ */
+- 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, /* 30..37 01234567 */
+- 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 38..3f 89:;<=>? */
+-
+- 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x02, /* 40..47 @ABCDEFG */
+- 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 48..4f HIJKLMNO */
+- 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 50..57 PQRSTUVW */
+- 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x40, /* 58..5f XYZ[\]^_ */
+- 0x00, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x22, /* 60..67 `abcdefg */
+- 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* 68..6f hijklmno */
+- 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* 70..77 pqrstuvw */
+- 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, /* 78..7f xyz{|}~. */
+-
+- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 80..87 ........ */
+- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 88..8f ........ */
+- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 90..97 ........ */
+- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 98..9f ........ */
+- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* a0..a7 ........ */
+- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* a8..af ........ */
+- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* b0..b7 ........ */
+- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* b8..bf ........ */
+-
+- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* c0..c7 ........ */
+- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* c8..cf ........ */
+- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* d0..d7 ........ */
+- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* d8..df ........ */
+- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* e0..e7 ........ */
+- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* e8..ef ........ */
+- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* f0..f7 ........ */
+- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 /* f8..ff ........ */
+-};
+-#endif
+-
+-/* EVIDENCE-OF: R-02982-34736 In order to maintain full backwards
+-** compatibility for legacy applications, the URI filename capability is
+-** disabled by default.
+** The file is divided into pages. The first page is called page 1,
+** the second is page 2, and so forth. A page number of zero indicates
+** "no such page". The page size can be any power of 2 between 512 and 65536.
+** Each page can be either a btree page, a freelist page, an overflow
+** page, or a pointer-map page.
-+**
+ **
+-** EVIDENCE-OF: R-38799-08373 URI filenames can be enabled or disabled
+-** using the SQLITE_USE_URI=1 or SQLITE_USE_URI=0 compile-time options.
+** The first page is always a btree page. The first 100 bytes of the first
+** page contain a special header (the "file header") that describes the file.
+** The format of the file header is as follows:
-+**
+ **
+-** EVIDENCE-OF: R-43642-56306 By default, URI handling is globally
+-** disabled. The default value may be changed by compiling with the
+-** SQLITE_USE_URI symbol defined.
+** OFFSET SIZE DESCRIPTION
+** 0 16 Header string: "SQLite format 3\000"
+** 16 2 Page size in bytes. (1 means 65536)
@@ -248,7 +297,7 @@
+**
+** The flags define the format of this btree page. The leaf flag means that
+** this page has no children. The zerodata flag means that this page carries
-+** only keys and no data. The intkey flag means that the key is a integer
++** only keys and no data. The intkey flag means that the key is an integer
+** which is stored in the key size entry of the cell header rather than in
+** the payload area.
+**
@@ -326,63 +375,34 @@
+** 4 Number of leaf pointers on this page
+** * zero or more pages numbers of leaves
*/
--#ifdef SQLITE_ASCII
--SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00..07 ........ */
-- 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, /* 08..0f ........ */
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10..17 ........ */
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 18..1f ........ */
-- 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, /* 20..27 !"#$%&' */
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 28..2f ()*+,-./ */
-- 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, /* 30..37 01234567 */
-- 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 38..3f 89:;<=>? */
--
-- 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x02, /* 40..47 @ABCDEFG */
-- 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 48..4f HIJKLMNO */
-- 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 50..57 PQRSTUVW */
-- 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x40, /* 58..5f XYZ[\]^_ */
-- 0x00, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x22, /* 60..67 `abcdefg */
-- 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* 68..6f hijklmno */
-- 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* 70..77 pqrstuvw */
-- 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, /* 78..7f xyz{|}~. */
-
-- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 80..87 ........ */
-- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 88..8f ........ */
-- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 90..97 ........ */
-- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 98..9f ........ */
-- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* a0..a7 ........ */
-- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* a8..af ........ */
-- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* b0..b7 ........ */
-- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* b8..bf ........ */
-
-- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* c0..c7 ........ */
-- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* c8..cf ........ */
-- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* d0..d7 ........ */
-- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* d8..df ........ */
-- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* e0..e7 ........ */
-- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* e8..ef ........ */
-- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* f0..f7 ........ */
-- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 /* f8..ff ........ */
--};
+-#ifndef SQLITE_USE_URI
+-# define SQLITE_USE_URI 0
-#endif
+
+-/* EVIDENCE-OF: R-38720-18127 The default setting is determined by the
+-** SQLITE_ALLOW_COVERING_INDEX_SCAN compile-time option, or is "on" if
+-** that compile-time option is omitted.
++
+/* The following value is the maximum cell size assuming a maximum page
+** size give above.
-+*/
+ */
+-#ifndef SQLITE_ALLOW_COVERING_INDEX_SCAN
+-# define SQLITE_ALLOW_COVERING_INDEX_SCAN 1
+-#endif
+#define MX_CELL_SIZE(pBt) ((int)(pBt->pageSize-8))
--#ifndef SQLITE_USE_URI
--# define SQLITE_USE_URI 0
--#endif
+-/* The minimum PMA size is set to this value multiplied by the database
+-** page size in bytes.
+/* The maximum number of cells on a single page of the database. This
+** assumes a minimum cell size of 6 bytes (4 bytes for the cell itself
+** plus 2 bytes for the index to the cell in the page header). Such
+** small cells will be rare, but they are possible.
-+*/
-+#define MX_CELL(pBt) ((pBt->pageSize-8)/6)
-
--#ifndef SQLITE_ALLOW_COVERING_INDEX_SCAN
--# define SQLITE_ALLOW_COVERING_INDEX_SCAN 1
+ */
+-#ifndef SQLITE_SORTER_PMASZ
+-# define SQLITE_SORTER_PMASZ 250
-#endif
++#define MX_CELL(pBt) ((pBt->pageSize-8)/6)
++
+/* Forward declarations */
+typedef struct MemPage MemPage;
+typedef struct BtLock BtLock;
@@ -427,6 +447,7 @@
- 0, /* nPage */
- 0, /* mxParserStack */
- 0, /* sharedCacheEnabled */
+- SQLITE_SORTER_PMASZ, /* szPma */
- /* All the rest should always be initialized to zero */
- 0, /* isInit */
- 0, /* inProgress */
@@ -452,68 +473,48 @@
#endif
- 0 /* bLocaltimeFault */
-};
--
--/*
+
+ /*
-** Hash table for global functions - functions common to all
-** database connections. After initialization, this table is
-** read-only.
--*/
--SQLITE_PRIVATE SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;
-
- /*
--** Constant tokens for values 0 and 1.
+** Page type flags. An ORed combination of these flags appear as the
+** first byte of on-disk image of every BTree page.
*/
--SQLITE_PRIVATE const Token sqlite3IntTokens[] = {
-- { "0", 1 },
-- { "1", 1 }
--};
--
+-SQLITE_PRIVATE SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;
+#define PTF_INTKEY 0x01
+#define PTF_ZERODATA 0x02
+#define PTF_LEAFDATA 0x04
+#define PTF_LEAF 0x08
/*
--** The value of the "pending" byte must be 0x40000000 (1 byte past the
--** 1-gibabyte boundary) in a compatible database. SQLite never uses
--** the database page that contains the pending byte. It never attempts
--** to read or write that page. The pending byte page is set assign
--** for use by the VFS layers as space for managing file locks.
+-** Constant tokens for values 0 and 1.
+** As each page of the file is loaded into memory, an instance of the following
+** structure is appended and initialized to zero. This structure stores
+** information about the page that is decoded from the raw file page.
- **
--** During testing, it is often desirable to move the pending byte to
--** a different position in the file. This allows code that has to
--** deal with the pending byte to run on files that are much smaller
--** than 1 GiB. The sqlite3_test_control() interface can be used to
--** move the pending byte.
++**
+** The pParent field points back to the parent page. This allows us to
+** walk up the BTree from any leaf to the root. Care must be taken to
+** unref() the parent page pointer when this page is no longer referenced.
+** The pageDestructor() routine handles that chore.
- **
--** IMPORTANT: Changing the pending byte to any value other than
--** 0x40000000 results in an incompatible database file format!
--** Changing the pending byte during operating results in undefined
--** and dileterious behavior.
++**
+** Access to all fields of this structure is controlled by the mutex
+** stored in MemPage.pBt->mutex.
*/
--#ifndef SQLITE_OMIT_WSD
--SQLITE_PRIVATE int sqlite3PendingByte = 0x40000000;
--#endif
+-SQLITE_PRIVATE const Token sqlite3IntTokens[] = {
+- { "0", 1 },
+- { "1", 1 }
+struct MemPage {
+ u8 isInit; /* True if previously initialized. MUST BE FIRST! */
+ u8 nOverflow; /* Number of overflow cell bodies in aCell[] */
-+ u8 intKey; /* True if intkey flag is set */
-+ u8 leaf; /* True if leaf flag is set */
-+ u8 hasData; /* True if this page stores data */
++ u8 intKey; /* True if table b-trees. False for index b-trees */
++ u8 intKeyLeaf; /* True if the leaf of an intKey table */
++ u8 noPayload; /* True if internal intKey page (thus w/o data) */
++ u8 leaf; /* True if a leaf page */
+ u8 hdrOffset; /* 100 for page 1. 0 otherwise */
+ u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */
+ u8 max1bytePayload; /* min(maxLocal,127) */
++ u8 bBusy; /* Prevent endless loops on corrupt database files */
+ u16 maxLocal; /* Copy of BtShared.maxLocal or BtShared.maxLeaf */
+ u16 minLocal; /* Copy of BtShared.minLocal or BtShared.minLeaf */
+ u16 cellOffset; /* Index in aData of first cell pointer */
@@ -529,42 +530,47 @@
+ u8 *aCellIdx; /* The cell index area */
+ DbPage *pDbPage; /* Pager page handle */
+ Pgno pgno; /* Page number for this page */
-+};
+ };
+-
/*
--** Properties of opcodes. The OPFLG_INITIALIZER macro is
--** created by mkopcodeh.awk during compilation. Data is obtained
--** from the comments following the "case OP_xxxx:" statements in
--** the vdbe.c file.
+-** The value of the "pending" byte must be 0x40000000 (1 byte past the
+-** 1-gibabyte boundary) in a compatible database. SQLite never uses
+-** the database page that contains the pending byte. It never attempts
+-** to read or write that page. The pending byte page is set assign
+-** for use by the VFS layers as space for managing file locks.
+-**
+-** During testing, it is often desirable to move the pending byte to
+-** a different position in the file. This allows code that has to
+-** deal with the pending byte to run on files that are much smaller
+-** than 1 GiB. The sqlite3_test_control() interface can be used to
+-** move the pending byte.
+-**
+-** IMPORTANT: Changing the pending byte to any value other than
+-** 0x40000000 results in an incompatible database file format!
+-** Changing the pending byte during operation will result in undefined
+-** and incorrect behavior.
+** The in-memory image of a disk page has the auxiliary information appended
+** to the end. EXTRA_SIZE is the number of bytes of space needed to hold
+** that extra information.
*/
--SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[] = OPFLG_INITIALIZER;
+-#ifndef SQLITE_OMIT_WSD
+-SQLITE_PRIVATE int sqlite3PendingByte = 0x40000000;
+-#endif
+#define EXTRA_SIZE sizeof(MemPage)
--/************** End of global.c **********************************************/
--/************** Begin file ctime.c *******************************************/
/*
--** 2010 February 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 routines used to report what compile-time options
--** SQLite was built with.
+-** Properties of opcodes. The OPFLG_INITIALIZER macro is
+-** created by mkopcodeh.awk during compilation. Data is obtained
+-** from the comments following the "case OP_xxxx:" statements in
+-** the vdbe.c file.
+** A linked list of the following structures is stored at BtShared.pLock.
+** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor
+** is opened on the table with root page BtShared.iTable. Locks are removed
+** from this list when a transaction is committed or rolled back, or when
+** a btree handle is closed.
*/
+-SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[] = OPFLG_INITIALIZER;
+struct BtLock {
+ Btree *pBtree; /* Btree handle holding this lock */
+ Pgno iTable; /* Root page of table */
@@ -572,39 +578,47 @@
+ BtLock *pNext; /* Next in BtShared.pLock list */
+};
--#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
--
+-/************** End of global.c **********************************************/
+-/************** Begin file ctime.c *******************************************/
+-/*
+-** 2010 February 23
+-**
+-** The author disclaims copyright to this source code. In place of
+-** a legal notice, here is a blessing:
+/* Candidate values for BtLock.eLock */
+#define READ_LOCK 1
+#define WRITE_LOCK 2
-
--/*
--** An array of names of all compile-time options. This array should
--** be sorted A-Z.
++
+/* A Btree handle
**
--** This array looks large, but in a typical installation actually uses
--** only a handful of compile-time options, so most times this array is usually
--** rather short and uses little memory space.
+-** 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.
+** A database connection contains a pointer to an instance of
+** this object for every database file that it has open. This structure
+** is opaque to the database connection. The database connection cannot
+** see the internals of this structure and only deals with pointers to
+** this structure.
-+**
+ **
+-*************************************************************************
+** For some database files, the same underlying database cache might be
+** shared between multiple connections. In that case, each connection
+** has it own instance of this object. But each instance of this object
+** points to the same BtShared object. The database cache and the
+** schema associated with the database file are all contained within
+** the BtShared object.
-+**
+ **
+-** This file implements routines used to report what compile-time options
+-** SQLite was built with.
+** All fields in this structure are accessed under sqlite3.mutex.
+** The pBt pointer itself may not be changed while there exists cursors
+** in the referenced BtShared that point back to this Btree since those
+** cursors have to go through this Btree to find their BtShared and
+** they often do so without holding sqlite3.mutex.
-+*/
+ */
+-
+-#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
+-
+struct Btree {
+ sqlite3 *db; /* The database connection holding this btree */
+ BtShared *pBt; /* Sharable content of this btree */
@@ -613,24 +627,74 @@
+ u8 locked; /* True if db currently has pBt locked */
+ int wantToLock; /* Number of nested calls to sqlite3BtreeEnter() */
+ int nBackup; /* Number of backup operations reading this btree */
++ u32 iDataVersion; /* Combines with pBt->pPager->iDataVersion */
+ Btree *pNext; /* List of other sharable Btrees from the same db */
+ Btree *pPrev; /* Back pointer of the same list */
+#ifndef SQLITE_OMIT_SHARED_CACHE
+ BtLock lock; /* Object used to lock page 1 */
+#endif
+};
-+
-+/*
+
+ /*
+-** An array of names of all compile-time options. This array should
+-** be sorted A-Z.
+** Btree.inTrans may take one of the following values.
-+**
+ **
+-** This array looks large, but in a typical installation actually uses
+-** only a handful of compile-time options, so most times this array is usually
+-** rather short and uses little memory space.
+** If the shared-data extension is enabled, there may be multiple users
+** of the Btree structure. At most one of these may open a write transaction,
+** but any number may have active read transactions.
-+*/
+ */
+-static const char * const azCompileOpt[] = {
+-
+-/* These macros are provided to "stringify" the value of the define
+-** for those options in which the value is meaningful. */
+-#define CTIMEOPT_VAL_(opt) #opt
+-#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
+#define TRANS_NONE 0
+#define TRANS_READ 1
+#define TRANS_WRITE 2
-+
+
+-#if SQLITE_32BIT_ROWID
+- "32BIT_ROWID",
+-#endif
+-#if SQLITE_4_BYTE_ALIGNED_MALLOC
+- "4_BYTE_ALIGNED_MALLOC",
+-#endif
+-#if SQLITE_CASE_SENSITIVE_LIKE
+- "CASE_SENSITIVE_LIKE",
+-#endif
+-#if SQLITE_CHECK_PAGES
+- "CHECK_PAGES",
+-#endif
+-#if SQLITE_COVERAGE_TEST
+- "COVERAGE_TEST",
+-#endif
+-#if SQLITE_DEBUG
+- "DEBUG",
+-#endif
+-#if SQLITE_DEFAULT_LOCKING_MODE
+- "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE),
+-#endif
+-#if defined(SQLITE_DEFAULT_MMAP_SIZE) && !defined(SQLITE_DEFAULT_MMAP_SIZE_xc)
+- "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE),
+-#endif
+-#if SQLITE_DISABLE_DIRSYNC
+- "DISABLE_DIRSYNC",
+-#endif
+-#if SQLITE_DISABLE_LFS
+- "DISABLE_LFS",
+-#endif
+-#if SQLITE_ENABLE_API_ARMOR
+- "ENABLE_API_ARMOR",
+-#endif
+-#if SQLITE_ENABLE_ATOMIC_WRITE
+- "ENABLE_ATOMIC_WRITE",
+-#endif
+-#if SQLITE_ENABLE_CEROD
+- "ENABLE_CEROD",
+/*
+** An instance of this object represents a single database file.
+**
@@ -676,9 +740,16 @@
+ u8 autoVacuum; /* True if auto-vacuum is enabled */
+ u8 incrVacuum; /* True if incr-vacuum is enabled */
+ u8 bDoTruncate; /* True to truncate db on commit */
-+#endif
+ #endif
+-#if SQLITE_ENABLE_COLUMN_METADATA
+- "ENABLE_COLUMN_METADATA",
+ u8 inTransaction; /* Transaction state */
+ u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */
++#ifdef SQLITE_HAS_CODEC
++ u8 optimalReserve; /* Desired amount of reserved space per page */
+ #endif
+-#if SQLITE_ENABLE_DBSTAT_VTAB
+- "ENABLE_DBSTAT_VTAB",
+ 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 */
@@ -697,8 +768,10 @@
+ BtShared *pNext; /* Next on a list of sharable BtShared structs */
+ BtLock *pLock; /* List of locks held on this shared-btree struct */
+ Btree *pWriter; /* Btree with currently open write transaction */
-+#endif
-+ u8 *pTmpSpace; /* BtShared.pageSize bytes of space for tmp use */
+ #endif
+-#if SQLITE_ENABLE_EXPENSIVE_ASSERT
+- "ENABLE_EXPENSIVE_ASSERT",
++ u8 *pTmpSpace; /* Temp space sufficient to hold a single cell */
+};
+
+/*
@@ -719,12 +792,10 @@
+*/
+typedef struct CellInfo CellInfo;
+struct CellInfo {
-+ i64 nKey; /* The key for INTKEY tables, or number of bytes in key */
-+ u8 *pCell; /* Pointer to the start of cell content */
-+ u32 nData; /* Number of bytes of data */
-+ u32 nPayload; /* Total amount of payload */
-+ u16 nHeader; /* Size of the cell content header in bytes */
-+ u16 nLocal; /* Amount of payload held locally */
++ i64 nKey; /* The key for INTKEY tables, or nPayload otherwise */
++ u8 *pPayload; /* Pointer to the start of payload */
++ u32 nPayload; /* Bytes of payload */
++ u16 nLocal; /* Amount of payload held locally, not on overflow */
+ u16 iOverflow; /* Offset to overflow page number. Zero if no overflow */
+ u16 nSize; /* Size of the cell content on the main b-tree page */
+};
@@ -753,6 +824,11 @@
+**
+** Fields in this structure are accessed under the BtShared.mutex
+** found at self->pBt->mutex.
++**
++** skipNext meaning:
++** eState==SKIPNEXT && skipNext>0: Next sqlite3BtreeNext() is no-op.
++** eState==SKIPNEXT && skipNext<0: Next sqlite3BtreePrevious() is no-op.
++** eState==FAULT: Cursor fault with skipNext as error code.
+*/
+struct BtCursor {
+ Btree *pBtree; /* The Btree to which this cursor belongs */
@@ -765,7 +841,8 @@
+ void *pKey; /* Saved key that was cursor last known position */
+ Pgno pgnoRoot; /* The root page of this tree */
+ int nOvflAlloc; /* Allocated size of aOverflow[] array */
-+ int skipNext; /* Prev() is noop if negative. Next() is noop if positive */
++ int skipNext; /* Prev() is noop if negative. Next() is noop if positive.
++ ** Error code if eState==CURSOR_FAULT */
+ u8 curFlags; /* zero or more BTCF_* flags defined below */
+ u8 eState; /* One of the CURSOR_XXX constants (see below) */
+ u8 hints; /* As configured by CursorSetHints() */
@@ -807,11 +884,11 @@
+** seek the cursor to the saved position.
+**
+** CURSOR_FAULT:
-+** A unrecoverable error (an I/O error or a malloc failure) has occurred
++** An unrecoverable error (an I/O error or a malloc failure) has occurred
+** on a different connection that shares the BtShared cache with this
+** cursor. The error has left the cache in an inconsistent state.
+** Do nothing else with this cursor. Any attempt to use the cursor
-+** should return the error code stored in BtCursor.skip
++** should return the error code stored in BtCursor.skipNext
+*/
+#define CURSOR_INVALID 0
+#define CURSOR_VALID 1
@@ -899,7 +976,9 @@
+#define ISAUTOVACUUM (pBt->autoVacuum)
+#else
+#define ISAUTOVACUUM 0
-+#endif
+ #endif
+-#if SQLITE_ENABLE_FTS1
+- "ENABLE_FTS1",
+
+
+/*
@@ -921,6 +1000,8 @@
+ int mxErr; /* Stop accumulating errors when this reaches zero */
+ int nErr; /* Number of messages written to zErrMsg so far */
+ int mallocFailed; /* A memory allocation error has occurred */
++ const char *zPfx; /* Error message prefix */
++ int v1, v2; /* Values for up to two %d fields in zPfx */
+ StrAccum errMsg; /* Accumulate the error message text here */
+};
+
@@ -977,17 +1058,29 @@
+ && !defined (SQLCIPHER_CRYPTO_LIBTOMCRYPT) \
+ && !defined (SQLCIPHER_CRYPTO_OPENSSL)
+#define SQLCIPHER_CRYPTO_OPENSSL
-+#endif
+ #endif
+-#if SQLITE_ENABLE_FTS2
+- "ENABLE_FTS2",
+
+#define FILE_HEADER_SZ 16
+
+#ifndef CIPHER_VERSION
-+#define CIPHER_VERSION "3.2.0"
-+#endif
++#ifdef SQLCIPHER_FIPS
++#define CIPHER_VERSION "3.3.1 FIPS"
++#else
++#define CIPHER_VERSION "3.3.1"
+ #endif
+-#if SQLITE_ENABLE_FTS3
+- "ENABLE_FTS3",
+ #endif
+-#if SQLITE_ENABLE_FTS3_PARENTHESIS
+- "ENABLE_FTS3_PARENTHESIS",
+
+#ifndef CIPHER
+#define CIPHER "aes-256-cbc"
-+#endif
+ #endif
+-#if SQLITE_ENABLE_FTS4
+- "ENABLE_FTS4",
+
+#define CIPHER_DECRYPT 0
+#define CIPHER_ENCRYPT 1
@@ -998,7 +1091,9 @@
+
+#ifndef PBKDF2_ITER
+#define PBKDF2_ITER 64000
-+#endif
+ #endif
+-#if SQLITE_ENABLE_ICU
+- "ENABLE_ICU",
+
+/* possible flags for cipher_ctx->flags */
+#define CIPHER_FLAG_HMAC 0x01
@@ -1007,7 +1102,9 @@
+
+#ifndef DEFAULT_CIPHER_FLAGS
+#define DEFAULT_CIPHER_FLAGS CIPHER_FLAG_HMAC | CIPHER_FLAG_LE_PGNO
-+#endif
+ #endif
+-#if SQLITE_ENABLE_IOTRACE
+- "ENABLE_IOTRACE",
+
+
+/* by default, sqlcipher will use a reduced number of iterations to generate
@@ -1015,7 +1112,9 @@
+ */
+#ifndef FAST_PBKDF2_ITER
+#define FAST_PBKDF2_ITER 2
-+#endif
+ #endif
+-#if SQLITE_ENABLE_LOAD_EXTENSION
+- "ENABLE_LOAD_EXTENSION",
+
+/* this if a fixed random array that will be xor'd with the database salt to ensure that the
+ salt passed to the HMAC key derivation function is not the same as that used to derive
@@ -1024,22 +1123,30 @@
+ will likely allow this to be defined at runtime via pragma */
+#ifndef HMAC_SALT_MASK
+#define HMAC_SALT_MASK 0x3a
-+#endif
+ #endif
+-#if SQLITE_ENABLE_LOCKING_STYLE
+- "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE),
+
+#ifndef CIPHER_MAX_IV_SZ
+#define CIPHER_MAX_IV_SZ 16
-+#endif
+ #endif
+-#if SQLITE_ENABLE_MEMORY_MANAGEMENT
+- "ENABLE_MEMORY_MANAGEMENT",
+
+#ifndef CIPHER_MAX_KEY_SZ
+#define CIPHER_MAX_KEY_SZ 64
-+#endif
+ #endif
+-#if SQLITE_ENABLE_MEMSYS3
+- "ENABLE_MEMSYS3",
+
+
+#ifdef CODEC_DEBUG
+#define CODEC_TRACE(X) {printf X;fflush(stdout);}
+#else
+#define CODEC_TRACE(X)
-+#endif
+ #endif
+-#if SQLITE_ENABLE_MEMSYS5
+- "ENABLE_MEMSYS5",
+
+#ifdef CODEC_DEBUG_PAGEDATA
+#define CODEC_HEXDUMP(DESC,BUFFER,LEN) \
@@ -1055,7 +1162,9 @@
+ }
+#else
+#define CODEC_HEXDUMP(DESC,BUFFER,LEN)
-+#endif
+ #endif
+-#if SQLITE_ENABLE_OVERSIZE_CELL_CHECK
+- "ENABLE_OVERSIZE_CELL_CHECK",
+
+/* extensions defined in pager.c */
+SQLITE_PRIVATE void sqlite3pager_get_codec(Pager *pPager, void **ctx);
@@ -1118,6 +1227,9 @@
+int sqlcipher_codec_ctx_get_pagesize(codec_ctx *);
+int sqlcipher_codec_ctx_get_reservesize(codec_ctx *);
+
++void sqlcipher_set_default_pagesize(int page_size);
++int sqlcipher_get_default_pagesize();
++
+void sqlcipher_set_default_kdf_iter(int iter);
+int sqlcipher_get_default_kdf_iter();
+
@@ -1157,14 +1269,291 @@
+static int sqlcipher_codec_get_store_pass(codec_ctx *ctx);
+static void sqlcipher_codec_get_pass(codec_ctx *ctx, void **zKey, int *nKey);
+static void sqlcipher_codec_set_store_pass(codec_ctx *ctx, int value);
++int sqlcipher_codec_fips_status(codec_ctx *ctx);
+
-+#endif
-+#endif
+ #endif
+-#if SQLITE_ENABLE_RTREE
+- "ENABLE_RTREE",
+ #endif
+-#if defined(SQLITE_ENABLE_STAT4)
+- "ENABLE_STAT4",
+-#elif defined(SQLITE_ENABLE_STAT3)
+- "ENABLE_STAT3",
+-#endif
+-#if SQLITE_ENABLE_UNLOCK_NOTIFY
+- "ENABLE_UNLOCK_NOTIFY",
+-#endif
+-#if SQLITE_ENABLE_UPDATE_DELETE_LIMIT
+- "ENABLE_UPDATE_DELETE_LIMIT",
+-#endif
+-#if SQLITE_HAS_CODEC
+- "HAS_CODEC",
+-#endif
+-#if HAVE_ISNAN || SQLITE_HAVE_ISNAN
+- "HAVE_ISNAN",
+-#endif
+-#if SQLITE_HOMEGROWN_RECURSIVE_MUTEX
+- "HOMEGROWN_RECURSIVE_MUTEX",
+-#endif
+-#if SQLITE_IGNORE_AFP_LOCK_ERRORS
+- "IGNORE_AFP_LOCK_ERRORS",
+-#endif
+-#if SQLITE_IGNORE_FLOCK_LOCK_ERRORS
+- "IGNORE_FLOCK_LOCK_ERRORS",
+-#endif
+-#ifdef SQLITE_INT64_TYPE
+- "INT64_TYPE",
+-#endif
+-#if SQLITE_LOCK_TRACE
+- "LOCK_TRACE",
+-#endif
+-#if defined(SQLITE_MAX_MMAP_SIZE) && !defined(SQLITE_MAX_MMAP_SIZE_xc)
+- "MAX_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE),
+-#endif
+-#ifdef SQLITE_MAX_SCHEMA_RETRY
+- "MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY),
+-#endif
+-#if SQLITE_MEMDEBUG
+- "MEMDEBUG",
+-#endif
+-#if SQLITE_MIXED_ENDIAN_64BIT_FLOAT
+- "MIXED_ENDIAN_64BIT_FLOAT",
+-#endif
+-#if SQLITE_NO_SYNC
+- "NO_SYNC",
+-#endif
+-#if SQLITE_OMIT_ALTERTABLE
+- "OMIT_ALTERTABLE",
+-#endif
+-#if SQLITE_OMIT_ANALYZE
+- "OMIT_ANALYZE",
+-#endif
+-#if SQLITE_OMIT_ATTACH
+- "OMIT_ATTACH",
+-#endif
+-#if SQLITE_OMIT_AUTHORIZATION
+- "OMIT_AUTHORIZATION",
+-#endif
+-#if SQLITE_OMIT_AUTOINCREMENT
+- "OMIT_AUTOINCREMENT",
+-#endif
+-#if SQLITE_OMIT_AUTOINIT
+- "OMIT_AUTOINIT",
+-#endif
+-#if SQLITE_OMIT_AUTOMATIC_INDEX
+- "OMIT_AUTOMATIC_INDEX",
+-#endif
+-#if SQLITE_OMIT_AUTORESET
+- "OMIT_AUTORESET",
+-#endif
+-#if SQLITE_OMIT_AUTOVACUUM
+- "OMIT_AUTOVACUUM",
+-#endif
+-#if SQLITE_OMIT_BETWEEN_OPTIMIZATION
+- "OMIT_BETWEEN_OPTIMIZATION",
+-#endif
+-#if SQLITE_OMIT_BLOB_LITERAL
+- "OMIT_BLOB_LITERAL",
+-#endif
+-#if SQLITE_OMIT_BTREECOUNT
+- "OMIT_BTREECOUNT",
+-#endif
+-#if SQLITE_OMIT_BUILTIN_TEST
+- "OMIT_BUILTIN_TEST",
+-#endif
+-#if SQLITE_OMIT_CAST
+- "OMIT_CAST",
+-#endif
+-#if SQLITE_OMIT_CHECK
+- "OMIT_CHECK",
+-#endif
+-#if SQLITE_OMIT_COMPLETE
+- "OMIT_COMPLETE",
+-#endif
+-#if SQLITE_OMIT_COMPOUND_SELECT
+- "OMIT_COMPOUND_SELECT",
+-#endif
+-#if SQLITE_OMIT_CTE
+- "OMIT_CTE",
+-#endif
+-#if SQLITE_OMIT_DATETIME_FUNCS
+- "OMIT_DATETIME_FUNCS",
+-#endif
+-#if SQLITE_OMIT_DECLTYPE
+- "OMIT_DECLTYPE",
+-#endif
+-#if SQLITE_OMIT_DEPRECATED
+- "OMIT_DEPRECATED",
+-#endif
+-#if SQLITE_OMIT_DISKIO
+- "OMIT_DISKIO",
+-#endif
+-#if SQLITE_OMIT_EXPLAIN
+- "OMIT_EXPLAIN",
+-#endif
+-#if SQLITE_OMIT_FLAG_PRAGMAS
+- "OMIT_FLAG_PRAGMAS",
+-#endif
+-#if SQLITE_OMIT_FLOATING_POINT
+- "OMIT_FLOATING_POINT",
+-#endif
+-#if SQLITE_OMIT_FOREIGN_KEY
+- "OMIT_FOREIGN_KEY",
+-#endif
+-#if SQLITE_OMIT_GET_TABLE
+- "OMIT_GET_TABLE",
+-#endif
+-#if SQLITE_OMIT_INCRBLOB
+- "OMIT_INCRBLOB",
+-#endif
+-#if SQLITE_OMIT_INTEGRITY_CHECK
+- "OMIT_INTEGRITY_CHECK",
+-#endif
+-#if SQLITE_OMIT_LIKE_OPTIMIZATION
+- "OMIT_LIKE_OPTIMIZATION",
+-#endif
+-#if SQLITE_OMIT_LOAD_EXTENSION
+- "OMIT_LOAD_EXTENSION",
+-#endif
+-#if SQLITE_OMIT_LOCALTIME
+- "OMIT_LOCALTIME",
+-#endif
+-#if SQLITE_OMIT_LOOKASIDE
+- "OMIT_LOOKASIDE",
+-#endif
+-#if SQLITE_OMIT_MEMORYDB
+- "OMIT_MEMORYDB",
+-#endif
+-#if SQLITE_OMIT_OR_OPTIMIZATION
+- "OMIT_OR_OPTIMIZATION",
+-#endif
+-#if SQLITE_OMIT_PAGER_PRAGMAS
+- "OMIT_PAGER_PRAGMAS",
+-#endif
+-#if SQLITE_OMIT_PRAGMA
+- "OMIT_PRAGMA",
+-#endif
+-#if SQLITE_OMIT_PROGRESS_CALLBACK
+- "OMIT_PROGRESS_CALLBACK",
+-#endif
+-#if SQLITE_OMIT_QUICKBALANCE
+- "OMIT_QUICKBALANCE",
+-#endif
+-#if SQLITE_OMIT_REINDEX
+- "OMIT_REINDEX",
+-#endif
+-#if SQLITE_OMIT_SCHEMA_PRAGMAS
+- "OMIT_SCHEMA_PRAGMAS",
+-#endif
+-#if SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
+- "OMIT_SCHEMA_VERSION_PRAGMAS",
+-#endif
+-#if SQLITE_OMIT_SHARED_CACHE
+- "OMIT_SHARED_CACHE",
+-#endif
+-#if SQLITE_OMIT_SUBQUERY
+- "OMIT_SUBQUERY",
+-#endif
+-#if SQLITE_OMIT_TCL_VARIABLE
+- "OMIT_TCL_VARIABLE",
+-#endif
+-#if SQLITE_OMIT_TEMPDB
+- "OMIT_TEMPDB",
+-#endif
+-#if SQLITE_OMIT_TRACE
+- "OMIT_TRACE",
+-#endif
+-#if SQLITE_OMIT_TRIGGER
+- "OMIT_TRIGGER",
+-#endif
+-#if SQLITE_OMIT_TRUNCATE_OPTIMIZATION
+- "OMIT_TRUNCATE_OPTIMIZATION",
+-#endif
+-#if SQLITE_OMIT_UTF16
+- "OMIT_UTF16",
+-#endif
+-#if SQLITE_OMIT_VACUUM
+- "OMIT_VACUUM",
+-#endif
+-#if SQLITE_OMIT_VIEW
+- "OMIT_VIEW",
+-#endif
+-#if SQLITE_OMIT_VIRTUALTABLE
+- "OMIT_VIRTUALTABLE",
+-#endif
+-#if SQLITE_OMIT_WAL
+- "OMIT_WAL",
+-#endif
+-#if SQLITE_OMIT_WSD
+- "OMIT_WSD",
+-#endif
+-#if SQLITE_OMIT_XFER_OPT
+- "OMIT_XFER_OPT",
+-#endif
+-#if SQLITE_PERFORMANCE_TRACE
+- "PERFORMANCE_TRACE",
+-#endif
+-#if SQLITE_PROXY_DEBUG
+- "PROXY_DEBUG",
+-#endif
+-#if SQLITE_RTREE_INT_ONLY
+- "RTREE_INT_ONLY",
+-#endif
+-#if SQLITE_SECURE_DELETE
+- "SECURE_DELETE",
+-#endif
+-#if SQLITE_SMALL_STACK
+- "SMALL_STACK",
+-#endif
+-#if SQLITE_SOUNDEX
+- "SOUNDEX",
+-#endif
+-#if SQLITE_SYSTEM_MALLOC
+- "SYSTEM_MALLOC",
+-#endif
+-#if SQLITE_TCL
+- "TCL",
+-#endif
+-#if defined(SQLITE_TEMP_STORE) && !defined(SQLITE_TEMP_STORE_xc)
+- "TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE),
+-#endif
+-#if SQLITE_TEST
+- "TEST",
+-#endif
+-#if defined(SQLITE_THREADSAFE)
+- "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE),
+-#endif
+-#if SQLITE_USE_ALLOCA
+- "USE_ALLOCA",
+-#endif
+-#if SQLITE_USER_AUTHENTICATION
+- "USER_AUTHENTICATION",
+-#endif
+-#if SQLITE_WIN32_MALLOC
+- "WIN32_MALLOC",
+-#endif
+-#if SQLITE_ZERO_MALLOC
+- "ZERO_MALLOC"
+-#endif
+-};
+/* END SQLCIPHER */
-+
+
+-/*
+-** Given the name of a compile-time option, return true if that option
+-** was used and false if not.
+-**
+-** The name can optionally begin with "SQLITE_" but the "SQLITE_" prefix
+-** is not required for a match.
+-*/
+-SQLITE_API int SQLITE_STDCALL sqlite3_compileoption_used(const char *zOptName){
+- int i, n;
+/************** End of crypto.h **********************************************/
+/************** Continuing where we left off in crypto.c *********************/
-+
+
+-#if SQLITE_ENABLE_API_ARMOR
+- if( zOptName==0 ){
+- (void)SQLITE_MISUSE_BKPT;
+- return 0;
+static const char* codec_get_cipher_version() {
+ return CIPHER_VERSION;
+}
@@ -1203,10 +1592,20 @@
+ codec_ctx *ctx;
+ sqlite3pager_get_codec(pDb->pBt->pBt->pPager, (void **) &ctx);
+ if(ctx) return sqlcipher_codec_ctx_set_pass(ctx, zKey, nKey, for_ctx);
-+ }
+ }
+-#endif
+- if( sqlite3StrNICmp(zOptName, "SQLITE_", 7)==0 ) zOptName += 7;
+- n = sqlite3Strlen30(zOptName);
+ return SQLITE_ERROR;
+}
-+
+
+- /* Since ArraySize(azCompileOpt) is normally in single digits, a
+- ** linear search is adequate. No need for a binary search. */
+- for(i=0; i<ArraySize(azCompileOpt); i++){
+- if( sqlite3StrNICmp(zOptName, azCompileOpt[i], n)==0
+- && sqlite3IsIdChar((unsigned char)azCompileOpt[i][n])==0
+- ){
+- return 1;
+int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLeft, const char *zRight) {
+ struct Db *pDb = &db->aDb[iDb];
+ codec_ctx *ctx = NULL;
@@ -1218,14 +1617,26 @@
+
+ CODEC_TRACE(("sqlcipher_codec_pragma: entered db=%p iDb=%d pParse=%p zLeft=%s zRight=%s ctx=%p\n", db,
iDb, pParse, zLeft, zRight, ctx));
+
++ if( sqlite3StrICmp(zLeft, "cipher_fips_status")== 0 && !zRight ){
++ if(ctx) {
++ char *fips_mode_status = sqlite3_mprintf("%d", sqlcipher_codec_fips_status(ctx));
++ codec_vdbe_return_static_string(pParse, "cipher_fips_status", fips_mode_status);
++ sqlite3_free(fips_mode_status);
++ }
++ } else
+ if( sqlite3StrICmp(zLeft, "cipher_store_pass")==0 && zRight ) {
-+ sqlcipher_codec_set_store_pass(ctx, sqlite3GetBoolean(zRight, 1));
++ if(ctx) {
++ sqlcipher_codec_set_store_pass(ctx, sqlite3GetBoolean(zRight, 1));
++ }
+ } else
+ if( sqlite3StrICmp(zLeft, "cipher_store_pass")==0 && !zRight ) {
-+ char *store_pass_value = sqlite3_mprintf("%d", sqlcipher_codec_get_store_pass(ctx));
-+ codec_vdbe_return_static_string(pParse, "cipher_store_pass", store_pass_value);
-+ sqlite3_free(store_pass_value);
-+ }
++ if(ctx){
++ char *store_pass_value = sqlite3_mprintf("%d", sqlcipher_codec_get_store_pass(ctx));
++ codec_vdbe_return_static_string(pParse, "cipher_store_pass", store_pass_value);
++ sqlite3_free(store_pass_value);
+ }
+ }
+- return 0;
+ if( sqlite3StrICmp(zLeft, "cipher_profile")== 0 && zRight ){
+ char *profile_status = sqlite3_mprintf("%d", sqlcipher_cipher_profile(db, zRight));
+ codec_vdbe_return_static_string(pParse, "cipher_profile", profile_status);
@@ -1315,6 +1726,15 @@
+ }
+ }
+ }else
++ if( sqlite3StrICmp(zLeft,"cipher_default_page_size")==0 ){
++ if( zRight ) {
++ sqlcipher_set_default_pagesize(atoi(zRight));
++ } else {
++ char *default_page_size = sqlite3_mprintf("%d", sqlcipher_get_default_pagesize());
++ codec_vdbe_return_static_string(pParse, "cipher_default_page_size", default_page_size);
++ sqlite3_free(default_page_size);
++ }
++ }else
+ if( sqlite3StrICmp(zLeft,"cipher_default_use_hmac")==0 ){
+ if( zRight ) {
+ sqlcipher_set_default_use_hmac(sqlite3GetBoolean(zRight,1));
@@ -1383,10 +1803,16 @@
+ return 0;
+ }
+ return 1;
-+}
-+
+ }
+
+
-+/*
+ /*
+-** Return the N-th compile-time option string. If N is out of range,
+-** return a NULL pointer.
+-*/
+-SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N){
+- if( N>=0 && N<ArraySize(azCompileOpt) ){
+- return azCompileOpt[N];
+ * sqlite3Codec can be called in multiple modes.
+ * encrypt mode - expected to return a pointer to the
+ * encrypted data without altering pData.
@@ -1487,7 +1913,7 @@
+ return SQLITE_OK;
+}
+
-+SQLITE_API void sqlite3_activate_see(const char* in) {
++SQLITE_API void SQLITE_STDCALL sqlite3_activate_see(const char* in) {
+ /* do nothing, security enhancements are always active */
+}
+
@@ -1501,16 +1927,17 @@
+ if(strcmp(pDb->zName, zDb) == 0) {
+ return db_index;
+ }
-+ }
-+ return 0;
-+}
-+
-+SQLITE_API int sqlite3_key(sqlite3 *db, const void *pKey, int nKey) {
+ }
+ return 0;
+ }
+
+-#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
++SQLITE_API int SQLITE_STDCALL sqlite3_key(sqlite3 *db, const void *pKey, int nKey) {
+ CODEC_TRACE(("sqlite3_key entered: db=%p pKey=%s nKey=%d\n", db, (char *)pKey, nKey));
+ return sqlite3_key_v2(db, "main", pKey, nKey);
+}
+
-+SQLITE_API int sqlite3_key_v2(sqlite3 *db, const char *zDb, const void *pKey, int nKey) {
++SQLITE_API int SQLITE_STDCALL sqlite3_key_v2(sqlite3 *db, const char *zDb, const void *pKey, int nKey) {
+ CODEC_TRACE(("sqlite3_key_v2: entered db=%p zDb=%s pKey=%s nKey=%d\n", db, zDb, (char *)pKey, nKey));
+ /* attach key if db and pKey are not null and nKey is > 0 */
+ if(db && pKey && nKey) {
@@ -1520,7 +1947,7 @@
+ return SQLITE_ERROR;
+}
+
-+SQLITE_API int sqlite3_rekey(sqlite3 *db, const void *pKey, int nKey) {
++SQLITE_API int SQLITE_STDCALL sqlite3_rekey(sqlite3 *db, const void *pKey, int nKey) {
+ CODEC_TRACE(("sqlite3_rekey entered: db=%p pKey=%s nKey=%d\n", db, (char *)pKey, nKey));
+ return sqlite3_rekey_v2(db, "main", pKey, nKey);
+}
@@ -1535,7 +1962,7 @@
+** 2. If there is NOT already a key present do nothing
+** 3. If there is a key present, re-encrypt the database with the new key
+*/
-+SQLITE_API int sqlite3_rekey_v2(sqlite3 *db, const char *zDb, const void *pKey, int nKey) {
++SQLITE_API int SQLITE_STDCALL sqlite3_rekey_v2(sqlite3 *db, const char *zDb, const void *pKey, int nKey) {
+ CODEC_TRACE(("sqlite3_rekey_v2: entered db=%p zDb=%s pKey=%s, nKey=%d\n", db, zDb, (char *)pKey, nKey));
+ if(db && pKey && nKey) {
+ int db_index = sqlcipher_find_db_index(db, zDb);
@@ -1591,7 +2018,7 @@
+ sqlcipher_codec_key_copy(ctx, CIPHER_WRITE_CTX);
+ } else {
+ CODEC_TRACE(("sqlite3_rekey_v2: rollback\n"));
-+ sqlite3BtreeRollback(pDb->pBt, SQLITE_ABORT_ROLLBACK);
++ sqlite3BtreeRollback(pDb->pBt, SQLITE_ABORT_ROLLBACK, 0);
+ }
+
+ sqlite3_mutex_leave(db->mutex);
@@ -1621,8 +2048,45 @@
+}
+
+#ifndef OMIT_EXPORT
-+
-+/*
+
+-/************** End of ctime.c ***********************************************/
+-/************** Begin file status.c ******************************************/
+-/*
+-** 2008 June 18
+-**
+-** 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 module implements the sqlite3_status() interface and related
+-** functionality.
+-*/
+-/************** Include vdbeInt.h in the middle of status.c ******************/
+-/************** Begin file vdbeInt.h *****************************************/
+ /*
+-** 2003 September 6
+-**
+-** 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 is the header file for information that is private to the
+-** VDBE. This information used to all be at the top of the single
+-** source code file "vdbe.c". When that file became too big (over
+-** 6000 lines long) it was split up into several smaller files and
+-** this header information was factored out.
+-*/
+-#ifndef _VDBEINT_H_
+-#define _VDBEINT_H_
+ * Implementation of an "export" function that allows a caller
+ * to duplicate the main database to an attached database. This is intended
+ * as a conveneince for users who need to:
@@ -1635,13 +2099,18 @@
+ * in vacuum.c, but is exposed as a function that allows export to any
+ * named attached database.
+ */
-+
-+/*
+
+ /*
+-** The maximum number of times that a statement will try to reparse
+-** itself before giving up and returning SQLITE_SCHEMA.
+** Finalize a prepared statement. If there was an error, store the
+** text of the error message in *pzErrMsg. Return the result code.
+**
+** Based on vacuumFinalize from vacuum.c
-+*/
+ */
+-#ifndef SQLITE_MAX_SCHEMA_RETRY
+-# define SQLITE_MAX_SCHEMA_RETRY 50
+-#endif
+static int sqlcipher_finalize(sqlite3 *db, sqlite3_stmt *pStmt, char **pzErrMsg){
+ int rc;
+ rc = sqlite3VdbeFinalize((Vdbe*)pStmt);
@@ -1650,12 +2119,16 @@
+ }
+ return rc;
+}
-+
-+/*
+
+ /*
+-** SQL is translated into a sequence of instructions to be
+-** executed by a virtual machine. Each instruction is an instance
+-** of the following structure.
+** Execute zSql on database db. Return an error code.
+**
+** Based on execSql from vacuum.c
-+*/
+ */
+-typedef struct VdbeOp Op;
+static int sqlcipher_execSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
+ sqlite3_stmt *pStmt;
+ VVA_ONLY( int rc; )
@@ -1670,20 +2143,29 @@
+ assert( rc!=SQLITE_ROW );
+ return sqlcipher_finalize(db, pStmt, pzErrMsg);
+}
-+
-+/*
+
+ /*
+-** Boolean values
+** Execute zSql on database db. The statement returns exactly
+** one column. Execute this as SQL on the same database.
+**
+** Based on execExecSql from vacuum.c
-+*/
+ */
+-typedef unsigned Bool;
+-
+-/* Opaque type used by code in vdbesort.c */
+-typedef struct VdbeSorter VdbeSorter;
+static int sqlcipher_execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
+ sqlite3_stmt *pStmt;
+ int rc;
-+
+
+-/* Opaque type used by the explainer */
+-typedef struct Explain Explain;
+ rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
+ if( rc!=SQLITE_OK ) return rc;
-+
+
+-/* Elements of the linked list at Vdbe.pAuxData */
+-typedef struct AuxData AuxData;
+ while( SQLITE_ROW==sqlite3_step(pStmt) ){
+ rc = sqlcipher_execSql(db, pzErrMsg, (char*)sqlite3_column_text(pStmt, 0));
+ if( rc!=SQLITE_OK ){
@@ -1694,12 +2176,33 @@
+
+ return sqlcipher_finalize(db, pStmt, pzErrMsg);
+}
-+
-+/*
+
+ /*
+-** A cursor is a pointer into a single BTree within a database file.
+-** The cursor can seek to a BTree entry with a particular key, or
+-** loop over all entries of the Btree. You can also insert new BTree
+-** entries or retrieve the key or data from the entry that the cursor
+-** is currently pointing to.
+-**
+-** Cursors can also point to virtual tables, sorters, or "pseudo-tables".
+-** A pseudo-table is a single-row table implemented by registers.
+-**
+-** Every cursor that the virtual machine has open is represented by an
+-** instance of the following structure.
+ * copy database and schema from the main database to an attached database
+ *
+ * Based on sqlite3RunVacuum from vacuum.c
-+*/
+ */
+-struct VdbeCursor {
+- BtCursor *pCursor; /* The cursor structure of the backend */
+- Btree *pBt; /* Separate file holding temporary table */
+- KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
+- int seekResult; /* Result of previous sqlite3BtreeMoveto() */
+- int pseudoTableReg; /* Register holding pseudotable content. */
+- i16 nField; /* Number of fields in the header */
+- u16 nHdrParsed; /* Number of header fields parsed so far */
+-#ifdef SQLITE_DEBUG
+- u8 seekOp; /* Most recent seek operation on this cursor */
+void sqlcipher_exportFunc(sqlite3_context *context, int argc, sqlite3_value **argv) {
+ sqlite3 *db = sqlite3_context_db_handle(context);
+ const char* attachedDb = (const char*) sqlite3_value_text(argv[0]);
@@ -1816,11 +2319,64 @@
+ }
+}
+
-+#endif
-+
+ #endif
+- i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */
+- u8 nullRow; /* True if pointing to a row with no data */
+- u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
+- Bool isEphemeral:1; /* True for an ephemeral table */
+- Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */
+- Bool isTable:1; /* True if a table requiring integer keys */
+- Bool isOrdered:1; /* True if the underlying table is BTREE_UNORDERED */
+- Pgno pgnoRoot; /* Root page of the open btree cursor */
+- sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */
+- i64 seqCount; /* Sequence counter */
+- i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
+- VdbeSorter *pSorter; /* Sorter object for OP_SorterOpen cursors */
+
+- /* Cached information about the header for the data record that the
+- ** cursor is currently pointing to. Only valid if cacheStatus matches
+- ** Vdbe.cacheCtr. Vdbe.cacheCtr will never take on the value of
+- ** CACHE_STALE and so setting cacheStatus=CACHE_STALE guarantees that
+- ** the cache is out of date.
+- **
+- ** aRow might point to (ephemeral) data for the current row, or it might
+- ** be NULL.
+- */
+- u32 cacheStatus; /* Cache is valid if this matches Vdbe.cacheCtr */
+- u32 payloadSize; /* Total number of bytes in the record */
+- u32 szRow; /* Byte available in aRow */
+- u32 iHdrOffset; /* Offset to next unparsed byte of the header */
+- const u8 *aRow; /* Data for the current row, if all on one page */
+- u32 *aOffset; /* Pointer to aType[nField] */
+- u32 aType[1]; /* Type values for all entries in the record */
+- /* 2*nField extra array elements allocated for aType[], beyond the one
+- ** static element declared in the structure. nField total array slots for
+- ** aType[] and nField+1 array slots for aOffset[] */
+-};
+-typedef struct VdbeCursor VdbeCursor;
+/* END SQLCIPHER */
+#endif
-+
+
+-/*
+-** When a sub-program is executed (OP_Program), a structure of this type
+-** is allocated to store the current value of the program counter, as
+-** well as the current memory cell array and various other frame specific
+-** values stored in the Vdbe struct. When the sub-program is finished,
+-** these values are copied back to the Vdbe from the VdbeFrame structure,
+-** restoring the state of the VM to as it was before the sub-program
+-** began executing.
+-**
+-** The memory for a VdbeFrame object is allocated and managed by a memory
+-** cell in the parent (calling) frame. When the memory cell is deleted or
+-** overwritten, the VdbeFrame object is not freed immediately. Instead, it
+-** is linked into the Vdbe.pDelFrame list. The contents of the Vdbe.pDelFrame
+-** list is deleted when the VM is reset in VdbeHalt(). The reason for doing
+-** this instead of deleting the VdbeFrame immediately is to avoid recursive
+-** calls to sqlite3VdbeMemRelease() when the memory cells belonging to the
+-** child frame are released.
+-**
+-** The currently executing frame is stored in Vdbe.pFrame. Vdbe.pFrame is
+-** set to NULL if the currently executing frame is the main program.
+/************** End of crypto.c **********************************************/
+/************** Begin file crypto_impl.c *************************************/
+/*
@@ -1852,10 +2408,35 @@
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**
-+*/
+ */
+-typedef struct VdbeFrame VdbeFrame;
+-struct VdbeFrame {
+- Vdbe *v; /* VM this frame belongs to */
+- VdbeFrame *pParent; /* Parent of this frame, or NULL if parent is main */
+- Op *aOp; /* Program instructions for parent frame */
+- i64 *anExec; /* Event counters from parent frame */
+- Mem *aMem; /* Array of memory cells for parent frame */
+- u8 *aOnceFlag; /* Array of OP_Once flags for parent frame */
+- VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */
+- void *token; /* Copy of SubProgram.token */
+- i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
+- int nCursor; /* Number of entries in apCsr */
+- int pc; /* Program Counter in parent (calling) frame */
+- int nOp; /* Size of aOp array */
+- int nMem; /* Number of entries in aMem */
+- int nOnceFlag; /* Number of entries in aOnceFlag */
+- int nChildMem; /* Number of memory cells for child frame */
+- int nChildCsr; /* Number of cursors for child frame */
+- int nChange; /* Statement changes (Vdbe.nChange) */
+- int nDbChange; /* Value of db->nChange */
+-};
+-
+-#define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))])
+/* BEGIN SQLCIPHER */
+#ifdef SQLITE_HAS_CODEC
-+
+
+-/*
+-** A value for VdbeCursor.cacheValid that means the cache is always invalid.
+/************** Include sqlcipher.h in the middle of crypto_impl.c ***********/
+/************** Begin file sqlcipher.h ***************************************/
+/*
@@ -1889,12 +2470,41 @@
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**
-+*/
+ */
+-#define CACHE_STALE 0
+/* BEGIN SQLCIPHER */
+#ifdef SQLITE_HAS_CODEC
+#ifndef SQLCIPHER_H
+#define SQLCIPHER_H
-+
+
+-/*
+-** Internally, the vdbe manipulates nearly all SQL values as Mem
+-** structures. Each Mem struct may cache multiple representations (string,
+-** integer etc.) of the same value.
+-*/
+-struct Mem {
+- union MemValue {
+- double r; /* Real value used when MEM_Real is set in flags */
+- i64 i; /* Integer value used when MEM_Int is set in flags */
+- int nZero; /* Used when bit MEM_Zero is set in flags */
+- FuncDef *pDef; /* Used only when flags==MEM_Agg */
+- RowSet *pRowSet; /* Used only when flags==MEM_RowSet */
+- VdbeFrame *pFrame; /* Used when flags==MEM_Frame */
+- } u;
+- u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
+- u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */
+- int n; /* Number of characters in string value, excluding '\0' */
+- char *z; /* String or BLOB value */
+- /* ShallowCopy only needs to copy the information above */
+- char *zMalloc; /* Space to hold MEM_Str or MEM_Blob if szMalloc>0 */
+- int szMalloc; /* Size of the zMalloc allocation */
+- u32 uTemp; /* Transient storage for serial_type in OP_MakeRecord */
+- sqlite3 *db; /* The associated database connection */
+- void (*xDel)(void*);/* Destructor for Mem.z - only valid if MEM_Dyn */
+-#ifdef SQLITE_DEBUG
+- Mem *pScopyFrom; /* This Mem is a shallow copy of pScopyFrom */
+- void *pFiller; /* So that sizeof(Mem) is a multiple of 8 */
+-#endif
+
+typedef struct {
+ int (*activate)(void *ctx);
@@ -1915,6 +2525,7 @@
+ int (*ctx_cmp)(void *c1, void *c2);
+ int (*ctx_init)(void **ctx);
+ int (*ctx_free)(void **ctx);
++ int (*fips_status)(void *ctx);
+} sqlcipher_provider;
+
+/* utility functions */
@@ -1937,7 +2548,7 @@
+/************** End of sqlcipher.h *******************************************/
+/************** Continuing where we left off in crypto_impl.c ****************/
+#ifndef OMIT_MEMLOCK
-+#if defined(__unix__) || defined(__APPLE__)
++#if defined(__unix__) || defined(__APPLE__) || defined(_AIX)
+#include <sys/mman.h>
+#elif defined(_WIN32)
+# include <windows.h>
@@ -1971,6 +2582,7 @@
+static unsigned int default_flags = DEFAULT_CIPHER_FLAGS;
+static unsigned char hmac_salt_mask = HMAC_SALT_MASK;
+static int default_kdf_iter = PBKDF2_ITER;
++static int default_page_size = SQLITE_DEFAULT_PAGE_SIZE;
+static unsigned int sqlcipher_activate_count = 0;
+static sqlite3_mutex* sqlcipher_provider_mutex = NULL;
+static sqlcipher_provider *default_provider = NULL;
@@ -1986,8 +2598,31 @@
+ cipher_ctx *write_ctx;
+ unsigned int skip_read_hmac;
+ unsigned int need_kdf_salt;
-+};
-+
+ };
+
+-/* One or more of the following flags are set to indicate the validOK
+-** representations of the value stored in the Mem struct.
+-**
+-** If the MEM_Null flag is set, then the value is an SQL NULL value.
+-** No other flags may be set in this case.
+-**
+-** If the MEM_Str flag is set then Mem.z points at a string representation.
+-** Usually this is encoded in the same unicode encoding as the main
+-** database (see below for exceptions). If the MEM_Term flag is also
+-** set, then the string is nul terminated. The MEM_Int and MEM_Real
+-** flags may coexist with the MEM_Str flag.
+-*/
+-#define MEM_Null 0x0001 /* Value is NULL */
+-#define MEM_Str 0x0002 /* Value is a string */
+-#define MEM_Int 0x0004 /* Value is an integer */
+-#define MEM_Real 0x0008 /* Value is a real number */
+-#define MEM_Blob 0x0010 /* Value is a BLOB */
+-#define MEM_AffMask 0x001f /* Mask of affinity bits */
+-#define MEM_RowSet 0x0020 /* Value is a RowSet object */
+-#define MEM_Frame 0x0040 /* Value is a VdbeFrame object */
+-#define MEM_Undefined 0x0080 /* Value is undefined */
+-#define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */
+-#define MEM_TypeMask 0x01ff /* Mask of type bits */
+int sqlcipher_register_provider(sqlcipher_provider *p) {
+ sqlite3_mutex_enter(sqlcipher_provider_mutex);
+ if(default_provider != NULL && default_provider != p) {
@@ -2000,22 +2635,48 @@
+ sqlite3_mutex_leave(sqlcipher_provider_mutex);
+ return SQLITE_OK;
+}
-+
+
+/* return a pointer to the currently registered provider. This will
+ allow an application to fetch the current registered provider and
+ make minor changes to it */
+sqlcipher_provider* sqlcipher_get_provider() {
+ return default_provider;
+}
-+
+
+-/* Whenever Mem contains a valid string or blob representation, one of
+-** the following flags must be set to determine the memory management
+-** policy for Mem.z. The MEM_Term flag tells us whether or not the
+-** string is \000 or \u0000 terminated
+-*/
+-#define MEM_Term 0x0200 /* String rep is nul terminated */
+-#define MEM_Dyn 0x0400 /* Need to call Mem.xDel() on Mem.z */
+-#define MEM_Static 0x0800 /* Mem.z points to a static string */
+-#define MEM_Ephem 0x1000 /* Mem.z points to an ephemeral string */
+-#define MEM_Agg 0x2000 /* Mem.z points to an agg function context */
+-#define MEM_Zero 0x4000 /* Mem.i contains count of 0s appended to blob */
+-#ifdef SQLITE_OMIT_INCRBLOB
+- #undef MEM_Zero
+- #define MEM_Zero 0x0000
+-#endif
+void sqlcipher_activate() {
+ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
-+
+
+-/*
+-** Clear any existing type flags from a Mem and replace them with f
+-*/
+-#define MemSetTypeFlag(p, f) \
+- ((p)->flags = ((p)->flags&~(MEM_TypeMask|MEM_Zero))|f)
+ if(sqlcipher_provider_mutex == NULL) {
+ /* allocate a new mutex to guard access to the provider */
+ sqlcipher_provider_mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
+ }
-+
+
+-/*
+-** Return true if a memory cell is not marked as invalid. This macro
+-** is for use inside assert() statements only.
+-*/
+-#ifdef SQLITE_DEBUG
+-#define memIsValid(M) ((M)->flags & MEM_Undefined)==0
+ /* check to see if there is a provider registered at this point
+ if there no provider registered at this point, register the
+ default provider */
@@ -2032,15 +2693,63 @@
+ sqlcipher_openssl_setup(p);
+#else
+#error "NO DEFAULT SQLCIPHER CRYPTO PROVIDER DEFINED"
-+#endif
+ #endif
+ sqlcipher_register_provider(p);
+ }
-+
+
+-/*
+-** Each auxiliary data pointer stored by a user defined function
+-** implementation calling sqlite3_set_auxdata() is stored in an instance
+-** of this structure. All such structures associated with a single VM
+-** are stored in a linked list headed at Vdbe.pAuxData. All are destroyed
+-** when the VM is halted (if not before).
+-*/
+-struct AuxData {
+- int iOp; /* Instruction number of OP_Function opcode */
+- int iArg; /* Index of function argument. */
+- void *pAux; /* Aux data pointer */
+- void (*xDelete)(void *); /* Destructor for the aux data */
+- AuxData *pNext; /* Next element in list */
+-};
+ sqlcipher_activate_count++; /* increment activation count */
-+
+
+-/*
+-** The "context" argument for an installable function. A pointer to an
+-** instance of this structure is the first argument to the routines used
+-** implement the SQL functions.
+-**
+-** There is a typedef for this structure in sqlite.h. So all routines,
+-** even the public interface to SQLite, can use a pointer to this structure.
+-** But this file is the only place where the internal details of this
+-** structure are known.
+-**
+-** This structure is defined inside of vdbeInt.h because it uses substructures
+-** (Mem) which are only defined there.
+-*/
+-struct sqlite3_context {
+- Mem *pOut; /* The return value is stored here */
+- FuncDef *pFunc; /* Pointer to function information */
+- Mem *pMem; /* Memory cell used to store aggregate context */
+- Vdbe *pVdbe; /* The VM that owns this context */
+- int iOp; /* Instruction number of OP_Function */
+- int isError; /* Error code returned by the function. */
+- u8 skipFlag; /* Skip accumulator loading if true */
+- u8 fErrorOrAux; /* isError!=0 or pVdbe->pAuxData modified */
+-};
+ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+}
-+
+
+-/*
+-** An Explain object accumulates indented output which is helpful
+-** in describing recursive data structures.
+-*/
+-struct Explain {
+- Vdbe *pVdbe; /* Attach the explanation to this Vdbe */
+- StrAccum str; /* The string being accumulated */
+- int nIndent; /* Number of elements in aIndent */
+- u16 aIndent[100]; /* Levels of indentation */
+- char zBase[100]; /* Initial space */
+-};
+void sqlcipher_deactivate() {
+ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+ sqlcipher_activate_count--;
@@ -2056,7 +2765,9 @@
+ /* last connection closed, free provider mutex*/
+ sqlite3_mutex_free(sqlcipher_provider_mutex);
+ sqlcipher_provider_mutex = NULL;
-+
+
+-/* A bitfield type for use inside of structures. Always follow with :N where
+-** N is the number of bits.
+ sqlcipher_activate_count = 0; /* reset activation count */
+ }
+ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
@@ -2065,47 +2776,218 @@
+/* constant time memset using volitile to avoid having the memset
+ optimized out by the compiler.
+ Note: As suggested by Joachim Schipper (joachim schipper fox-it com)
-+*/
+ */
+-typedef unsigned bft; /* Bit Field Type */
+void* sqlcipher_memset(void *v, unsigned char value, int len) {
+ int i = 0;
+ volatile unsigned char *a = v;
-+
+
+-typedef struct ScanStatus ScanStatus;
+-struct ScanStatus {
+- int addrExplain; /* OP_Explain for loop */
+- int addrLoop; /* Address of "loops" counter */
+- int addrVisit; /* Address of "rows visited" counter */
+- int iSelectID; /* The "Select-ID" for this loop */
+- LogEst nEst; /* Estimated output rows per loop */
+- char *zName; /* Name of table or index */
+-};
+ if (v == NULL) return v;
-+
+
+-/*
+-** An instance of the virtual machine. This structure contains the complete
+-** state of the virtual machine.
+-**
+-** The "sqlite3_stmt" structure pointer that is returned by sqlite3_prepare()
+-** is really a pointer to an instance of this structure.
+-*/
+-struct Vdbe {
+- sqlite3 *db; /* The database connection that owns this statement */
+- Op *aOp; /* Space to hold the virtual machine's program */
+- Mem *aMem; /* The memory locations */
+- Mem **apArg; /* Arguments to currently executing user function */
+- Mem *aColName; /* Column names to return */
+- Mem *pResultSet; /* Pointer to an array of results */
+- Parse *pParse; /* Parsing context used to create this Vdbe */
+- int nMem; /* Number of memory locations currently allocated */
+- int nOp; /* Number of instructions in the program */
+- int nCursor; /* Number of slots in apCsr[] */
+- u32 magic; /* Magic number for sanity checking */
+- char *zErrMsg; /* Error message written here */
+- Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
+- VdbeCursor **apCsr; /* One element of this array for each open cursor */
+- Mem *aVar; /* Values for the OP_Variable opcode. */
+- char **azVar; /* Name of variables */
+- ynVar nVar; /* Number of entries in aVar[] */
+- ynVar nzVar; /* Number of entries in azVar[] */
+- u32 cacheCtr; /* VdbeCursor row cache generation counter */
+- int pc; /* The program counter */
+- int rc; /* Value to return */
+-#ifdef SQLITE_DEBUG
+- int rcApp; /* errcode set by sqlite3_result_error_code() */
+-#endif
+- u16 nResColumn; /* Number of columns in one row of the result set */
+- u8 errorAction; /* Recovery action to do in case of an error */
+- u8 minWriteFileFormat; /* Minimum file format for writable database files */
+- bft explain:2; /* True if EXPLAIN present on SQL command */
+- bft changeCntOn:1; /* True to update the change-counter */
+- bft expired:1; /* True if the VM needs to be recompiled */
+- bft runOnlyOnce:1; /* Automatically expire on reset */
+- bft usesStmtJournal:1; /* True if uses a statement journal */
+- bft readOnly:1; /* True for statements that do not write */
+- bft bIsReader:1; /* True for statements that read */
+- bft isPrepareV2:1; /* True if prepared with prepare_v2() */
+- bft doingRerun:1; /* True if rerunning after an auto-reprepare */
+- int nChange; /* Number of db changes made since last reset */
+- yDbMask btreeMask; /* Bitmask of db->aDb[] entries referenced */
+- yDbMask lockMask; /* Subset of btreeMask that requires a lock */
+- int iStatement; /* Statement number (or 0 if has not opened stmt) */
+- u32 aCounter[5]; /* Counters used by sqlite3_stmt_status() */
+-#ifndef SQLITE_OMIT_TRACE
+- i64 startTime; /* Time when query started - used for profiling */
+-#endif
+- i64 iCurrentTime; /* Value of julianday('now') for this statement */
+- i64 nFkConstraint; /* Number of imm. FK constraints this VM */
+- i64 nStmtDefCons; /* Number of def. constraints when stmt started */
+- i64 nStmtDefImmCons; /* Number of def. imm constraints when stmt started */
+- char *zSql; /* Text of the SQL statement that generated this */
+- void *pFree; /* Free this when deleting the vdbe */
+- VdbeFrame *pFrame; /* Parent frame */
+- VdbeFrame *pDelFrame; /* List of frame objects to free on VM reset */
+- int nFrame; /* Number of frames in pFrame list */
+- u32 expmask; /* Binding to these vars invalidates VM */
+- SubProgram *pProgram; /* Linked list of all sub-programs used by VM */
+- int nOnceFlag; /* Size of array aOnceFlag[] */
+- u8 *aOnceFlag; /* Flags for OP_Once */
+- AuxData *pAuxData; /* Linked list of auxdata allocations */
+-#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+- i64 *anExec; /* Number of times each op has been executed */
+- int nScan; /* Entries in aScan[] */
+- ScanStatus *aScan; /* Scan definitions for sqlite3_stmt_scanstatus() */
+-#endif
+-};
+ for(i = 0; i < len; i++) {
+ a[i] = value;
+ }
-+
+
+-/*
+-** The following are allowed values for Vdbe.magic
+-*/
+-#define VDBE_MAGIC_INIT 0x26bceaa5 /* Building a VDBE program */
+-#define VDBE_MAGIC_RUN 0xbdf20da3 /* VDBE is ready to execute */
+-#define VDBE_MAGIC_HALT 0x519c2973 /* VDBE has completed execution */
+-#define VDBE_MAGIC_DEAD 0xb606c3c8 /* The VDBE has been deallocated */
+ return v;
+}
-+
+
+-/*
+-** Function prototypes
+-*/
+-SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*);
+-void sqliteVdbePopStack(Vdbe*,int);
+-SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor*);
+-SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor*);
+-#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
+-SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE*, int, Op*);
+-#endif
+-SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32);
+-SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem*, int);
+-SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32);
+-SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
+-SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(Vdbe*, int, int);
+/* constant time memory check tests every position of a memory segement
+ matches a single value (i.e. the memory is all zeros)
+ returns 0 if match, 1 of no match */
+int sqlcipher_ismemset(const void *v, unsigned char value, int len) {
+ const unsigned char *a = v;
+ int i = 0, result = 0;
-+
+
+-int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
+-SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(sqlite3*,VdbeCursor*,UnpackedRecord*,int*);
+-SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3*, BtCursor*, i64*);
+-SQLITE_PRIVATE int sqlite3VdbeExec(Vdbe*);
+-SQLITE_PRIVATE int sqlite3VdbeList(Vdbe*);
+-SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe*);
+-SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *, int);
+-SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem*);
+-SQLITE_PRIVATE int sqlite3VdbeMemCopy(Mem*, const Mem*);
+-SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem*, const Mem*, int);
+-SQLITE_PRIVATE void sqlite3VdbeMemMove(Mem*, Mem*);
+-SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem*);
+-SQLITE_PRIVATE int sqlite3VdbeMemSetStr(Mem*, const char*, int, u8, void(*)(void*));
+-SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem*, i64);
+-#ifdef SQLITE_OMIT_FLOATING_POINT
+-# define sqlite3VdbeMemSetDouble sqlite3VdbeMemSetInt64
+-#else
+-SQLITE_PRIVATE void sqlite3VdbeMemSetDouble(Mem*, double);
+-#endif
+-SQLITE_PRIVATE void sqlite3VdbeMemInit(Mem*,sqlite3*,u16);
+-SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem*);
+-SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem*,int);
+-SQLITE_PRIVATE void sqlite3VdbeMemSetRowSet(Mem*);
+-SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem*);
+-SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem*, u8, u8);
+-SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem*);
+-SQLITE_PRIVATE int sqlite3VdbeMemIntegerify(Mem*);
+-SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem*);
+-SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem*);
+-SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem*);
+-SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem*);
+-SQLITE_PRIVATE void sqlite3VdbeMemCast(Mem*,u8,u8);
+-SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,int,Mem*);
+-SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p);
+-#define VdbeMemDynamic(X) \
+- (((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))!=0)
+-SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
+-SQLITE_PRIVATE const char *sqlite3OpcodeName(int);
+-SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve);
+-SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int n);
+-SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *, int);
+-SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*);
+-SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *);
+-SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p);
+ for(i = 0; i < len; i++) {
+ result |= a[i] ^ value;
+ }
-+
+
+-SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *, int, VdbeCursor *);
+-SQLITE_PRIVATE void sqlite3VdbeSorterReset(sqlite3 *, VdbeSorter *);
+-SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *);
+-SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *);
+-SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *);
+-SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *, int *);
+-SQLITE_PRIVATE int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *);
+-SQLITE_PRIVATE int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *);
+ return (result != 0);
+}
-+
+
+-#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0
+-SQLITE_PRIVATE void sqlite3VdbeEnter(Vdbe*);
+-SQLITE_PRIVATE void sqlite3VdbeLeave(Vdbe*);
+-#else
+-# define sqlite3VdbeEnter(X)
+-# define sqlite3VdbeLeave(X)
+-#endif
+/* constant time memory comparison routine.
+ returns 0 if match, 1 if no match */
+int sqlcipher_memcmp(const void *v0, const void *v1, int len) {
+ const unsigned char *a0 = v0, *a1 = v1;
+ int i = 0, result = 0;
-+
+
+-#ifdef SQLITE_DEBUG
+-SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe*,Mem*);
+-SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem*);
+-#endif
+ for(i = 0; i < len; i++) {
+ result |= a0[i] ^ a1[i];
+ }
+
+ return (result != 0);
+}
-+
+
+-#ifndef SQLITE_OMIT_FOREIGN_KEY
+-SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *, int);
+-#else
+-# define sqlite3VdbeCheckFk(p,i) 0
+/**
+ * Free and wipe memory. Uses SQLites internal sqlite3_free so that memory
+ * can be countend and memory leak detection works in the test suite.
@@ -2124,14 +3006,26 @@
+#elif defined(_WIN32)
+#if !(defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP || WINAPI_FAMILY ==
WINAPI_FAMILY_APP))
+VirtualUnlock(ptr, sz);
-+#endif
-+#endif
+ #endif
+-
+-SQLITE_PRIVATE int sqlite3VdbeMemTranslate(Mem*, u8);
+-#ifdef SQLITE_DEBUG
+-SQLITE_PRIVATE void sqlite3VdbePrintSql(Vdbe*);
+-SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf);
+ #endif
+-SQLITE_PRIVATE int sqlite3VdbeMemHandleBom(Mem *pMem);
+#endif
+ }
+ sqlite3_free(ptr);
+ }
+}
-+
+
+-#ifndef SQLITE_OMIT_INCRBLOB
+-SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *);
+- #define ExpandBlob(P) (((P)->flags&MEM_Zero)?sqlite3VdbeMemExpandBlob(P):0)
+-#else
+- #define sqlite3VdbeMemExpandBlob(x) SQLITE_OK
+- #define ExpandBlob(P) SQLITE_OK
+/**
+ * allocate memory. Uses sqlite's internall malloc wrapper so memory can be
+ * reference counted and leak detection works. Unless compiled with OMIT_MEMLOCK
@@ -2148,13 +3042,16 @@
+#if !(defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP || WINAPI_FAMILY ==
WINAPI_FAMILY_APP))
+ VirtualLock(ptr, sz);
+#endif
-+#endif
+ #endif
+ }
+#endif
+ return ptr;
+}
-+
-+
+
+-#endif /* !defined(_VDBEINT_H_) */
+
+-/************** End of vdbeInt.h *********************************************/
+-/************** Continuing where we left off in status.c *********************/
+/**
+ * Initialize new cipher_ctx struct. This function will allocate memory
+ * for the cipher context and for the key
@@ -2182,13 +3079,42 @@
+ ctx->hmac_key = (unsigned char *) sqlcipher_malloc(CIPHER_MAX_KEY_SZ);
+ if(ctx->key == NULL) return SQLITE_NOMEM;
+ if(ctx->hmac_key == NULL) return SQLITE_NOMEM;
-+
+
+-/*
+-** Variables in which to record status information.
+-*/
+-typedef struct sqlite3StatType sqlite3StatType;
+-static SQLITE_WSD struct sqlite3StatType {
+-#if SQLITE_PTRSIZE>4
+- sqlite3_int64 nowValue[10]; /* Current value */
+- sqlite3_int64 mxValue[10]; /* Maximum value */
+-#else
+- u32 nowValue[10]; /* Current value */
+- u32 mxValue[10]; /* Maximum value */
+-#endif
+-} sqlite3Stat = { {0,}, {0,} };
+ /* setup default flags */
+ ctx->flags = default_flags;
-+
+
+-/*
+-** Elements of sqlite3Stat[] are protected by either the memory allocator
+-** mutex, or by the pcache1 mutex. The following array determines which.
+-*/
+-static const char statMutex[] = {
+- 0, /* SQLITE_STATUS_MEMORY_USED */
+- 1, /* SQLITE_STATUS_PAGECACHE_USED */
+- 1, /* SQLITE_STATUS_PAGECACHE_OVERFLOW */
+- 0, /* SQLITE_STATUS_SCRATCH_USED */
+- 0, /* SQLITE_STATUS_SCRATCH_OVERFLOW */
+- 0, /* SQLITE_STATUS_MALLOC_SIZE */
+- 0, /* SQLITE_STATUS_PARSER_STACK */
+- 1, /* SQLITE_STATUS_PAGECACHE_SIZE */
+- 0, /* SQLITE_STATUS_SCRATCH_SIZE */
+- 0, /* SQLITE_STATUS_MALLOC_COUNT */
+-};
+ return SQLITE_OK;
+}
-+
+
+/**
+ * Free and wipe memory associated with a cipher_ctx
+ */
@@ -2307,7 +3233,20 @@
+ }
+ return SQLITE_OK;
+}
-+
+
+-/* The "wsdStat" macro will resolve to the status information
+-** state vector. If writable static data is unsupported on the target,
+-** we have to locate the state vector at run-time. In the more common
+-** case where writable static data is supported, wsdStat can refer directly
+-** to the "sqlite3Stat" state vector declared above.
+-*/
+-#ifdef SQLITE_OMIT_WSD
+-# define wsdStatInit sqlite3StatType *x = &GLOBAL(sqlite3StatType,sqlite3Stat)
+-# define wsdStat x[0]
+-#else
+-# define wsdStatInit
+-# define wsdStat sqlite3Stat
+-#endif
+/**
+ * Set the keyspec for the cipher_ctx
+ *
@@ -2334,20 +3273,74 @@
+ ctx->keyspec[ctx->keyspec_sz - 1] = '\'';
+ return SQLITE_OK;
+}
-+
-+static int sqlcipher_codec_get_store_pass(codec_ctx *ctx) {
+
+-/*
+-** Return the current value of a status parameter. The caller must
+-** be holding the appropriate mutex.
+-*/
+-SQLITE_PRIVATE sqlite3_int64 sqlite3StatusValue(int op){
+- wsdStatInit;
+- assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
+- assert( op>=0 && op<ArraySize(statMutex) );
+- assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
+- : sqlite3MallocMutex()) );
+- return wsdStat.nowValue[op];
++int sqlcipher_codec_get_store_pass(codec_ctx *ctx) {
+ return ctx->read_ctx->store_pass;
-+}
-+
-+static void sqlcipher_codec_set_store_pass(codec_ctx *ctx, int value) {
+ }
+
+-/*
+-** Add N to the value of a status record. The caller must hold the
+-** appropriate mutex. (Locking is checked by assert()).
+-**
+-** The StatusUp() routine can accept positive or negative values for N.
+-** The value of N is added to the current status value and the high-water
+-** mark is adjusted if necessary.
+-**
+-** The StatusDown() routine lowers the current value by N. The highwater
+-** mark is unchanged. N must be non-negative for StatusDown().
+-*/
+-SQLITE_PRIVATE void sqlite3StatusUp(int op, int N){
+- wsdStatInit;
+- assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
+- assert( op>=0 && op<ArraySize(statMutex) );
+- assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
+- : sqlite3MallocMutex()) );
+- wsdStat.nowValue[op] += N;
+- if( wsdStat.nowValue[op]>wsdStat.mxValue[op] ){
+- wsdStat.mxValue[op] = wsdStat.nowValue[op];
+- }
++void sqlcipher_codec_set_store_pass(codec_ctx *ctx, int value) {
+ ctx->read_ctx->store_pass = value;
-+}
-+
-+static void sqlcipher_codec_get_pass(codec_ctx *ctx, void **zKey, int *nKey) {
+ }
+-SQLITE_PRIVATE void sqlite3StatusDown(int op, int N){
+- wsdStatInit;
+- assert( N>=0 );
+- assert( op>=0 && op<ArraySize(statMutex) );
+- assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
+- : sqlite3MallocMutex()) );
+- assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
+- wsdStat.nowValue[op] -= N;
++
++void sqlcipher_codec_get_pass(codec_ctx *ctx, void **zKey, int *nKey) {
+ *zKey = ctx->read_ctx->pass;
+ *nKey = ctx->read_ctx->pass_sz;
-+}
-+
+ }
+
+-/*
+-** Set the value of a status to X. The highwater mark is adjusted if
+-** necessary. The caller must hold the appropriate mutex.
+-*/
+-SQLITE_PRIVATE void sqlite3StatusSet(int op, int X){
+- wsdStatInit;
+- assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
+- assert( op>=0 && op<ArraySize(statMutex) );
+- assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
+- : sqlite3MallocMutex()) );
+- wsdStat.nowValue[op] = X;
+- if( wsdStat.nowValue[op]>wsdStat.mxValue[op] ){
+- wsdStat.mxValue[op] = wsdStat.nowValue[op];
+- }
+/**
+ * Set the passphrase for the cipher_ctx
+ *
@@ -2368,8 +3361,34 @@
+ memcpy(ctx->pass, zKey, nKey);
+ }
+ return SQLITE_OK;
-+}
-+
+ }
+
+-/*
+-** Query status information.
+-*/
+-SQLITE_API int SQLITE_STDCALL sqlite3_status64(
+- int op,
+- sqlite3_int64 *pCurrent,
+- sqlite3_int64 *pHighwater,
+- int resetFlag
+-){
+- sqlite3_mutex *pMutex;
+- wsdStatInit;
+- if( op<0 || op>=ArraySize(wsdStat.nowValue) ){
+- return SQLITE_MISUSE_BKPT;
+- }
+-#ifdef SQLITE_ENABLE_API_ARMOR
+- if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT;
+-#endif
+- pMutex = statMutex[op] ? sqlite3Pcache1Mutex() : sqlite3MallocMutex();
+- sqlite3_mutex_enter(pMutex);
+- *pCurrent = wsdStat.nowValue[op];
+- *pHighwater = wsdStat.mxValue[op];
+- if( resetFlag ){
+- wsdStat.mxValue[op] = wsdStat.nowValue[op];
+- }
+- sqlite3_mutex_leave(pMutex);
+- (void)pMutex; /* Prevent warning when SQLITE_THREADSAFE=0 */
+int sqlcipher_codec_ctx_set_pass(codec_ctx *ctx, const void *zKey, int nKey, int for_ctx) {
+ cipher_ctx *c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
+ int rc;
@@ -2400,8 +3419,10 @@
+ if((rc = sqlcipher_cipher_ctx_copy( for_ctx ? ctx->read_ctx : ctx->write_ctx, c_ctx)) != SQLITE_OK)
+ return rc;
+
-+ return SQLITE_OK;
-+}
+ return SQLITE_OK;
+ }
+-SQLITE_API int SQLITE_STDCALL sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){
+- sqlite3_int64 iCur, iHwtr;
+
+const char* sqlcipher_codec_ctx_get_cipher(codec_ctx *ctx, int for_ctx) {
+ cipher_ctx *c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
@@ -2419,7 +3440,14 @@
+
+int sqlcipher_codec_ctx_set_kdf_iter(codec_ctx *ctx, int kdf_iter, int for_ctx) {
+ cipher_ctx *c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
-+ int rc;
+ int rc;
+-#ifdef SQLITE_ENABLE_API_ARMOR
+- if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT;
+-#endif
+- rc = sqlite3_status64(op, &iCur, &iHwtr, resetFlag);
+- if( rc==0 ){
+- *pCurrent = (int)iCur;
+- *pHighwater = (int)iHwtr;
+
+ c_ctx->kdf_iter = kdf_iter;
+ c_ctx->derive_key = 1;
@@ -2562,6 +3590,14 @@
+ return ctx->page_sz;
+}
+
++void sqlcipher_set_default_pagesize(int page_size) {
++ default_page_size = page_size;
++}
++
++int sqlcipher_get_default_pagesize() {
++ return default_page_size;
++}
++
+int sqlcipher_codec_ctx_init(codec_ctx **iCtx, Db *pDb, Pager *pPager, sqlite3_file *fd, const void *zKey,
int nKey) {
+ int rc;
+ codec_ctx *ctx;
@@ -2592,14 +3628,15 @@
+ in encrypted and thus sqlite can't effectively determine the pagesize. this causes an issue in
+ cases where bytes 16 & 17 of the page header are a power of 2 as reported by John Lehman
+ */
-+ if((rc = sqlcipher_codec_ctx_set_pagesize(ctx, SQLITE_DEFAULT_PAGE_SIZE)) != SQLITE_OK) return rc;
++ if((rc = sqlcipher_codec_ctx_set_pagesize(ctx, default_page_size)) != SQLITE_OK) return rc;
+
+ if((rc = sqlcipher_cipher_ctx_init(&ctx->read_ctx)) != SQLITE_OK) return rc;
+ if((rc = sqlcipher_cipher_ctx_init(&ctx->write_ctx)) != SQLITE_OK) return rc;
+
+ if(fd == NULL || sqlite3OsRead(fd, ctx->kdf_salt, FILE_HEADER_SZ, 0) != SQLITE_OK) {
+ ctx->need_kdf_salt = 1;
-+ }
+ }
+- return rc;
+
+ if((rc = sqlcipher_codec_ctx_set_cipher(ctx, CIPHER, 0)) != SQLITE_OK) return rc;
+ if((rc = sqlcipher_codec_ctx_set_kdf_iter(ctx, default_kdf_iter, 0)) != SQLITE_OK) return rc;
@@ -2665,9 +3702,33 @@
+ in_sz, (unsigned char*) &pgno_raw,
+ sizeof(pgno), out);
+ return SQLITE_OK;
-+}
-+
-+/*
+ }
+
+ /*
+-** Query status information for a single database connection
+-*/
+-SQLITE_API int SQLITE_STDCALL sqlite3_db_status(
+- sqlite3 *db, /* The database connection whose status is desired */
+- int op, /* Status verb */
+- int *pCurrent, /* Write current value here */
+- int *pHighwater, /* Write high-water mark here */
+- int resetFlag /* Reset high-water mark if true */
+-){
+- int rc = SQLITE_OK; /* Return code */
+-#ifdef SQLITE_ENABLE_API_ARMOR
+- if( !sqlite3SafetyCheckOk(db) || pCurrent==0|| pHighwater==0 ){
+- return SQLITE_MISUSE_BKPT;
+- }
+-#endif
+- sqlite3_mutex_enter(db->mutex);
+- switch( op ){
+- case SQLITE_DBSTATUS_LOOKASIDE_USED: {
+- *pCurrent = db->lookaside.nOut;
+- *pHighwater = db->lookaside.mxOut;
+- if( resetFlag ){
+- db->lookaside.mxOut = db->lookaside.nOut;
+- }
+- break;
+ * ctx - codec context
+ * pgno - page number in database
+ * size - size in bytes of input and output buffers
@@ -2713,8 +3774,20 @@
+ sqlcipher_memset(out, 0, page_sz);
+ CODEC_TRACE(("codec_cipher: hmac operations failed for pgno=%d\n", pgno));
+ return SQLITE_ERROR;
-+ }
-+
+ }
+
+- case SQLITE_DBSTATUS_LOOKASIDE_HIT:
+- case SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE:
+- case SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL: {
+- testcase( op==SQLITE_DBSTATUS_LOOKASIDE_HIT );
+- testcase( op==SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE );
+- testcase( op==SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL );
+- assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)>=0 );
+- assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)<3 );
+- *pCurrent = 0;
+- *pHighwater = db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT];
+- if( resetFlag ){
+- db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT] = 0;
+ CODEC_TRACE(("codec_cipher: comparing hmac on in=%p out=%p hmac_sz=%d\n", hmac_in, hmac_out,
c_ctx->hmac_sz));
+ if(sqlcipher_memcmp(hmac_in, hmac_out, c_ctx->hmac_sz) != 0) { /* the hmac check failed */
+ if(sqlcipher_ismemset(in, 0, page_sz) == 0) {
@@ -2732,12 +3805,20 @@
+ CODEC_TRACE(("codec_cipher: hmac check failed for pgno=%d returning SQLITE_ERROR\n", pgno));
+ sqlcipher_memset(out, 0, page_sz);
+ return SQLITE_ERROR;
-+ }
-+ }
+ }
+- break;
+ }
+ }
+
+ c_ctx->provider->cipher(c_ctx->provider_ctx, mode, c_ctx->key, c_ctx->key_sz, iv_out, in, size, out);
-+
+
+- /*
+- ** Return an approximation for the amount of memory currently used
+- ** by all pagers associated with the given database connection. The
+- ** highwater mark is meaningless and is returned as zero.
+- */
+- case SQLITE_DBSTATUS_CACHE_USED: {
+- int totalUsed = 0;
+ if((c_ctx->flags & CIPHER_FLAG_HMAC) && (mode == CIPHER_ENCRYPT)) {
+ sqlcipher_page_hmac(c_ctx, pgno, out_start, size + c_ctx->iv_sz, hmac_out);
+ }
@@ -2801,8 +3882,29 @@
+ key for HMAC. In this case, we use the output of the previous KDF as the input to
+ this KDF run. This ensures a distinct but predictable HMAC key. */
+ if(c_ctx->flags & CIPHER_FLAG_HMAC) {
-+ int i;
-+
+ int i;
+- sqlite3BtreeEnterAll(db);
+- for(i=0; i<db->nDb; i++){
+- Btree *pBt = db->aDb[i].pBt;
+- if( pBt ){
+- Pager *pPager = sqlite3BtreePager(pBt);
+- totalUsed += sqlite3PagerMemUsed(pPager);
+- }
+- }
+- sqlite3BtreeLeaveAll(db);
+- *pCurrent = totalUsed;
+- *pHighwater = 0;
+- break;
+- }
+
+- /*
+- ** *pCurrent gets an accurate estimate of the amount of memory used
+- ** to store the schema for all databases (main, temp, and any ATTACHed
+- ** databases. *pHighwater is set to zero.
+- */
+- case SQLITE_DBSTATUS_SCHEMA_USED: {
+- int i; /* Used to iterate through schemas */
+- int nByte = 0; /* Used to accumulate return value */
+ /* start by copying the kdf key into the hmac salt slot
+ then XOR it with the fixed hmac salt defined at compile time
+ this ensures that the salt passed in to derive the hmac key, while
@@ -2812,22 +3914,51 @@
+ for(i = 0; i < ctx->kdf_salt_sz; i++) {
+ ctx->hmac_kdf_salt[i] ^= hmac_salt_mask;
+ }
-+
+
+- sqlite3BtreeEnterAll(db);
+- db->pnBytesFreed = &nByte;
+- for(i=0; i<db->nDb; i++){
+- Schema *pSchema = db->aDb[i].pSchema;
+- if( ALWAYS(pSchema!=0) ){
+- HashElem *p;
+ CODEC_TRACE(("cipher_ctx_key_derive: deriving hmac key from encryption key using PBKDF2 with %d
iterations\n",
+ c_ctx->fast_kdf_iter));
-+
+
+- nByte += sqlite3GlobalConfig.m.xRoundup(sizeof(HashElem)) * (
+- pSchema->tblHash.count
+- + pSchema->trigHash.count
+- + pSchema->idxHash.count
+- + pSchema->fkeyHash.count
+- );
+- nByte += sqlite3MallocSize(pSchema->tblHash.ht);
+- nByte += sqlite3MallocSize(pSchema->trigHash.ht);
+- nByte += sqlite3MallocSize(pSchema->idxHash.ht);
+- nByte += sqlite3MallocSize(pSchema->fkeyHash.ht);
+
+ c_ctx->provider->kdf(c_ctx->provider_ctx, c_ctx->key, c_ctx->key_sz,
+ ctx->hmac_kdf_salt, ctx->kdf_salt_sz, c_ctx->fast_kdf_iter,
+ c_ctx->key_sz, c_ctx->hmac_key);
+ }
-+
+
+- for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){
+- sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
+- }
+- for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){
+- sqlite3DeleteTable(db, (Table *)sqliteHashData(p));
+- }
+- }
+- }
+- db->pnBytesFreed = 0;
+- sqlite3BtreeLeaveAll(db);
+ c_ctx->derive_key = 0;
+ return SQLITE_OK;
+ };
+ return SQLITE_ERROR;
+}
-+
+
+- *pHighwater = 0;
+- *pCurrent = nByte;
+- break;
+int sqlcipher_codec_key_derive(codec_ctx *ctx) {
+ /* derive key on first use if necessary */
+ if(ctx->read_ctx->derive_key) {
@@ -2840,18 +3971,34 @@
+ if(sqlcipher_cipher_ctx_copy(ctx->write_ctx, ctx->read_ctx) != SQLITE_OK) return SQLITE_ERROR;
+ } else {
+ if(sqlcipher_cipher_ctx_key_derive(ctx, ctx->write_ctx) != SQLITE_OK) return SQLITE_ERROR;
-+ }
+ }
+ }
-+
+
+- /*
+- ** *pCurrent gets an accurate estimate of the amount of memory used
+- ** to store all prepared statements.
+- ** *pHighwater is set to zero.
+- */
+- case SQLITE_DBSTATUS_STMT_USED: {
+- struct Vdbe *pVdbe; /* Used to iterate through VMs */
+- int nByte = 0; /* Used to accumulate return value */
+ /* TODO: wipe and free passphrase after key derivation */
+ if(ctx->read_ctx->store_pass != 1) {
+ sqlcipher_cipher_ctx_set_pass(ctx->read_ctx, NULL, 0);
+ sqlcipher_cipher_ctx_set_pass(ctx->write_ctx, NULL, 0);
+ }
-+
+
+- db->pnBytesFreed = &nByte;
+- for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){
+- sqlite3VdbeClearObject(db, pVdbe);
+- sqlite3DbFree(db, pVdbe);
+- }
+- db->pnBytesFreed = 0;
+ return SQLITE_OK;
+}
-+
+
+- *pHighwater = 0; /* IMP: R-64479-57858 */
+- *pCurrent = nByte;
+int sqlcipher_codec_key_copy(codec_ctx *ctx, int source) {
+ if(source == CIPHER_READ_CTX) {
+ return sqlcipher_cipher_ctx_copy(ctx->write_ctx, ctx->read_ctx);
@@ -2859,12 +4006,31 @@
+ return sqlcipher_cipher_ctx_copy(ctx->read_ctx, ctx->write_ctx);
+ }
+}
-+
+
+- break;
+- }
+const char* sqlcipher_codec_get_cipher_provider(codec_ctx *ctx) {
+ return ctx->read_ctx->provider->get_provider_name(ctx->read_ctx);
+}
-+
-+
+
+- /*
+- ** Set *pCurrent to the total cache hits or misses encountered by all
+- ** pagers the database handle is connected to. *pHighwater is always set
+- ** to zero.
+- */
+- case SQLITE_DBSTATUS_CACHE_HIT:
+- case SQLITE_DBSTATUS_CACHE_MISS:
+- case SQLITE_DBSTATUS_CACHE_WRITE:{
+- int i;
+- int nRet = 0;
+- assert( SQLITE_DBSTATUS_CACHE_MISS==SQLITE_DBSTATUS_CACHE_HIT+1 );
+- assert( SQLITE_DBSTATUS_CACHE_WRITE==SQLITE_DBSTATUS_CACHE_HIT+2 );
+
+- for(i=0; i<db->nDb; i++){
+- if( db->aDb[i].pBt ){
+- Pager *pPager = sqlite3BtreePager(db->aDb[i].pBt);
+- sqlite3PagerCacheStat(pPager, op, resetFlag, &nRet);
+- }
+static int sqlcipher_check_connection(const char *filename, char *key, int key_sz, char *sql, int
*user_version) {
+ int rc;
+ sqlite3 *db = NULL;
@@ -2988,8 +4154,13 @@
+ rc = sqlite3_exec(db, command, NULL, NULL, NULL);
+ if(rc != SQLITE_OK){
+ break;
-+ }
-+ }
+ }
+- *pHighwater = 0; /* IMP: R-42420-56072 */
+- /* IMP: R-54100-20147 */
+- /* IMP: R-29431-39229 */
+- *pCurrent = nRet;
+- break;
+ }
+ sqlite3_free(attach_command);
+ sqlite3_free(set_user_version);
+ sqlcipher_free(key, key_sz);
@@ -2998,7 +4169,16 @@
+ Btree *pDest;
+ Btree *pSrc;
+ int i = 0;
-+
+
+- /* Set *pCurrent to non-zero if there are unresolved deferred foreign
+- ** key constraints. Set *pCurrent to zero if all foreign key constraints
+- ** have been satisfied. The *pHighwater is always set to zero.
+- */
+- case SQLITE_DBSTATUS_DEFERRED_FKS: {
+- *pHighwater = 0; /* IMP: R-11967-56545 */
+- *pCurrent = db->nDeferredImmCons>0 || db->nDeferredCons>0;
+- break;
+- }
+ if( !db->autoCommit ){
+ CODEC_TRACE(("cannot migrate from within a transaction"));
+ goto handle_error;
@@ -3029,7 +4209,9 @@
+
+ assert( 1==sqlite3BtreeIsInTrans(pDest) );
+ assert( 1==sqlite3BtreeIsInTrans(pSrc) );
-+
+
+- default: {
+- rc = SQLITE_ERROR;
+ sqlite3CodecGetKey(db, db->nDb - 1, (void**)&key, &password_sz);
+ sqlite3CodecAttach(db, 0, key, password_sz);
+ sqlite3pager_get_codec(pDest->pBt->pPager, (void**)&ctx);
@@ -3050,19 +4232,18 @@
+ db->nTotalChange = saved_nTotalChange;
+ db->xTrace = saved_xTrace;
+ db->autoCommit = 1;
-+ if( pDb ){
-+ sqlite3BtreeClose(pDb->pBt);
-+ pDb->pBt = 0;
-+ pDb->pSchema = 0;
-+ }
++ sqlite3BtreeClose(pDb->pBt);
++ pDb->pBt = 0;
++ pDb->pSchema = 0;
+ sqlite3ResetAllSchemasOfConnection(db);
+ remove(migrated_db_filename);
+ sqlite3_free(migrated_db_filename);
+ } else {
+ CODEC_TRACE(("*** migration failure** \n\n"));
-+ }
+ }
+
-+ }
+ }
+- sqlite3_mutex_leave(db->mutex);
+ goto exit;
+
+ handle_error:
@@ -3070,9 +4251,11 @@
+ rc = SQLITE_ERROR;
+
+ exit:
-+ return rc;
-+}
-+
+ return rc;
+ }
+
+-/************** End of status.c **********************************************/
+-/************** Begin file date.c ********************************************/
+int sqlcipher_codec_add_random(codec_ctx *ctx, const char *zRight, int random_sz){
+ const char *suffix = &zRight[random_sz-1];
+ int n = random_sz - 3; /* adjust for leading x' and tailing ' */
@@ -3119,19 +4302,54 @@
+ if( f ) fprintf(f, "Elapsed time:%.3f ms - %s\n", elapsed, sql);
+}
+
++int sqlcipher_codec_fips_status(codec_ctx *ctx) {
++ return ctx->read_ctx->provider->fips_status(ctx->read_ctx);
++}
+
+#endif
+/* END SQLCIPHER */
+
+/************** End of crypto_impl.c *****************************************/
+/************** Begin file crypto_libtomcrypt.c ******************************/
-+/*
+ /*
+-** 2003 October 31
+-**
+-** The author disclaims copyright to this source code. In place of
+-** a legal notice, here is a blessing:
+** SQLCipher
+** http://sqlcipher.net
-+**
+ **
+-** May you do good and not evil.
+-** May you find forgiveness for yourself and forgive others.
+-** May you share freely, never taking more than you give.
+-**
+-*************************************************************************
+-** This file contains the C functions that implement date and time
+-** functions for SQLite.
+-**
+-** There is only one exported symbol in this file - the function
+-** sqlite3RegisterDateTimeFunctions() found at the bottom of the file.
+-** All other code has file scope.
+-**
+-** SQLite processes all times and dates as julian day numbers. The
+-** dates and times are stored as the number of days since noon
+-** in Greenwich on November 24, 4714 B.C. according to the Gregorian
+-** calendar system.
+** Copyright (c) 2008 - 2013, ZETETIC LLC
+** All rights reserved.
-+**
+ **
+-** 1970-01-01 00:00:00 is JD 2440587.5
+-** 2000-01-01 00:00:00 is JD 2451544.5
+-**
+-** This implementation requires years to be expressed as a 4-digit number
+-** which means that only dates between 0000-01-01 and 9999-12-31 can
+-** be represented, even though julian day numbers allow a much wider
+-** range of dates.
+-**
+-** The Gregorian calendar system is used for all dates and times,
+-** even those that predate the Gregorian calendar. Historians usually
+-** use the julian calendar for dates prior to 1582-10-15 and for some
+-** dates afterwards, depending on locale. Beware of this difference.
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+** * Redistributions of source code must retain the above copyright
@@ -3142,7 +4360,9 @@
+** * Neither the name of the ZETETIC LLC nor the
+** names of its contributors may be used to endorse or promote products
+** derived from this software without specific prior written permission.
-+**
+ **
+-** The conversion algorithms are implemented based on descriptions
+-** in the following text:
+** THIS SOFTWARE IS PROVIDED BY ZETETIC LLC ''AS IS'' AND ANY
+** EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -3153,19 +4373,45 @@
+** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+**
-+*/
+ **
+-** Jean Meeus
+-** Astronomical Algorithms, 2nd Edition, 1998
+-** ISBM 0-943396-61-1
+-** Willmann-Bell, Inc
+-** Richmond, Virginia (USA)
+ */
+-/* #include <stdlib.h> */
+-/* #include <assert.h> */
+-#include <time.h>
+-
+-#ifndef SQLITE_OMIT_DATETIME_FUNCS
+-
+/* BEGIN SQLCIPHER */
+#ifdef SQLITE_HAS_CODEC
+#ifdef SQLCIPHER_CRYPTO_LIBTOMCRYPT
+#include <tomcrypt.h>
-+
+
+-/*
+-** A structure for holding a single date and time.
+-*/
+-typedef struct DateTime DateTime;
+-struct DateTime {
+- sqlite3_int64 iJD; /* The julian day number times 86400000 */
+- int Y, M, D; /* Year, month, and day */
+- int h, m; /* Hour and minutes */
+- int tz; /* Timezone offset in minutes */
+- double s; /* Seconds */
+- char validYMD; /* True (1) if Y,M,D are valid */
+- char validHMS; /* True (1) if h,m,s are valid */
+- char validJD; /* True (1) if iJD is valid */
+- char validTZ; /* True (1) if tz is valid */
+-};
+#define FORTUNA_MAX_SZ 32
+static prng_state prng;
+static unsigned int ltc_init = 0;
+static unsigned int ltc_ref_count = 0;
+static sqlite3_mutex* ltc_rand_mutex = NULL;
-+
+
+static int sqlcipher_ltc_add_random(void *ctx, void *buffer, int length) {
+ int rc = 0;
+ int data_to_read = length;
@@ -3190,7 +4436,46 @@
+#endif
+ return rc;
+}
-+
+
+-/*
+-** Convert zDate into one or more integers. Additional arguments
+-** come in groups of 5 as follows:
+-**
+-** N number of digits in the integer
+-** min minimum allowed value of the integer
+-** max maximum allowed value of the integer
+-** nextC first character after the integer
+-** pVal where to write the integers value.
+-**
+-** Conversions continue until one with nextC==0 is encountered.
+-** The function returns the number of successful conversions.
+-*/
+-static int getDigits(const char *zDate, ...){
+- va_list ap;
+- int val;
+- int N;
+- int min;
+- int max;
+- int nextC;
+- int *pVal;
+- int cnt = 0;
+- va_start(ap, zDate);
+- do{
+- N = va_arg(ap, int);
+- min = va_arg(ap, int);
+- max = va_arg(ap, int);
+- nextC = va_arg(ap, int);
+- pVal = va_arg(ap, int*);
+- val = 0;
+- while( N-- ){
+- if( !sqlite3Isdigit(*zDate) ){
+- goto end_getDigits;
+- }
+- val = val*10 + *zDate - '0';
+- zDate++;
+- }
+- if( val<min || val>max || (nextC!=0 && nextC!=*zDate) ){
+- goto end_getDigits;
+static int sqlcipher_ltc_activate(void *ctx) {
+ unsigned char random_buffer[FORTUNA_MAX_SZ];
+#ifndef SQLCIPHER_LTC_NO_MUTEX_RAND
@@ -3206,7 +4491,14 @@
+ if(register_hash(&sha1_desc) != CRYPT_OK) return SQLITE_ERROR;
+ if(fortuna_start(&prng) != CRYPT_OK) {
+ return SQLITE_ERROR;
-+ }
+ }
+- *pVal = val;
+- zDate++;
+- cnt++;
+- }while( nextC );
+-end_getDigits:
+- va_end(ap);
+- return cnt;
+ ltc_init = 1;
+ }
+ ltc_ref_count++;
@@ -3221,8 +4513,44 @@
+ }
+ sqlcipher_memset(random_buffer, 0, FORTUNA_MAX_SZ);
+ return SQLITE_OK;
-+}
-+
+ }
+
+-/*
+-** Parse a timezone extension on the end of a date-time.
+-** The extension is of the form:
+-**
+-** (+/-)HH:MM
+-**
+-** Or the "zulu" notation:
+-**
+-** Z
+-**
+-** If the parse is successful, write the number of minutes
+-** of change in p->tz and return 0. If a parser error occurs,
+-** return non-zero.
+-**
+-** A missing specifier is not considered an error.
+-*/
+-static int parseTimezone(const char *zDate, DateTime *p){
+- int sgn = 0;
+- int nHr, nMn;
+- int c;
+- while( sqlite3Isspace(*zDate) ){ zDate++; }
+- p->tz = 0;
+- c = *zDate;
+- if( c=='-' ){
+- sgn = -1;
+- }else if( c=='+' ){
+- sgn = +1;
+- }else if( c=='Z' || c=='z' ){
+- zDate++;
+- goto zulu_time;
+- }else{
+- return c!=0;
+- }
+- zDate++;
+- if( getDigits(zDate, 2, 0, 14, ':', &nHr, 2, 0, 59, 0, &nMn)!=2 ){
+- return 1;
+static int sqlcipher_ltc_deactivate(void *ctx) {
+#ifndef SQLCIPHER_LTC_NO_MUTEX_RAND
+ sqlite3_mutex_enter(ltc_rand_mutex);
@@ -3240,11 +4568,28 @@
+#ifndef SQLCIPHER_LTC_NO_MUTEX_RAND
+ else {
+ sqlite3_mutex_leave(ltc_rand_mutex);
-+ }
+ }
+- zDate += 5;
+- p->tz = sgn*(nMn + nHr*60);
+-zulu_time:
+- while( sqlite3Isspace(*zDate) ){ zDate++; }
+- return *zDate!=0;
+#endif
+ return SQLITE_OK;
-+}
-+
+ }
+
+-/*
+-** Parse times of the form HH:MM or HH:MM:SS or HH:MM:SS.FFFF.
+-** The HH, MM, and SS must each be exactly 2 digits. The
+-** fractional seconds FFFF can be one or more digits.
+-**
+-** Return 1 if there is a parsing error and 0 on success.
+-*/
+-static int parseHhMmSs(const char *zDate, DateTime *p){
+- int h, m, s;
+- double ms = 0.0;
+- if( getDigits(zDate, 2, 0, 24, ':', &h, 2, 0, 59, 0, &m)!=2 ){
+- return 1;
+static const char* sqlcipher_ltc_get_provider_name(void *ctx) {
+ return "libtomcrypt";
+}
@@ -3284,11 +4629,37 @@
+ if((rc = pkcs_5_alg2(pass, pass_sz, salt, salt_sz,
+ workfactor, hash_idx, key, &outlen)) != CRYPT_OK) {
+ return SQLITE_ERROR;
-+ }
+ }
+- zDate += 5;
+- if( *zDate==':' ){
+- zDate++;
+- if( getDigits(zDate, 2, 0, 59, 0, &s)!=1 ){
+- return 1;
+- }
+- zDate += 2;
+- if( *zDate=='.' && sqlite3Isdigit(zDate[1]) ){
+- double rScale = 1.0;
+- zDate++;
+- while( sqlite3Isdigit(*zDate) ){
+- ms = ms*10.0 + *zDate - '0';
+- rScale *= 10.0;
+- zDate++;
+- }
+- ms /= rScale;
+- }
+- }else{
+- s = 0;
+ if((rc = pkcs_5_alg2(key, key_sz, salt, salt_sz,
+ 1, hash_idx, random_buffer, &random_buffer_sz)) != CRYPT_OK) {
+ return SQLITE_ERROR;
-+ }
+ }
+- p->validJD = 0;
+- p->validHMS = 1;
+- p->h = h;
+- p->m = m;
+- p->s = s + ms;
+- if( parseTimezone(zDate, p) ) return 1;
+- p->validTZ = (p->tz!=0)?1:0;
+ sqlcipher_ltc_add_random(ctx, random_buffer, random_buffer_sz);
+ sqlcipher_free(random_buffer, random_buffer_sz);
+ return SQLITE_OK;
@@ -3352,6 +4723,10 @@
+ return SQLITE_OK;
+}
+
++static int sqlcipher_ltc_fips_status(void *ctx) {
+ return 0;
+ }
+
+int sqlcipher_ltc_setup(sqlcipher_provider *p) {
+ p->activate = sqlcipher_ltc_activate;
+ p->deactivate = sqlcipher_ltc_deactivate;
@@ -3371,6 +4746,7 @@
+ p->ctx_init = sqlcipher_ltc_ctx_init;
+ p->ctx_free = sqlcipher_ltc_ctx_free;
+ p->add_random = sqlcipher_ltc_add_random;
++ p->fips_status = sqlcipher_ltc_fips_status;
+ return SQLITE_OK;
+}
+
@@ -3380,7 +4756,9 @@
+
+/************** End of crypto_libtomcrypt.c **********************************/
+/************** Begin file crypto_openssl.c **********************************/
-+/*
+ /*
+-** Convert from YYYY-MM-DD HH:MM:SS to julian day. We always assume
+-** that the YYYY-MM-DD is according to the Gregorian calendar.
+** SQLCipher
+** http://sqlcipher.net
+**
@@ -3408,8 +4786,11 @@
+** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+**
-+*/
+ **
+-** Reference: Meeus page 61
+ */
+-static void computeJD(DateTime *p){
+- int Y, M, D, A, B, X1, X2;
+/* BEGIN SQLCIPHER */
+#ifdef SQLITE_HAS_CODEC
+#ifdef SQLCIPHER_CRYPTO_OPENSSL
@@ -3421,7 +4802,6 @@
+ EVP_CIPHER *evp_cipher;
+} openssl_ctx;
+
-+
+static unsigned int openssl_external_init = 0;
+static unsigned int openssl_init_count = 0;
+static sqlite3_mutex* openssl_rand_mutex = NULL;
@@ -3436,7 +4816,20 @@
+#endif
+ return SQLITE_OK;
+}
-+
+
+- if( p->validJD ) return;
+- if( p->validYMD ){
+- Y = p->Y;
+- M = p->M;
+- D = p->D;
+- }else{
+- Y = 2000; /* If no YMD specified, assume 2000-Jan-01 */
+- M = 1;
+- D = 1;
+- }
+- if( M<=2 ){
+- Y--;
+- M += 12;
+/* activate and initialize sqlcipher. Most importantly, this will automatically
+ intialize OpenSSL's EVP system if it hasn't already be externally. Note that
+ this function may be called multiple times as new codecs are intiialized.
@@ -3454,18 +4847,71 @@
+ a call to get_cipherbyname works, then the openssl library
+ has been initialized externally already. */
+ openssl_external_init = 1;
-+ }
-+
+ }
+- A = Y/100;
+- B = 2 - A + (A/4);
+- X1 = 36525*(Y+4716)/100;
+- X2 = 306001*(M+1)/10000;
+- p->iJD = (sqlite3_int64)((X1 + X2 + D + B - 1524.5 ) * 86400000);
+- p->validJD = 1;
+- if( p->validHMS ){
+- p->iJD += p->h*3600000 + p->m*60000 + (sqlite3_int64)(p->s*1000);
+- if( p->validTZ ){
+- p->iJD -= p->tz*60000;
+- p->validYMD = 0;
+- p->validHMS = 0;
+- p->validTZ = 0;
++
++#ifdef SQLCIPHER_FIPS
++ if(!FIPS_mode()){
++ if(!FIPS_mode_set(1)){
++ ERR_load_crypto_strings();
++ ERR_print_errors_fp(stderr);
+ }
+ }
+-}
++#endif
+
+-/*
+-** Parse dates of the form
+-**
+-** YYYY-MM-DD HH:MM:SS.FFF
+-** YYYY-MM-DD HH:MM:SS
+-** YYYY-MM-DD HH:MM
+-** YYYY-MM-DD
+-**
+-** Write the result into the DateTime structure and return 0
+-** on success and 1 if the input string is not a well-formed
+-** date.
+-*/
+-static int parseYyyyMmDd(const char *zDate, DateTime *p){
+- int Y, M, D, neg;
+ if(openssl_init_count == 0 && openssl_external_init == 0) {
+ /* if the library was not externally initialized, then should be now */
+ OpenSSL_add_all_algorithms();
+ }
-+
+
+- if( zDate[0]=='-' ){
+- zDate++;
+- neg = 1;
+- }else{
+- neg = 0;
+- }
+- if( getDigits(zDate,4,0,9999,'-',&Y,2,1,12,'-',&M,2,1,31,0,&D)!=3 ){
+- return 1;
+#ifndef SQLCIPHER_OPENSSL_NO_MUTEX_RAND
+ if(openssl_rand_mutex == NULL) {
+ /* allocate a mutex to guard against concurrent calls to RAND_bytes() */
+ openssl_rand_mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
-+ }
+ }
+- zDate += 10;
+- while( sqlite3Isspace(*zDate) || 'T'==*(u8*)zDate ){ zDate++; }
+- if( parseHhMmSs(zDate, p)==0 ){
+- /* We got the time */
+- }else if( *zDate==0 ){
+- p->validHMS = 0;
+- }else{
+- return 1;
+#endif
+
+ openssl_init_count++;
@@ -3493,7 +4939,14 @@
+ sqlite3_mutex_free(openssl_rand_mutex);
+ openssl_rand_mutex = NULL;
+#endif
-+ }
+ }
+- p->validJD = 0;
+- p->validYMD = 1;
+- p->Y = neg ? -Y : Y;
+- p->M = M;
+- p->D = D;
+- if( p->validTZ ){
+- computeJD(p);
+ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+ return SQLITE_OK;
+}
@@ -3557,8 +5010,11 @@
+
+static int sqlcipher_openssl_set_cipher(void *ctx, const char *cipher_name) {
+ openssl_ctx *o_ctx = (openssl_ctx *)ctx;
-+ o_ctx->evp_cipher = (EVP_CIPHER *) EVP_get_cipherbyname(cipher_name);
-+ return SQLITE_OK;
++ EVP_CIPHER* cipher = (EVP_CIPHER *) EVP_get_cipherbyname(cipher_name);
++ if(cipher != NULL) {
++ o_ctx->evp_cipher = cipher;
+ }
++ return cipher != NULL ? SQLITE_OK : SQLITE_ERROR;
+}
+
+static const char* sqlcipher_openssl_get_cipher(void *ctx) {
@@ -3603,6 +5059,27 @@
+ return SQLITE_OK;
+}
+
++static int sqlcipher_openssl_fips_status(void *ctx) {
++#ifdef SQLCIPHER_FIPS
++ return FIPS_mode();
++#else
+ return 0;
++#endif
+ }
+
+-/*
+-** Set the time to the current time reported by the VFS.
+-**
+-** Return the number of errors.
+-*/
+-static int setDateTimeToCurrent(sqlite3_context *context, DateTime *p){
+- p->iJD = sqlite3StmtCurrentTime(context);
+- if( p->iJD>0 ){
+- p->validJD = 1;
+- return 0;
+- }else{
+- return 1;
+- }
+int sqlcipher_openssl_setup(sqlcipher_provider *p) {
+ p->activate = sqlcipher_openssl_activate;
+ p->deactivate = sqlcipher_openssl_deactivate;
@@ -3622,19 +5099,27 @@
+ p->ctx_init = sqlcipher_openssl_ctx_init;
+ p->ctx_free = sqlcipher_openssl_ctx_free;
+ p->add_random = sqlcipher_openssl_add_random;
++ p->fips_status = sqlcipher_openssl_fips_status;
+ return SQLITE_OK;
-+}
-+
+ }
+
+#endif
+#endif
+/* END SQLCIPHER */
+
+/************** End of crypto_openssl.c **************************************/
+/************** Begin file crypto_cc.c ***************************************/
-+/*
+ /*
+-** Attempt to parse the given string into a julian day number. Return
+-** the number of errors.
+-**
+-** The following are acceptable forms for the input string:
+** SQLCipher
+** http://sqlcipher.net
-+**
+ **
+-** YYYY-MM-DD HH:MM:SS.FFF +/-HH:MM
+-** DDDD.DD
+-** now
+** Copyright (c) 2008 - 2013, ZETETIC LLC
+** All rights reserved.
+**
@@ -3659,8 +5144,31 @@
+** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+**
-+*/
+ **
+-** In the first form, the +/-HH:MM is always optional. The fractional
+-** seconds extension (the ".FFF") is optional. The seconds portion
+-** (":SS.FFF") is option. The year and date can be omitted as long
+-** as there is a time string. The time string can be omitted as long
+-** as there is a year and date.
+ */
+-static int parseDateOrTime(
+- sqlite3_context *context,
+- const char *zDate,
+- DateTime *p
+-){
+- double r;
+- if( parseYyyyMmDd(zDate,p)==0 ){
+- return 0;
+- }else if( parseHhMmSs(zDate, p)==0 ){
+- return 0;
+- }else if( sqlite3StrICmp(zDate,"now")==0){
+- return setDateTimeToCurrent(context, p);
+- }else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8) ){
+- p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5);
+- p->validJD = 1;
+- return 0;
+- }
+- return 1;
+/* BEGIN SQLCIPHER */
+#ifdef SQLITE_HAS_CODEC
+#ifdef SQLCIPHER_CRYPTO_CC
@@ -3669,17 +5177,63 @@
+
+static int sqlcipher_cc_add_random(void *ctx, void *buffer, int length) {
+ return SQLITE_OK;
-+}
-+
+ }
+
+-/*
+-** Compute the Year, Month, and Day from the julian day number.
+-*/
+-static void computeYMD(DateTime *p){
+- int Z, A, B, C, D, E, X1;
+- if( p->validYMD ) return;
+- if( !p->validJD ){
+- p->Y = 2000;
+- p->M = 1;
+- p->D = 1;
+- }else{
+- Z = (int)((p->iJD + 43200000)/86400000);
+- A = (int)((Z - 1867216.25)/36524.25);
+- A = Z + 1 + A - (A/4);
+- B = A + 1524;
+- C = (int)((B - 122.1)/365.25);
+- D = (36525*C)/100;
+- E = (int)((B-D)/30.6001);
+- X1 = (int)(30.6001*E);
+- p->D = B - D - X1;
+- p->M = E<14 ? E-1 : E-13;
+- p->Y = p->M>2 ? C - 4716 : C - 4715;
+- }
+- p->validYMD = 1;
+/* generate a defined number of random bytes */
+static int sqlcipher_cc_random (void *ctx, void *buffer, int length) {
+ return (SecRandomCopyBytes(kSecRandomDefault, length, (uint8_t *)buffer) == 0) ? SQLITE_OK : SQLITE_ERROR;
-+}
-+
+ }
+
+-/*
+-** Compute the Hour, Minute, and Seconds from the julian day number.
+-*/
+-static void computeHMS(DateTime *p){
+- int s;
+- if( p->validHMS ) return;
+- computeJD(p);
+- s = (int)((p->iJD + 43200000) % 86400000);
+- p->s = s/1000.0;
+- s = (int)p->s;
+- p->s -= s;
+- p->h = s/3600;
+- s -= p->h*3600;
+- p->m = s/60;
+- p->s += s - p->m*60;
+- p->validHMS = 1;
+static const char* sqlcipher_cc_get_provider_name(void *ctx) {
+ return "commoncrypto";
-+}
-+
+ }
+
+-/*
+-** Compute both YMD and HMS
+-*/
+-static void computeYMD_HMS(DateTime *p){
+- computeYMD(p);
+- computeHMS(p);
+static int sqlcipher_cc_hmac(void *ctx, unsigned char *hmac_key, int key_sz, unsigned char *in, int in_sz,
unsigned char *in2, int in2_sz, unsigned char *out) {
+ CCHmacContext hmac_context;
+ CCHmacInit(&hmac_context, kCCHmacAlgSHA1, hmac_key, key_sz);
@@ -3687,8 +5241,15 @@
+ CCHmacUpdate(&hmac_context, in2, in2_sz);
+ CCHmacFinal(&hmac_context, out);
+ return SQLITE_OK;
-+}
-+
+ }
+
+-/*
+-** Clear the YMD and HMS and the TZ
+-*/
+-static void clearYMD_HMS_TZ(DateTime *p){
+- p->validYMD = 0;
+- p->validHMS = 0;
+- p->validTZ = 0;
+static int sqlcipher_cc_kdf(void *ctx, const unsigned char *pass, int pass_sz, unsigned char* salt, int
salt_sz, int workfactor, int key_sz, unsigned char *key) {
+ CCKeyDerivationPBKDF(kCCPBKDF2, (const char *)pass, pass_sz, salt, salt_sz, kCCPRFHmacAlgSHA1,
workfactor, key, key_sz);
+ return SQLITE_OK;
@@ -3751,6 +5312,10 @@
+ return SQLITE_OK;
+}
+
++static int sqlcipher_cc_fips_status(void *ctx) {
++ return 0;
++}
++
+int sqlcipher_cc_setup(sqlcipher_provider *p) {
+ p->random = sqlcipher_cc_random;
+ p->get_provider_name = sqlcipher_cc_get_provider_name;
@@ -3768,37 +5333,81 @@
+ p->ctx_init = sqlcipher_cc_ctx_init;
+ p->ctx_free = sqlcipher_cc_ctx_free;
+ p->add_random = sqlcipher_cc_add_random;
++ p->fips_status = sqlcipher_cc_fips_status;
+ return SQLITE_OK;
-+}
-+
+ }
+
+#endif
+#endif
+/* END SQLCIPHER */
+
+/************** End of crypto_cc.c *******************************************/
+/************** Begin file global.c ******************************************/
-+/*
+ /*
+-** On recent Windows platforms, the localtime_s() function is available
+-** as part of the "Secure CRT". It is essentially equivalent to
+-** localtime_r() available under most POSIX platforms, except that the
+-** order of the parameters is reversed.
+** 2008 June 13
-+**
+ **
+-** See http://msdn.microsoft.com/en-us/library/a442x3ye(VS.80).aspx.
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
-+**
+ **
+-** If the user has not indicated to use localtime_r() or localtime_s()
+-** already, check for an MSVC build environment that provides
+-** localtime_s().
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+**
-+** This file contains definitions of global variables and contants.
-+*/
-+
++** This file contains definitions of global variables and constants.
+ */
+-#if !HAVE_LOCALTIME_R && !HAVE_LOCALTIME_S \
+- && defined(_MSC_VER) && defined(_CRT_INSECURE_DEPRECATE)
+-#undef HAVE_LOCALTIME_S
+-#define HAVE_LOCALTIME_S 1
+-#endif
+
+-#ifndef SQLITE_OMIT_LOCALTIME
+-/*
+-** The following routine implements the rough equivalent of localtime_r()
+-** using whatever operating-system specific localtime facility that
+-** is available. This routine returns 0 on success and
+-** non-zero on any kind of error.
+-**
+-** If the sqlite3GlobalConfig.bLocaltimeFault variable is true then this
+-** routine will always fail.
+/* An array to map all upper-case characters into their corresponding
+** lower-case character.
-+**
+ **
+-** EVIDENCE-OF: R-62172-00036 In this implementation, the standard C
+-** library function localtime_r() is used to assist in the calculation of
+-** local time.
+** SQLite only considers US-ASCII (or EBCDIC) characters. We do not
+** handle case conversions for the UTF character set since the tables
+** involved are nearly as big or bigger than SQLite itself.
-+*/
+ */
+-static int osLocaltime(time_t *t, struct tm *pTm){
+- int rc;
+-#if !HAVE_LOCALTIME_R && !HAVE_LOCALTIME_S
+- struct tm *pX;
+-#if SQLITE_THREADSAFE>0
+- sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
+-#endif
+- sqlite3_mutex_enter(mutex);
+- pX = localtime(t);
+-#ifndef SQLITE_OMIT_BUILTIN_TEST
+- if( sqlite3GlobalConfig.bLocaltimeFault ) pX = 0;
+-#endif
+- if( pX ) *pTm = *pX;
+- sqlite3_mutex_leave(mutex);
+- rc = pX==0;
+-#else
+-#ifndef SQLITE_OMIT_BUILTIN_TEST
+- if( sqlite3GlobalConfig.bLocaltimeFault ) return 1;
+SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[] = {
+#ifdef SQLITE_ASCII
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
@@ -3816,7 +5425,17 @@
+ 216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,
+ 234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,
+ 252,253,254,255
-+#endif
+ #endif
+-#if HAVE_LOCALTIME_R
+- rc = localtime_r(t, pTm)==0;
+-#else
+- rc = localtime_s(pTm, t);
+-#endif /* HAVE_LOCALTIME_R */
+-#endif /* HAVE_LOCALTIME_R || HAVE_LOCALTIME_S */
+- return rc;
+-}
+-#endif /* SQLITE_OMIT_LOCALTIME */
+-
+#ifdef SQLITE_EBCDIC
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 0x */
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 1x */
@@ -3824,23 +5443,29 @@
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 3x */
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, /* 4x */
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, /* 5x */
-+ 96, 97, 66, 67, 68, 69, 70, 71, 72, 73,106,107,108,109,110,111, /* 6x */
-+ 112, 81, 82, 83, 84, 85, 86, 87, 88, 89,122,123,124,125,126,127, /* 7x */
++ 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, /* 6x */
++ 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, /* 7x */
+ 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, /* 8x */
-+ 144,145,146,147,148,149,150,151,152,153,154,155,156,157,156,159, /* 9x */
++ 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, /* 9x */
+ 160,161,162,163,164,165,166,167,168,169,170,171,140,141,142,175, /* Ax */
+ 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, /* Bx */
+ 192,129,130,131,132,133,134,135,136,137,202,203,204,205,206,207, /* Cx */
+ 208,145,146,147,148,149,150,151,152,153,218,219,220,221,222,223, /* Dx */
-+ 224,225,162,163,164,165,166,167,168,169,232,203,204,205,206,207, /* Ex */
-+ 239,240,241,242,243,244,245,246,247,248,249,219,220,221,222,255, /* Fx */
++ 224,225,162,163,164,165,166,167,168,169,234,235,236,237,238,239, /* Ex */
++ 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, /* Fx */
+#endif
+};
-+
-+/*
+
+-#ifndef SQLITE_OMIT_LOCALTIME
+ /*
+-** Compute the difference (in milliseconds) between localtime and UTC
+-** (a.k.a. GMT) for the time value p where p is in UTC. If no error occurs,
+-** return this value and set *pRc to SQLITE_OK.
+** The following 256 byte lookup table is used to support SQLites built-in
+** equivalents to the following standard library functions:
-+**
+ **
+-** Or, if an error does occur, set *pRc to SQLITE_ERROR. The returned value
+-** is undefined in this case.
+** isspace() 0x01
+** isalpha() 0x02
+** isdigit() 0x04
@@ -3866,7 +5491,15 @@
+**
+** SQLite's versions are identical to the standard versions assuming a
+** locale of "C". They are implemented as macros in sqliteInt.h.
-+*/
+ */
+-static sqlite3_int64 localtimeOffset(
+- DateTime *p, /* Date at which to calculate offset */
+- sqlite3_context *pCtx, /* Write error here if one occurs */
+- int *pRc /* OUT: Error code. SQLITE_OK or ERROR */
+-){
+- DateTime x, y;
+- time_t t;
+- struct tm sLocal;
+#ifdef SQLITE_ASCII
+SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00..07 ........ */
@@ -3877,7 +5510,9 @@
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 28..2f ()*+,-./ */
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, /* 30..37 01234567 */
+ 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 38..3f 89:;<=>? */
-+
+
+- /* Initialize the contents of sLocal to avoid a compiler warning. */
+- memset(&sLocal, 0, sizeof(sLocal));
+ 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x02, /* 40..47 @ABCDEFG */
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 48..4f HIJKLMNO */
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 50..57 PQRSTUVW */
@@ -3886,7 +5521,49 @@
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* 68..6f hijklmno */
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* 70..77 pqrstuvw */
+ 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, /* 78..7f xyz{|}~. */
-+
+
+- x = *p;
+- computeYMD_HMS(&x);
+- if( x.Y<1971 || x.Y>=2038 ){
+- /* EVIDENCE-OF: R-55269-29598 The localtime_r() C function normally only
+- ** works for years between 1970 and 2037. For dates outside this range,
+- ** SQLite attempts to map the year into an equivalent year within this
+- ** range, do the calculation, then map the year back.
+- */
+- x.Y = 2000;
+- x.M = 1;
+- x.D = 1;
+- x.h = 0;
+- x.m = 0;
+- x.s = 0.0;
+- } else {
+- int s = (int)(x.s + 0.5);
+- x.s = s;
+- }
+- x.tz = 0;
+- x.validJD = 0;
+- computeJD(&x);
+- t = (time_t)(x.iJD/1000 - 21086676*(i64)10000);
+- if( osLocaltime(&t, &sLocal) ){
+- sqlite3_result_error(pCtx, "local time unavailable", -1);
+- *pRc = SQLITE_ERROR;
+- return 0;
+- }
+- y.Y = sLocal.tm_year + 1900;
+- y.M = sLocal.tm_mon + 1;
+- y.D = sLocal.tm_mday;
+- y.h = sLocal.tm_hour;
+- y.m = sLocal.tm_min;
+- y.s = sLocal.tm_sec;
+- y.validYMD = 1;
+- y.validHMS = 1;
+- y.validJD = 0;
+- y.validTZ = 0;
+- computeJD(&y);
+- *pRc = SQLITE_OK;
+- return y.iJD - x.iJD;
+-}
+-#endif /* SQLITE_OMIT_LOCALTIME */
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 80..87 ........ */
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 88..8f ........ */
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 90..97 ........ */
@@ -3895,7 +5572,10 @@
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* a8..af ........ */
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* b0..b7 ........ */
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* b8..bf ........ */
-+
+
+-/*
+-** Process a modifier to a date-time stamp. The modifiers are
+-** as follows:
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* c0..c7 ........ */
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* c8..cf ........ */
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* d0..d7 ........ */
@@ -3907,14 +5587,284 @@
+};
+#endif
+
++/* EVIDENCE-OF: R-02982-34736 In order to maintain full backwards
++** compatibility for legacy applications, the URI filename capability is
++** disabled by default.
+ **
+-** NNN days
+-** NNN hours
+-** NNN minutes
+-** NNN.NNNN seconds
+-** NNN months
+-** NNN years
+-** start of month
+-** start of year
+-** start of week
+-** start of day
+-** weekday N
+-** unixepoch
+-** localtime
+-** utc
++** EVIDENCE-OF: R-38799-08373 URI filenames can be enabled or disabled
++** using the SQLITE_USE_URI=1 or SQLITE_USE_URI=0 compile-time options.
+ **
+-** Return 0 on success and 1 if there is any kind of error. If the error
+-** is in a system call (i.e. localtime()), then an error message is written
+-** to context pCtx. If the error is an unrecognized modifier, no error is
+-** written to pCtx.
++** EVIDENCE-OF: R-43642-56306 By default, URI handling is globally
++** disabled. The default value may be changed by compiling with the
++** SQLITE_USE_URI symbol defined.
+ */
+-static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
+- int rc = 1;
+- int n;
+- double r;
+- char *z, zBuf[30];
+- z = zBuf;
+- for(n=0; n<ArraySize(zBuf)-1 && zMod[n]; n++){
+- z[n] = (char)sqlite3UpperToLower[(u8)zMod[n]];
+- }
+- z[n] = 0;
+- switch( z[0] ){
+-#ifndef SQLITE_OMIT_LOCALTIME
+- case 'l': {
+- /* localtime
+- **
+- ** Assuming the current time value is UTC (a.k.a. GMT), shift it to
+- ** show local time.
+- */
+- if( strcmp(z, "localtime")==0 ){
+- computeJD(p);
+- p->iJD += localtimeOffset(p, pCtx, &rc);
+- clearYMD_HMS_TZ(p);
+- }
+- break;
+- }
+#ifndef SQLITE_USE_URI
+# define SQLITE_USE_URI 0
-+#endif
+ #endif
+- case 'u': {
+- /*
+- ** unixepoch
+- **
+- ** Treat the current value of p->iJD as the number of
+- ** seconds since 1970. Convert to a real julian day number.
+- */
+- if( strcmp(z, "unixepoch")==0 && p->validJD ){
+- p->iJD = (p->iJD + 43200)/86400 + 21086676*(i64)10000000;
+- clearYMD_HMS_TZ(p);
+- rc = 0;
+- }
+-#ifndef SQLITE_OMIT_LOCALTIME
+- else if( strcmp(z, "utc")==0 ){
+- sqlite3_int64 c1;
+- computeJD(p);
+- c1 = localtimeOffset(p, pCtx, &rc);
+- if( rc==SQLITE_OK ){
+- p->iJD -= c1;
+- clearYMD_HMS_TZ(p);
+- p->iJD += c1 - localtimeOffset(p, pCtx, &rc);
+- }
+- }
+
++/* EVIDENCE-OF: R-38720-18127 The default setting is determined by the
++** SQLITE_ALLOW_COVERING_INDEX_SCAN compile-time option, or is "on" if
++** that compile-time option is omitted.
++*/
+#ifndef SQLITE_ALLOW_COVERING_INDEX_SCAN
+# define SQLITE_ALLOW_COVERING_INDEX_SCAN 1
+ #endif
+- break;
+- }
+- case 'w': {
+- /*
+- ** weekday N
+- **
+- ** Move the date to the same time on the next occurrence of
+- ** weekday N where 0==Sunday, 1==Monday, and so forth. If the
+- ** date is already on the appropriate weekday, this is a no-op.
+- */
+- if( strncmp(z, "weekday ", 8)==0
+- && sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8)
+- && (n=(int)r)==r && n>=0 && r<7 ){
+- sqlite3_int64 Z;
+- computeYMD_HMS(p);
+- p->validTZ = 0;
+- p->validJD = 0;
+- computeJD(p);
+- Z = ((p->iJD + 129600000)/86400000) % 7;
+- if( Z>n ) Z -= 7;
+- p->iJD += (n - Z)*86400000;
+- clearYMD_HMS_TZ(p);
+- rc = 0;
+- }
+- break;
+- }
+- case 's': {
+- /*
+- ** start of TTTTT
+- **
+- ** Move the date backwards to the beginning of the current day,
+- ** or month or year.
+- */
+- if( strncmp(z, "start of ", 9)!=0 ) break;
+- z += 9;
+- computeYMD(p);
+- p->validHMS = 1;
+- p->h = p->m = 0;
+- p->s = 0.0;
+- p->validTZ = 0;
+- p->validJD = 0;
+- if( strcmp(z,"month")==0 ){
+- p->D = 1;
+- rc = 0;
+- }else if( strcmp(z,"year")==0 ){
+- computeYMD(p);
+- p->M = 1;
+- p->D = 1;
+- rc = 0;
+- }else if( strcmp(z,"day")==0 ){
+- rc = 0;
+- }
+- break;
+- }
+- case '+':
+- case '-':
+- case '0':
+- case '1':
+- case '2':
+- case '3':
+- case '4':
+- case '5':
+- case '6':
+- case '7':
+- case '8':
+- case '9': {
+- double rRounder;
+- for(n=1; z[n] && z[n]!=':' && !sqlite3Isspace(z[n]); n++){}
+- if( !sqlite3AtoF(z, &r, n, SQLITE_UTF8) ){
+- rc = 1;
+- break;
+- }
+- if( z[n]==':' ){
+- /* A modifier of the form (+|-)HH:MM:SS.FFF adds (or subtracts) the
+- ** specified number of hours, minutes, seconds, and fractional seconds
+- ** to the time. The ".FFF" may be omitted. The ":SS.FFF" may be
+- ** omitted.
+- */
+- const char *z2 = z;
+- DateTime tx;
+- sqlite3_int64 day;
+- if( !sqlite3Isdigit(*z2) ) z2++;
+- memset(&tx, 0, sizeof(tx));
+- if( parseHhMmSs(z2, &tx) ) break;
+- computeJD(&tx);
+- tx.iJD -= 43200000;
+- day = tx.iJD/86400000;
+- tx.iJD -= day*86400000;
+- if( z[0]=='-' ) tx.iJD = -tx.iJD;
+- computeJD(p);
+- clearYMD_HMS_TZ(p);
+- p->iJD += tx.iJD;
+- rc = 0;
+- break;
+- }
+- z += n;
+- while( sqlite3Isspace(*z) ) z++;
+- n = sqlite3Strlen30(z);
+- if( n>10 || n<3 ) break;
+- if( z[n-1]=='s' ){ z[n-1] = 0; n--; }
+- computeJD(p);
+- rc = 0;
+- rRounder = r<0 ? -0.5 : +0.5;
+- if( n==3 && strcmp(z,"day")==0 ){
+- p->iJD += (sqlite3_int64)(r*86400000.0 + rRounder);
+- }else if( n==4 && strcmp(z,"hour")==0 ){
+- p->iJD += (sqlite3_int64)(r*(86400000.0/24.0) + rRounder);
+- }else if( n==6 && strcmp(z,"minute")==0 ){
+- p->iJD += (sqlite3_int64)(r*(86400000.0/(24.0*60.0)) + rRounder);
+- }else if( n==6 && strcmp(z,"second")==0 ){
+- p->iJD += (sqlite3_int64)(r*(86400000.0/(24.0*60.0*60.0)) + rRounder);
+- }else if( n==5 && strcmp(z,"month")==0 ){
+- int x, y;
+- computeYMD_HMS(p);
+- p->M += (int)r;
+- x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
+- p->Y += x;
+- p->M -= x*12;
+- p->validJD = 0;
+- computeJD(p);
+- y = (int)r;
+- if( y!=r ){
+- p->iJD += (sqlite3_int64)((r - y)*30.0*86400000.0 + rRounder);
+- }
+- }else if( n==4 && strcmp(z,"year")==0 ){
+- int y = (int)r;
+- computeYMD_HMS(p);
+- p->Y += y;
+- p->validJD = 0;
+- computeJD(p);
+- if( y!=r ){
+- p->iJD += (sqlite3_int64)((r - y)*365.0*86400000.0 + rRounder);
+- }
+- }else{
+- rc = 1;
+- }
+- clearYMD_HMS_TZ(p);
+- break;
+- }
+- default: {
+- break;
+- }
+- }
+- return rc;
+-}
+
+-/*
+-** Process time function arguments. argv[0] is a date-time stamp.
+-** argv[1] and following are modifiers. Parse them all and write
+-** the resulting time into the DateTime structure p. Return 0
+-** on success and 1 if there are any errors.
+-**
+-** If there are zero parameters (if even argv[0] is undefined)
+-** then assume a default value of "now" for argv[0].
++/* The minimum PMA size is set to this value multiplied by the database
++** page size in bytes.
+ */
+-static int isDate(
+- sqlite3_context *context,
+- int argc,
+- sqlite3_value **argv,
+- DateTime *p
+-){
+- int i;
+- const unsigned char *z;
+- int eType;
+- memset(p, 0, sizeof(*p));
+- if( argc==0 ){
+- return setDateTimeToCurrent(context, p);
+- }
+- if( (eType = sqlite3_value_type(argv[0]))==SQLITE_FLOAT
+- || eType==SQLITE_INTEGER ){
+- p->iJD = (sqlite3_int64)(sqlite3_value_double(argv[0])*86400000.0 + 0.5);
+- p->validJD = 1;
+- }else{
+- z = sqlite3_value_text(argv[0]);
+- if( !z || parseDateOrTime(context, (char*)z, p) ){
+- return 1;
+- }
+- }
+- for(i=1; i<argc; i++){
+- z = sqlite3_value_text(argv[i]);
+- if( z==0 || parseModifier(context, (char*)z, p) ) return 1;
+- }
+- return 0;
+-}
++#ifndef SQLITE_SORTER_PMASZ
++# define SQLITE_SORTER_PMASZ 250
+#endif
-+
+
+/*
+** The following singleton contains the global configuration for
+** the SQLite library.
@@ -3945,6 +5895,7 @@
+ 0, /* nPage */
+ 0, /* mxParserStack */
+ 0, /* sharedCacheEnabled */
++ SQLITE_SORTER_PMASZ, /* szPma */
+ /* All the rest should always be initialized to zero */
+ 0, /* isInit */
+ 0, /* inProgress */
@@ -3968,57 +5919,969 @@
+#endif
+ 0 /* bLocaltimeFault */
+};
-+
-+/*
+
+ /*
+-** The following routines implement the various date and time functions
+-** of SQLite.
+** Hash table for global functions - functions common to all
+** database connections. After initialization, this table is
+** read-only.
-+*/
+ */
+SQLITE_PRIVATE SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;
-+
-+/*
+
+ /*
+-** julianday( TIMESTRING, MOD, MOD, ...)
+-**
+-** Return the julian day number of the date specified in the arguments
+** Constant tokens for values 0 and 1.
-+*/
+ */
+-static void juliandayFunc(
+- sqlite3_context *context,
+- int argc,
+- sqlite3_value **argv
+-){
+- DateTime x;
+- if( isDate(context, argc, argv, &x)==0 ){
+- computeJD(&x);
+- sqlite3_result_double(context, x.iJD/86400000.0);
+- }
+-}
+-
+-/*
+-** datetime( TIMESTRING, MOD, MOD, ...)
+-**
+-** Return YYYY-MM-DD HH:MM:SS
+-*/
+-static void datetimeFunc(
+- sqlite3_context *context,
+- int argc,
+- sqlite3_value **argv
+-){
+- DateTime x;
+- if( isDate(context, argc, argv, &x)==0 ){
+- char zBuf[100];
+- computeYMD_HMS(&x);
+- sqlite3_snprintf(sizeof(zBuf), zBuf, "%04d-%02d-%02d %02d:%02d:%02d",
+- x.Y, x.M, x.D, x.h, x.m, (int)(x.s));
+- sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
+- }
+-}
+-
+-/*
+-** time( TIMESTRING, MOD, MOD, ...)
+-**
+-** Return HH:MM:SS
+-*/
+-static void timeFunc(
+- sqlite3_context *context,
+- int argc,
+- sqlite3_value **argv
+-){
+- DateTime x;
+- if( isDate(context, argc, argv, &x)==0 ){
+- char zBuf[100];
+- computeHMS(&x);
+- sqlite3_snprintf(sizeof(zBuf), zBuf, "%02d:%02d:%02d", x.h, x.m, (int)x.s);
+- sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
+- }
+-}
+-
+-/*
+-** date( TIMESTRING, MOD, MOD, ...)
+-**
+-** Return YYYY-MM-DD
+-*/
+-static void dateFunc(
+- sqlite3_context *context,
+- int argc,
+- sqlite3_value **argv
+-){
+- DateTime x;
+- if( isDate(context, argc, argv, &x)==0 ){
+- char zBuf[100];
+- computeYMD(&x);
+- sqlite3_snprintf(sizeof(zBuf), zBuf, "%04d-%02d-%02d", x.Y, x.M, x.D);
+- sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
+- }
+-}
+-
+-/*
+-** strftime( FORMAT, TIMESTRING, MOD, MOD, ...)
+-**
+-** Return a string described by FORMAT. Conversions as follows:
+-**
+-** %d day of month
+-** %f ** fractional seconds SS.SSS
+-** %H hour 00-24
+-** %j day of year 000-366
+-** %J ** julian day number
+-** %m month 01-12
+-** %M minute 00-59
+-** %s seconds since 1970-01-01
+-** %S seconds 00-59
+-** %w day of week 0-6 sunday==0
+-** %W week of year 00-53
+-** %Y year 0000-9999
+-** %% %
+-*/
+-static void strftimeFunc(
+- sqlite3_context *context,
+- int argc,
+- sqlite3_value **argv
+-){
+- DateTime x;
+- u64 n;
+- size_t i,j;
+- char *z;
+- sqlite3 *db;
+- const char *zFmt;
+- char zBuf[100];
+- if( argc==0 ) return;
+- zFmt = (const char*)sqlite3_value_text(argv[0]);
+- if( zFmt==0 || isDate(context, argc-1, argv+1, &x) ) return;
+- db = sqlite3_context_db_handle(context);
+- for(i=0, n=1; zFmt[i]; i++, n++){
+- if( zFmt[i]=='%' ){
+- switch( zFmt[i+1] ){
+- case 'd':
+- case 'H':
+- case 'm':
+- case 'M':
+- case 'S':
+- case 'W':
+- n++;
+- /* fall thru */
+- case 'w':
+- case '%':
+- break;
+- case 'f':
+- n += 8;
+- break;
+- case 'j':
+- n += 3;
+- break;
+- case 'Y':
+- n += 8;
+- break;
+- case 's':
+- case 'J':
+- n += 50;
+- break;
+- default:
+- return; /* ERROR. return a NULL */
+- }
+- i++;
+- }
+- }
+- testcase( n==sizeof(zBuf)-1 );
+- testcase( n==sizeof(zBuf) );
+- testcase( n==(u64)db->aLimit[SQLITE_LIMIT_LENGTH]+1 );
+- testcase( n==(u64)db->aLimit[SQLITE_LIMIT_LENGTH] );
+- if( n<sizeof(zBuf) ){
+- z = zBuf;
+- }else if( n>(u64)db->aLimit[SQLITE_LIMIT_LENGTH] ){
+- sqlite3_result_error_toobig(context);
+- return;
+- }else{
+- z = sqlite3DbMallocRaw(db, (int)n);
+- if( z==0 ){
+- sqlite3_result_error_nomem(context);
+- return;
+- }
+- }
+- computeJD(&x);
+- computeYMD_HMS(&x);
+- for(i=j=0; zFmt[i]; i++){
+- if( zFmt[i]!='%' ){
+- z[j++] = zFmt[i];
+- }else{
+- i++;
+- switch( zFmt[i] ){
+- case 'd': sqlite3_snprintf(3, &z[j],"%02d",x.D); j+=2; break;
+- case 'f': {
+- double s = x.s;
+- if( s>59.999 ) s = 59.999;
+- sqlite3_snprintf(7, &z[j],"%06.3f", s);
+- j += sqlite3Strlen30(&z[j]);
+- break;
+- }
+- case 'H': sqlite3_snprintf(3, &z[j],"%02d",x.h); j+=2; break;
+- case 'W': /* Fall thru */
+- case 'j': {
+- int nDay; /* Number of days since 1st day of year */
+- DateTime y = x;
+- y.validJD = 0;
+- y.M = 1;
+- y.D = 1;
+- computeJD(&y);
+- nDay = (int)((x.iJD-y.iJD+43200000)/86400000);
+- if( zFmt[i]=='W' ){
+- int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */
+- wd = (int)(((x.iJD+43200000)/86400000)%7);
+- sqlite3_snprintf(3, &z[j],"%02d",(nDay+7-wd)/7);
+- j += 2;
+- }else{
+- sqlite3_snprintf(4, &z[j],"%03d",nDay+1);
+- j += 3;
+- }
+- break;
+- }
+- case 'J': {
+- sqlite3_snprintf(20, &z[j],"%.16g",x.iJD/86400000.0);
+- j+=sqlite3Strlen30(&z[j]);
+- break;
+- }
+- case 'm': sqlite3_snprintf(3, &z[j],"%02d",x.M); j+=2; break;
+- case 'M': sqlite3_snprintf(3, &z[j],"%02d",x.m); j+=2; break;
+- case 's': {
+- sqlite3_snprintf(30,&z[j],"%lld",
+- (i64)(x.iJD/1000 - 21086676*(i64)10000));
+- j += sqlite3Strlen30(&z[j]);
+- break;
+- }
+- case 'S': sqlite3_snprintf(3,&z[j],"%02d",(int)x.s); j+=2; break;
+- case 'w': {
+- z[j++] = (char)(((x.iJD+129600000)/86400000) % 7) + '0';
+- break;
+- }
+- case 'Y': {
+- sqlite3_snprintf(5,&z[j],"%04d",x.Y); j+=sqlite3Strlen30(&z[j]);
+- break;
+- }
+- default: z[j++] = '%'; break;
+- }
+- }
+- }
+- z[j] = 0;
+- sqlite3_result_text(context, z, -1,
+- z==zBuf ? SQLITE_TRANSIENT : SQLITE_DYNAMIC);
+-}
+-
+-/*
+-** current_time()
+-**
+-** This function returns the same value as time('now').
+-*/
+-static void ctimeFunc(
+- sqlite3_context *context,
+- int NotUsed,
+- sqlite3_value **NotUsed2
+-){
+- UNUSED_PARAMETER2(NotUsed, NotUsed2);
+- timeFunc(context, 0, 0);
+-}
+SQLITE_PRIVATE const Token sqlite3IntTokens[] = {
+ { "0", 1 },
+ { "1", 1 }
+};
-+
-+
-+/*
+
+-/*
+-** current_date()
+-**
+-** This function returns the same value as date('now').
+-*/
+-static void cdateFunc(
+- sqlite3_context *context,
+- int NotUsed,
+- sqlite3_value **NotUsed2
+-){
+- UNUSED_PARAMETER2(NotUsed, NotUsed2);
+- dateFunc(context, 0, 0);
+-}
+
+ /*
+-** current_timestamp()
+** The value of the "pending" byte must be 0x40000000 (1 byte past the
+** 1-gibabyte boundary) in a compatible database. SQLite never uses
+** the database page that contains the pending byte. It never attempts
+** to read or write that page. The pending byte page is set assign
+** for use by the VFS layers as space for managing file locks.
-+**
+ **
+-** This function returns the same value as datetime('now').
+-*/
+-static void ctimestampFunc(
+- sqlite3_context *context,
+- int NotUsed,
+- sqlite3_value **NotUsed2
+-){
+- UNUSED_PARAMETER2(NotUsed, NotUsed2);
+- datetimeFunc(context, 0, 0);
+-}
+-#endif /* !defined(SQLITE_OMIT_DATETIME_FUNCS) */
+-
+-#ifdef SQLITE_OMIT_DATETIME_FUNCS
+-/*
+-** If the library is compiled to omit the full-scale date and time
+-** handling (to get a smaller binary), the following minimal version
+-** of the functions current_time(), current_date() and current_timestamp()
+-** are included instead. This is to support column declarations that
+-** include "DEFAULT CURRENT_TIME" etc.
+** During testing, it is often desirable to move the pending byte to
+** a different position in the file. This allows code that has to
+** deal with the pending byte to run on files that are much smaller
+** than 1 GiB. The sqlite3_test_control() interface can be used to
+** move the pending byte.
-+**
+ **
+-** This function uses the C-library functions time(), gmtime()
+-** and strftime(). The format string to pass to strftime() is supplied
+-** as the user-data for the function.
+** IMPORTANT: Changing the pending byte to any value other than
+** 0x40000000 results in an incompatible database file format!
-+** Changing the pending byte during operating results in undefined
-+** and dileterious behavior.
-+*/
++** Changing the pending byte during operation will result in undefined
++** and incorrect behavior.
+ */
+-static void currentTimeFunc(
+- sqlite3_context *context,
+- int argc,
+- sqlite3_value **argv
+-){
+- time_t t;
+- char *zFormat = (char *)sqlite3_user_data(context);
+- sqlite3 *db;
+- sqlite3_int64 iT;
+- struct tm *pTm;
+- struct tm sNow;
+- char zBuf[20];
+-
+- UNUSED_PARAMETER(argc);
+- UNUSED_PARAMETER(argv);
+-
+- iT = sqlite3StmtCurrentTime(context);
+- if( iT<=0 ) return;
+- t = iT/1000 - 10000*(sqlite3_int64)21086676;
+-#if HAVE_GMTIME_R
+- pTm = gmtime_r(&t, &sNow);
+-#else
+- sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+- pTm = gmtime(&t);
+- if( pTm ) memcpy(&sNow, pTm, sizeof(sNow));
+- sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+-#endif
+- if( pTm ){
+- strftime(zBuf, 20, zFormat, &sNow);
+- sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
+- }
+-}
+#ifndef SQLITE_OMIT_WSD
+SQLITE_PRIVATE int sqlite3PendingByte = 0x40000000;
-+#endif
-+
-+/*
+ #endif
+
+ /*
+-** This function registered all of the above C functions as SQL
+-** functions. This should be the only routine in this file with
+-** external linkage.
+** Properties of opcodes. The OPFLG_INITIALIZER macro is
+** created by mkopcodeh.awk during compilation. Data is obtained
+** from the comments following the "case OP_xxxx:" statements in
+** the vdbe.c file.
-+*/
+ */
+-SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){
+- static SQLITE_WSD FuncDef aDateTimeFuncs[] = {
+-#ifndef SQLITE_OMIT_DATETIME_FUNCS
+- FUNCTION(julianday, -1, 0, 0, juliandayFunc ),
+- FUNCTION(date, -1, 0, 0, dateFunc ),
+- FUNCTION(time, -1, 0, 0, timeFunc ),
+- FUNCTION(datetime, -1, 0, 0, datetimeFunc ),
+- FUNCTION(strftime, -1, 0, 0, strftimeFunc ),
+- FUNCTION(current_time, 0, 0, 0, ctimeFunc ),
+- FUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc),
+- FUNCTION(current_date, 0, 0, 0, cdateFunc ),
+-#else
+- STR_FUNCTION(current_time, 0, "%H:%M:%S", 0, currentTimeFunc),
+- STR_FUNCTION(current_date, 0, "%Y-%m-%d", 0, currentTimeFunc),
+- STR_FUNCTION(current_timestamp, 0, "%Y-%m-%d %H:%M:%S", 0, currentTimeFunc),
+-#endif
+- };
+- int i;
+- FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
+- FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aDateTimeFuncs);
+-
+- for(i=0; i<ArraySize(aDateTimeFuncs); i++){
+- sqlite3FuncDefInsert(pHash, &aFunc[i]);
+- }
+-}
+SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[] = OPFLG_INITIALIZER;
-+
+
+-/************** End of date.c ************************************************/
+-/************** Begin file os.c **********************************************/
+/************** End of global.c **********************************************/
+/************** Begin file ctime.c *******************************************/
-+/*
+ /*
+-** 2005 November 29
+** 2010 February 23
+ **
+ ** The author disclaims copyright to this source code. In place of
+ ** a legal notice, here is a blessing:
+@@ -16474,157 +17692,2571 @@
+ ** May you find forgiveness for yourself and forgive others.
+ ** May you share freely, never taking more than you give.
+ **
+-******************************************************************************
++*************************************************************************
+ **
+-** This file contains OS interface code that is common to all
+-** architectures.
++** This file implements routines used to report what compile-time options
++** SQLite was built with.
+ */
+-#define _SQLITE_OS_C_ 1
+-#undef _SQLITE_OS_C_
+
+-/*
+-** The default SQLite sqlite3_vfs implementations do not allocate
+-** memory (actually, os_unix.c allocates a small amount of memory
+-** from within OsOpen()), but some third-party implementations may.
+-** So we test the effects of a malloc() failing and the sqlite3OsXXX()
+-** function returning SQLITE_IOERR_NOMEM using the DO_OS_MALLOC_TEST macro.
+-**
+-** The following functions are instrumented for malloc() failure
+-** testing:
+-**
+-** sqlite3OsRead()
+-** sqlite3OsWrite()
+-** sqlite3OsSync()
+-** sqlite3OsFileSize()
+-** sqlite3OsLock()
+-** sqlite3OsCheckReservedLock()
+-** sqlite3OsFileControl()
+-** sqlite3OsShmMap()
+-** sqlite3OsOpen()
+-** sqlite3OsDelete()
+-** sqlite3OsAccess()
+-** sqlite3OsFullPathname()
+-**
+-*/
+-#if defined(SQLITE_TEST)
+-SQLITE_API int sqlite3_memdebug_vfs_oom_test = 1;
+- #define DO_OS_MALLOC_TEST(x) \
+- if (sqlite3_memdebug_vfs_oom_test && (!x || !sqlite3IsMemJournal(x))) { \
+- void *pTstAlloc = sqlite3Malloc(10); \
+- if (!pTstAlloc) return SQLITE_IOERR_NOMEM; \
+- sqlite3_free(pTstAlloc); \
+- }
+-#else
+- #define DO_OS_MALLOC_TEST(x)
+-#endif
++#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
+
+-/*
+-** The following routines are convenience wrappers around methods
+-** of the sqlite3_file object. This is mostly just syntactic sugar. All
+-** of this would be completely automatic if SQLite were coded using
+-** C++ instead of plain old C.
+-*/
+-SQLITE_PRIVATE int sqlite3OsClose(sqlite3_file *pId){
+- int rc = SQLITE_OK;
+- if( pId->pMethods ){
+- rc = pId->pMethods->xClose(pId);
+- pId->pMethods = 0;
+- }
+- return rc;
+-}
+-SQLITE_PRIVATE int sqlite3OsRead(sqlite3_file *id, void *pBuf, int amt, i64 offset){
+- DO_OS_MALLOC_TEST(id);
+- return id->pMethods->xRead(id, pBuf, amt, offset);
+-}
+-SQLITE_PRIVATE int sqlite3OsWrite(sqlite3_file *id, const void *pBuf, int amt, i64 offset){
+- DO_OS_MALLOC_TEST(id);
+- return id->pMethods->xWrite(id, pBuf, amt, offset);
+-}
+-SQLITE_PRIVATE int sqlite3OsTruncate(sqlite3_file *id, i64 size){
+- return id->pMethods->xTruncate(id, size);
+-}
+-SQLITE_PRIVATE int sqlite3OsSync(sqlite3_file *id, int flags){
+- DO_OS_MALLOC_TEST(id);
+- return id->pMethods->xSync(id, flags);
+-}
+-SQLITE_PRIVATE int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){
+- DO_OS_MALLOC_TEST(id);
+- return id->pMethods->xFileSize(id, pSize);
+-}
+-SQLITE_PRIVATE int sqlite3OsLock(sqlite3_file *id, int lockType){
+- DO_OS_MALLOC_TEST(id);
+- return id->pMethods->xLock(id, lockType);
+-}
+-SQLITE_PRIVATE int sqlite3OsUnlock(sqlite3_file *id, int lockType){
+- return id->pMethods->xUnlock(id, lockType);
+-}
+-SQLITE_PRIVATE int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut){
+- DO_OS_MALLOC_TEST(id);
+- return id->pMethods->xCheckReservedLock(id, pResOut);
+-}
+
+ /*
+-** Use sqlite3OsFileControl() when we are doing something that might fail
+-** and we need to know about the failures. Use sqlite3OsFileControlHint()
+-** when simply tossing information over the wall to the VFS and we do not
+-** really care if the VFS receives and understands the information since it
+-** is only a hint and can be safely ignored. The sqlite3OsFileControlHint()
+-** routine has no return value since the return value would be meaningless.
++** An array of names of all compile-time options. This array should
++** be sorted A-Z.
++**
++** This array looks large, but in a typical installation actually uses
++** only a handful of compile-time options, so most times this array is usually
++** rather short and uses little memory space.
+ */
+-SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){
+-#ifdef SQLITE_TEST
+- if( op!=SQLITE_FCNTL_COMMIT_PHASETWO ){
+- /* Faults are not injected into COMMIT_PHASETWO because, assuming SQLite
+- ** is using a regular VFS, it is called after the corresponding
+- ** transaction has been committed. Injecting a fault at this point
+- ** confuses the test scripts - the COMMIT comand returns SQLITE_NOMEM
+- ** but the transaction is committed anyway.
+- **
+- ** The core must call OsFileControl() though, not OsFileControlHint(),
+- ** as if a custom VFS (e.g. zipvfs) returns an error here, it probably
+- ** means the commit really has failed and an error should be returned
+- ** to the user. */
+- DO_OS_MALLOC_TEST(id);
+- }
+-#endif
+- return id->pMethods->xFileControl(id, op, pArg);
+-}
+-SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file *id, int op, void *pArg){
+- (void)id->pMethods->xFileControl(id, op, pArg);
+-}
++static const char * const azCompileOpt[] = {
+
+-SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id){
+- int (*xSectorSize)(sqlite3_file*) = id->pMethods->xSectorSize;
+- return (xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE);
+-}
+-SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id){
+- return id->pMethods->xDeviceCharacteristics(id);
+-}
+-SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int offset, int n, int flags){
+- return id->pMethods->xShmLock(id, offset, n, flags);
+-}
+-SQLITE_PRIVATE void sqlite3OsShmBarrier(sqlite3_file *id){
+- id->pMethods->xShmBarrier(id);
+-}
+-SQLITE_PRIVATE int sqlite3OsShmUnmap(sqlite3_file *id, int deleteFlag){
+- return id->pMethods->xShmUnmap(id, deleteFlag);
+-}
+-SQLITE_PRIVATE int sqlite3OsShmMap(
+- sqlite3_file *id, /* Database file handle */
+- int iPage,
+- int pgsz,
+- int bExtend, /* True to extend file if necessary */
+- void volatile **pp /* OUT: Pointer to mapping */
+-){
+- DO_OS_MALLOC_TEST(id);
+- return id->pMethods->xShmMap(id, iPage, pgsz, bExtend, pp);
+-}
++/* These macros are provided to "stringify" the value of the define
++** for those options in which the value is meaningful. */
++#define CTIMEOPT_VAL_(opt) #opt
++#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
+
+-#if SQLITE_MAX_MMAP_SIZE>0
+-/* The real implementation of xFetch and xUnfetch */
+-SQLITE_PRIVATE int sqlite3OsFetch(sqlite3_file *id, i64 iOff, int iAmt, void **pp){
+- DO_OS_MALLOC_TEST(id);
+- return id->pMethods->xFetch(id, iOff, iAmt, pp);
++#if SQLITE_32BIT_ROWID
++ "32BIT_ROWID",
++#endif
++#if SQLITE_4_BYTE_ALIGNED_MALLOC
++ "4_BYTE_ALIGNED_MALLOC",
++#endif
++#if SQLITE_CASE_SENSITIVE_LIKE
++ "CASE_SENSITIVE_LIKE",
++#endif
++#if SQLITE_CHECK_PAGES
++ "CHECK_PAGES",
++#endif
++#if SQLITE_COVERAGE_TEST
++ "COVERAGE_TEST",
++#endif
++#if SQLITE_DEBUG
++ "DEBUG",
++#endif
++#if SQLITE_DEFAULT_LOCKING_MODE
++ "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE),
++#endif
++#if defined(SQLITE_DEFAULT_MMAP_SIZE) && !defined(SQLITE_DEFAULT_MMAP_SIZE_xc)
++ "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE),
++#endif
++#if SQLITE_DISABLE_DIRSYNC
++ "DISABLE_DIRSYNC",
++#endif
++#if SQLITE_DISABLE_LFS
++ "DISABLE_LFS",
++#endif
++#if SQLITE_ENABLE_API_ARMOR
++ "ENABLE_API_ARMOR",
++#endif
++#if SQLITE_ENABLE_ATOMIC_WRITE
++ "ENABLE_ATOMIC_WRITE",
++#endif
++#if SQLITE_ENABLE_CEROD
++ "ENABLE_CEROD",
++#endif
++#if SQLITE_ENABLE_COLUMN_METADATA
++ "ENABLE_COLUMN_METADATA",
++#endif
++#if SQLITE_ENABLE_DBSTAT_VTAB
++ "ENABLE_DBSTAT_VTAB",
++#endif
++#if SQLITE_ENABLE_EXPENSIVE_ASSERT
++ "ENABLE_EXPENSIVE_ASSERT",
++#endif
++#if SQLITE_ENABLE_FTS1
++ "ENABLE_FTS1",
++#endif
++#if SQLITE_ENABLE_FTS2
++ "ENABLE_FTS2",
++#endif
++#if SQLITE_ENABLE_FTS3
++ "ENABLE_FTS3",
++#endif
++#if SQLITE_ENABLE_FTS3_PARENTHESIS
++ "ENABLE_FTS3_PARENTHESIS",
++#endif
++#if SQLITE_ENABLE_FTS4
++ "ENABLE_FTS4",
++#endif
++#if SQLITE_ENABLE_ICU
++ "ENABLE_ICU",
++#endif
++#if SQLITE_ENABLE_IOTRACE
++ "ENABLE_IOTRACE",
++#endif
++#if SQLITE_ENABLE_LOAD_EXTENSION
++ "ENABLE_LOAD_EXTENSION",
++#endif
++#if SQLITE_ENABLE_LOCKING_STYLE
++ "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE),
++#endif
++#if SQLITE_ENABLE_MEMORY_MANAGEMENT
++ "ENABLE_MEMORY_MANAGEMENT",
++#endif
++#if SQLITE_ENABLE_MEMSYS3
++ "ENABLE_MEMSYS3",
++#endif
++#if SQLITE_ENABLE_MEMSYS5
++ "ENABLE_MEMSYS5",
++#endif
++#if SQLITE_ENABLE_OVERSIZE_CELL_CHECK
++ "ENABLE_OVERSIZE_CELL_CHECK",
++#endif
++#if SQLITE_ENABLE_RTREE
++ "ENABLE_RTREE",
++#endif
++#if defined(SQLITE_ENABLE_STAT4)
++ "ENABLE_STAT4",
++#elif defined(SQLITE_ENABLE_STAT3)
++ "ENABLE_STAT3",
++#endif
++#if SQLITE_ENABLE_UNLOCK_NOTIFY
++ "ENABLE_UNLOCK_NOTIFY",
++#endif
++#if SQLITE_ENABLE_UPDATE_DELETE_LIMIT
++ "ENABLE_UPDATE_DELETE_LIMIT",
++#endif
++#if SQLITE_HAS_CODEC
++ "HAS_CODEC",
++#endif
++#if HAVE_ISNAN || SQLITE_HAVE_ISNAN
++ "HAVE_ISNAN",
++#endif
++#if SQLITE_HOMEGROWN_RECURSIVE_MUTEX
++ "HOMEGROWN_RECURSIVE_MUTEX",
++#endif
++#if SQLITE_IGNORE_AFP_LOCK_ERRORS
++ "IGNORE_AFP_LOCK_ERRORS",
++#endif
++#if SQLITE_IGNORE_FLOCK_LOCK_ERRORS
++ "IGNORE_FLOCK_LOCK_ERRORS",
++#endif
++#ifdef SQLITE_INT64_TYPE
++ "INT64_TYPE",
++#endif
++#if SQLITE_LOCK_TRACE
++ "LOCK_TRACE",
++#endif
++#if defined(SQLITE_MAX_MMAP_SIZE) && !defined(SQLITE_MAX_MMAP_SIZE_xc)
++ "MAX_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE),
++#endif
++#ifdef SQLITE_MAX_SCHEMA_RETRY
++ "MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY),
++#endif
++#if SQLITE_MEMDEBUG
++ "MEMDEBUG",
++#endif
++#if SQLITE_MIXED_ENDIAN_64BIT_FLOAT
++ "MIXED_ENDIAN_64BIT_FLOAT",
++#endif
++#if SQLITE_NO_SYNC
++ "NO_SYNC",
++#endif
++#if SQLITE_OMIT_ALTERTABLE
++ "OMIT_ALTERTABLE",
++#endif
++#if SQLITE_OMIT_ANALYZE
++ "OMIT_ANALYZE",
++#endif
++#if SQLITE_OMIT_ATTACH
++ "OMIT_ATTACH",
++#endif
++#if SQLITE_OMIT_AUTHORIZATION
++ "OMIT_AUTHORIZATION",
++#endif
++#if SQLITE_OMIT_AUTOINCREMENT
++ "OMIT_AUTOINCREMENT",
++#endif
++#if SQLITE_OMIT_AUTOINIT
++ "OMIT_AUTOINIT",
++#endif
++#if SQLITE_OMIT_AUTOMATIC_INDEX
++ "OMIT_AUTOMATIC_INDEX",
++#endif
++#if SQLITE_OMIT_AUTORESET
++ "OMIT_AUTORESET",
++#endif
++#if SQLITE_OMIT_AUTOVACUUM
++ "OMIT_AUTOVACUUM",
++#endif
++#if SQLITE_OMIT_BETWEEN_OPTIMIZATION
++ "OMIT_BETWEEN_OPTIMIZATION",
++#endif
++#if SQLITE_OMIT_BLOB_LITERAL
++ "OMIT_BLOB_LITERAL",
++#endif
++#if SQLITE_OMIT_BTREECOUNT
++ "OMIT_BTREECOUNT",
++#endif
++#if SQLITE_OMIT_BUILTIN_TEST
++ "OMIT_BUILTIN_TEST",
++#endif
++#if SQLITE_OMIT_CAST
++ "OMIT_CAST",
++#endif
++#if SQLITE_OMIT_CHECK
++ "OMIT_CHECK",
++#endif
++#if SQLITE_OMIT_COMPLETE
++ "OMIT_COMPLETE",
++#endif
++#if SQLITE_OMIT_COMPOUND_SELECT
++ "OMIT_COMPOUND_SELECT",
++#endif
++#if SQLITE_OMIT_CTE
++ "OMIT_CTE",
++#endif
++#if SQLITE_OMIT_DATETIME_FUNCS
++ "OMIT_DATETIME_FUNCS",
++#endif
++#if SQLITE_OMIT_DECLTYPE
++ "OMIT_DECLTYPE",
++#endif
++#if SQLITE_OMIT_DEPRECATED
++ "OMIT_DEPRECATED",
++#endif
++#if SQLITE_OMIT_DISKIO
++ "OMIT_DISKIO",
++#endif
++#if SQLITE_OMIT_EXPLAIN
++ "OMIT_EXPLAIN",
++#endif
++#if SQLITE_OMIT_FLAG_PRAGMAS
++ "OMIT_FLAG_PRAGMAS",
++#endif
++#if SQLITE_OMIT_FLOATING_POINT
++ "OMIT_FLOATING_POINT",
++#endif
++#if SQLITE_OMIT_FOREIGN_KEY
++ "OMIT_FOREIGN_KEY",
++#endif
++#if SQLITE_OMIT_GET_TABLE
++ "OMIT_GET_TABLE",
++#endif
++#if SQLITE_OMIT_INCRBLOB
++ "OMIT_INCRBLOB",
++#endif
++#if SQLITE_OMIT_INTEGRITY_CHECK
++ "OMIT_INTEGRITY_CHECK",
++#endif
++#if SQLITE_OMIT_LIKE_OPTIMIZATION
++ "OMIT_LIKE_OPTIMIZATION",
++#endif
++#if SQLITE_OMIT_LOAD_EXTENSION
++ "OMIT_LOAD_EXTENSION",
++#endif
++#if SQLITE_OMIT_LOCALTIME
++ "OMIT_LOCALTIME",
++#endif
++#if SQLITE_OMIT_LOOKASIDE
++ "OMIT_LOOKASIDE",
++#endif
++#if SQLITE_OMIT_MEMORYDB
++ "OMIT_MEMORYDB",
++#endif
++#if SQLITE_OMIT_OR_OPTIMIZATION
++ "OMIT_OR_OPTIMIZATION",
++#endif
++#if SQLITE_OMIT_PAGER_PRAGMAS
++ "OMIT_PAGER_PRAGMAS",
++#endif
++#if SQLITE_OMIT_PRAGMA
++ "OMIT_PRAGMA",
++#endif
++#if SQLITE_OMIT_PROGRESS_CALLBACK
++ "OMIT_PROGRESS_CALLBACK",
++#endif
++#if SQLITE_OMIT_QUICKBALANCE
++ "OMIT_QUICKBALANCE",
++#endif
++#if SQLITE_OMIT_REINDEX
++ "OMIT_REINDEX",
++#endif
++#if SQLITE_OMIT_SCHEMA_PRAGMAS
++ "OMIT_SCHEMA_PRAGMAS",
++#endif
++#if SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
++ "OMIT_SCHEMA_VERSION_PRAGMAS",
++#endif
++#if SQLITE_OMIT_SHARED_CACHE
++ "OMIT_SHARED_CACHE",
++#endif
++#if SQLITE_OMIT_SUBQUERY
++ "OMIT_SUBQUERY",
++#endif
++#if SQLITE_OMIT_TCL_VARIABLE
++ "OMIT_TCL_VARIABLE",
++#endif
++#if SQLITE_OMIT_TEMPDB
++ "OMIT_TEMPDB",
++#endif
++#if SQLITE_OMIT_TRACE
++ "OMIT_TRACE",
++#endif
++#if SQLITE_OMIT_TRIGGER
++ "OMIT_TRIGGER",
++#endif
++#if SQLITE_OMIT_TRUNCATE_OPTIMIZATION
++ "OMIT_TRUNCATE_OPTIMIZATION",
++#endif
++#if SQLITE_OMIT_UTF16
++ "OMIT_UTF16",
++#endif
++#if SQLITE_OMIT_VACUUM
++ "OMIT_VACUUM",
++#endif
++#if SQLITE_OMIT_VIEW
++ "OMIT_VIEW",
++#endif
++#if SQLITE_OMIT_VIRTUALTABLE
++ "OMIT_VIRTUALTABLE",
++#endif
++#if SQLITE_OMIT_WAL
++ "OMIT_WAL",
++#endif
++#if SQLITE_OMIT_WSD
++ "OMIT_WSD",
++#endif
++#if SQLITE_OMIT_XFER_OPT
++ "OMIT_XFER_OPT",
++#endif
++#if SQLITE_PERFORMANCE_TRACE
++ "PERFORMANCE_TRACE",
++#endif
++#if SQLITE_PROXY_DEBUG
++ "PROXY_DEBUG",
++#endif
++#if SQLITE_RTREE_INT_ONLY
++ "RTREE_INT_ONLY",
++#endif
++#if SQLITE_SECURE_DELETE
++ "SECURE_DELETE",
++#endif
++#if SQLITE_SMALL_STACK
++ "SMALL_STACK",
++#endif
++#if SQLITE_SOUNDEX
++ "SOUNDEX",
++#endif
++#if SQLITE_SYSTEM_MALLOC
++ "SYSTEM_MALLOC",
++#endif
++#if SQLITE_TCL
++ "TCL",
++#endif
++#if defined(SQLITE_TEMP_STORE) && !defined(SQLITE_TEMP_STORE_xc)
++ "TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE),
++#endif
++#if SQLITE_TEST
++ "TEST",
++#endif
++#if defined(SQLITE_THREADSAFE)
++ "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE),
++#endif
++#if SQLITE_USE_ALLOCA
++ "USE_ALLOCA",
++#endif
++#if SQLITE_USER_AUTHENTICATION
++ "USER_AUTHENTICATION",
++#endif
++#if SQLITE_WIN32_MALLOC
++ "WIN32_MALLOC",
++#endif
++#if SQLITE_ZERO_MALLOC
++ "ZERO_MALLOC"
++#endif
++};
++
++/*
++** Given the name of a compile-time option, return true if that option
++** was used and false if not.
++**
++** The name can optionally begin with "SQLITE_" but the "SQLITE_" prefix
++** is not required for a match.
++*/
++SQLITE_API int SQLITE_STDCALL sqlite3_compileoption_used(const char *zOptName){
++ int i, n;
++
++#if SQLITE_ENABLE_API_ARMOR
++ if( zOptName==0 ){
++ (void)SQLITE_MISUSE_BKPT;
++ return 0;
++ }
++#endif
++ if( sqlite3StrNICmp(zOptName, "SQLITE_", 7)==0 ) zOptName += 7;
++ n = sqlite3Strlen30(zOptName);
++
++ /* Since ArraySize(azCompileOpt) is normally in single digits, a
++ ** linear search is adequate. No need for a binary search. */
++ for(i=0; i<ArraySize(azCompileOpt); i++){
++ if( sqlite3StrNICmp(zOptName, azCompileOpt[i], n)==0
++ && sqlite3IsIdChar((unsigned char)azCompileOpt[i][n])==0
++ ){
++ return 1;
++ }
++ }
++ return 0;
++}
++
++/*
++** Return the N-th compile-time option string. If N is out of range,
++** return a NULL pointer.
++*/
++SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N){
++ if( N>=0 && N<ArraySize(azCompileOpt) ){
++ return azCompileOpt[N];
++ }
++ return 0;
++}
++
++#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
++
++/************** End of ctime.c ***********************************************/
++/************** Begin file status.c ******************************************/
++/*
++** 2008 June 18
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
@@ -4029,24 +6892,2141 @@
+**
+*************************************************************************
+**
-+** This file implements routines used to report what compile-time options
-+** SQLite was built with.
++** This module implements the sqlite3_status() interface and related
++** functionality.
++*/
++/************** Include vdbeInt.h in the middle of status.c ******************/
++/************** Begin file vdbeInt.h *****************************************/
++/*
++** 2003 September 6
++**
++** 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 is the header file for information that is private to the
++** VDBE. This information used to all be at the top of the single
++** source code file "vdbe.c". When that file became too big (over
++** 6000 lines long) it was split up into several smaller files and
++** this header information was factored out.
+*/
++#ifndef _VDBEINT_H_
++#define _VDBEINT_H_
+
-+#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
++/*
++** The maximum number of times that a statement will try to reparse
++** itself before giving up and returning SQLITE_SCHEMA.
++*/
++#ifndef SQLITE_MAX_SCHEMA_RETRY
++# define SQLITE_MAX_SCHEMA_RETRY 50
++#endif
+
++/*
++** SQL is translated into a sequence of instructions to be
++** executed by a virtual machine. Each instruction is an instance
++** of the following structure.
++*/
++typedef struct VdbeOp Op;
+
+/*
-+** An array of names of all compile-time options. This array should
-+** be sorted A-Z.
++** Boolean values
++*/
++typedef unsigned Bool;
++
++/* Opaque type used by code in vdbesort.c */
++typedef struct VdbeSorter VdbeSorter;
++
++/* Opaque type used by the explainer */
++typedef struct Explain Explain;
++
++/* Elements of the linked list at Vdbe.pAuxData */
++typedef struct AuxData AuxData;
++
++/*
++** A cursor is a pointer into a single BTree within a database file.
++** The cursor can seek to a BTree entry with a particular key, or
++** loop over all entries of the Btree. You can also insert new BTree
++** entries or retrieve the key or data from the entry that the cursor
++** is currently pointing to.
+**
-+** This array looks large, but in a typical installation actually uses
-+** only a handful of compile-time options, so most times this array is usually
-+** rather short and uses little memory space.
- */
- static const char * const azCompileOpt[] = {
-
-@@ -19343,7 +22894,7 @@
++** Cursors can also point to virtual tables, sorters, or "pseudo-tables".
++** A pseudo-table is a single-row table implemented by registers.
++**
++** Every cursor that the virtual machine has open is represented by an
++** instance of the following structure.
++*/
++struct VdbeCursor {
++ BtCursor *pCursor; /* The cursor structure of the backend */
++ Btree *pBt; /* Separate file holding temporary table */
++ KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
++ int seekResult; /* Result of previous sqlite3BtreeMoveto() */
++ int pseudoTableReg; /* Register holding pseudotable content. */
++ i16 nField; /* Number of fields in the header */
++ u16 nHdrParsed; /* Number of header fields parsed so far */
++#ifdef SQLITE_DEBUG
++ u8 seekOp; /* Most recent seek operation on this cursor */
++#endif
++ i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */
++ u8 nullRow; /* True if pointing to a row with no data */
++ u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
++ Bool isEphemeral:1; /* True for an ephemeral table */
++ Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */
++ Bool isTable:1; /* True if a table requiring integer keys */
++ Bool isOrdered:1; /* True if the underlying table is BTREE_UNORDERED */
++ Pgno pgnoRoot; /* Root page of the open btree cursor */
++ sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */
++ i64 seqCount; /* Sequence counter */
++ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
++ VdbeSorter *pSorter; /* Sorter object for OP_SorterOpen cursors */
++
++ /* Cached information about the header for the data record that the
++ ** cursor is currently pointing to. Only valid if cacheStatus matches
++ ** Vdbe.cacheCtr. Vdbe.cacheCtr will never take on the value of
++ ** CACHE_STALE and so setting cacheStatus=CACHE_STALE guarantees that
++ ** the cache is out of date.
++ **
++ ** aRow might point to (ephemeral) data for the current row, or it might
++ ** be NULL.
++ */
++ u32 cacheStatus; /* Cache is valid if this matches Vdbe.cacheCtr */
++ u32 payloadSize; /* Total number of bytes in the record */
++ u32 szRow; /* Byte available in aRow */
++ u32 iHdrOffset; /* Offset to next unparsed byte of the header */
++ const u8 *aRow; /* Data for the current row, if all on one page */
++ u32 *aOffset; /* Pointer to aType[nField] */
++ u32 aType[1]; /* Type values for all entries in the record */
++ /* 2*nField extra array elements allocated for aType[], beyond the one
++ ** static element declared in the structure. nField total array slots for
++ ** aType[] and nField+1 array slots for aOffset[] */
++};
++typedef struct VdbeCursor VdbeCursor;
++
++/*
++** When a sub-program is executed (OP_Program), a structure of this type
++** is allocated to store the current value of the program counter, as
++** well as the current memory cell array and various other frame specific
++** values stored in the Vdbe struct. When the sub-program is finished,
++** these values are copied back to the Vdbe from the VdbeFrame structure,
++** restoring the state of the VM to as it was before the sub-program
++** began executing.
++**
++** The memory for a VdbeFrame object is allocated and managed by a memory
++** cell in the parent (calling) frame. When the memory cell is deleted or
++** overwritten, the VdbeFrame object is not freed immediately. Instead, it
++** is linked into the Vdbe.pDelFrame list. The contents of the Vdbe.pDelFrame
++** list is deleted when the VM is reset in VdbeHalt(). The reason for doing
++** this instead of deleting the VdbeFrame immediately is to avoid recursive
++** calls to sqlite3VdbeMemRelease() when the memory cells belonging to the
++** child frame are released.
++**
++** The currently executing frame is stored in Vdbe.pFrame. Vdbe.pFrame is
++** set to NULL if the currently executing frame is the main program.
++*/
++typedef struct VdbeFrame VdbeFrame;
++struct VdbeFrame {
++ Vdbe *v; /* VM this frame belongs to */
++ VdbeFrame *pParent; /* Parent of this frame, or NULL if parent is main */
++ Op *aOp; /* Program instructions for parent frame */
++ i64 *anExec; /* Event counters from parent frame */
++ Mem *aMem; /* Array of memory cells for parent frame */
++ u8 *aOnceFlag; /* Array of OP_Once flags for parent frame */
++ VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */
++ void *token; /* Copy of SubProgram.token */
++ i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
++ int nCursor; /* Number of entries in apCsr */
++ int pc; /* Program Counter in parent (calling) frame */
++ int nOp; /* Size of aOp array */
++ int nMem; /* Number of entries in aMem */
++ int nOnceFlag; /* Number of entries in aOnceFlag */
++ int nChildMem; /* Number of memory cells for child frame */
++ int nChildCsr; /* Number of cursors for child frame */
++ int nChange; /* Statement changes (Vdbe.nChange) */
++ int nDbChange; /* Value of db->nChange */
++};
++
++#define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))])
++
++/*
++** A value for VdbeCursor.cacheValid that means the cache is always invalid.
++*/
++#define CACHE_STALE 0
++
++/*
++** Internally, the vdbe manipulates nearly all SQL values as Mem
++** structures. Each Mem struct may cache multiple representations (string,
++** integer etc.) of the same value.
++*/
++struct Mem {
++ union MemValue {
++ double r; /* Real value used when MEM_Real is set in flags */
++ i64 i; /* Integer value used when MEM_Int is set in flags */
++ int nZero; /* Used when bit MEM_Zero is set in flags */
++ FuncDef *pDef; /* Used only when flags==MEM_Agg */
++ RowSet *pRowSet; /* Used only when flags==MEM_RowSet */
++ VdbeFrame *pFrame; /* Used when flags==MEM_Frame */
++ } u;
++ u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
++ u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */
++ int n; /* Number of characters in string value, excluding '\0' */
++ char *z; /* String or BLOB value */
++ /* ShallowCopy only needs to copy the information above */
++ char *zMalloc; /* Space to hold MEM_Str or MEM_Blob if szMalloc>0 */
++ int szMalloc; /* Size of the zMalloc allocation */
++ u32 uTemp; /* Transient storage for serial_type in OP_MakeRecord */
++ sqlite3 *db; /* The associated database connection */
++ void (*xDel)(void*);/* Destructor for Mem.z - only valid if MEM_Dyn */
++#ifdef SQLITE_DEBUG
++ Mem *pScopyFrom; /* This Mem is a shallow copy of pScopyFrom */
++ void *pFiller; /* So that sizeof(Mem) is a multiple of 8 */
++#endif
++};
++
++/* One or more of the following flags are set to indicate the validOK
++** representations of the value stored in the Mem struct.
++**
++** If the MEM_Null flag is set, then the value is an SQL NULL value.
++** No other flags may be set in this case.
++**
++** If the MEM_Str flag is set then Mem.z points at a string representation.
++** Usually this is encoded in the same unicode encoding as the main
++** database (see below for exceptions). If the MEM_Term flag is also
++** set, then the string is nul terminated. The MEM_Int and MEM_Real
++** flags may coexist with the MEM_Str flag.
++*/
++#define MEM_Null 0x0001 /* Value is NULL */
++#define MEM_Str 0x0002 /* Value is a string */
++#define MEM_Int 0x0004 /* Value is an integer */
++#define MEM_Real 0x0008 /* Value is a real number */
++#define MEM_Blob 0x0010 /* Value is a BLOB */
++#define MEM_AffMask 0x001f /* Mask of affinity bits */
++#define MEM_RowSet 0x0020 /* Value is a RowSet object */
++#define MEM_Frame 0x0040 /* Value is a VdbeFrame object */
++#define MEM_Undefined 0x0080 /* Value is undefined */
++#define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */
++#define MEM_TypeMask 0x01ff /* Mask of type bits */
++
++
++/* Whenever Mem contains a valid string or blob representation, one of
++** the following flags must be set to determine the memory management
++** policy for Mem.z. The MEM_Term flag tells us whether or not the
++** string is \000 or \u0000 terminated
++*/
++#define MEM_Term 0x0200 /* String rep is nul terminated */
++#define MEM_Dyn 0x0400 /* Need to call Mem.xDel() on Mem.z */
++#define MEM_Static 0x0800 /* Mem.z points to a static string */
++#define MEM_Ephem 0x1000 /* Mem.z points to an ephemeral string */
++#define MEM_Agg 0x2000 /* Mem.z points to an agg function context */
++#define MEM_Zero 0x4000 /* Mem.i contains count of 0s appended to blob */
++#ifdef SQLITE_OMIT_INCRBLOB
++ #undef MEM_Zero
++ #define MEM_Zero 0x0000
++#endif
++
++/*
++** Clear any existing type flags from a Mem and replace them with f
++*/
++#define MemSetTypeFlag(p, f) \
++ ((p)->flags = ((p)->flags&~(MEM_TypeMask|MEM_Zero))|f)
++
++/*
++** Return true if a memory cell is not marked as invalid. This macro
++** is for use inside assert() statements only.
++*/
++#ifdef SQLITE_DEBUG
++#define memIsValid(M) ((M)->flags & MEM_Undefined)==0
++#endif
++
++/*
++** Each auxiliary data pointer stored by a user defined function
++** implementation calling sqlite3_set_auxdata() is stored in an instance
++** of this structure. All such structures associated with a single VM
++** are stored in a linked list headed at Vdbe.pAuxData. All are destroyed
++** when the VM is halted (if not before).
++*/
++struct AuxData {
++ int iOp; /* Instruction number of OP_Function opcode */
++ int iArg; /* Index of function argument. */
++ void *pAux; /* Aux data pointer */
++ void (*xDelete)(void *); /* Destructor for the aux data */
++ AuxData *pNext; /* Next element in list */
++};
++
++/*
++** The "context" argument for an installable function. A pointer to an
++** instance of this structure is the first argument to the routines used
++** implement the SQL functions.
++**
++** There is a typedef for this structure in sqlite.h. So all routines,
++** even the public interface to SQLite, can use a pointer to this structure.
++** But this file is the only place where the internal details of this
++** structure are known.
++**
++** This structure is defined inside of vdbeInt.h because it uses substructures
++** (Mem) which are only defined there.
++*/
++struct sqlite3_context {
++ Mem *pOut; /* The return value is stored here */
++ FuncDef *pFunc; /* Pointer to function information */
++ Mem *pMem; /* Memory cell used to store aggregate context */
++ Vdbe *pVdbe; /* The VM that owns this context */
++ int iOp; /* Instruction number of OP_Function */
++ int isError; /* Error code returned by the function. */
++ u8 skipFlag; /* Skip accumulator loading if true */
++ u8 fErrorOrAux; /* isError!=0 or pVdbe->pAuxData modified */
++};
++
++/*
++** An Explain object accumulates indented output which is helpful
++** in describing recursive data structures.
++*/
++struct Explain {
++ Vdbe *pVdbe; /* Attach the explanation to this Vdbe */
++ StrAccum str; /* The string being accumulated */
++ int nIndent; /* Number of elements in aIndent */
++ u16 aIndent[100]; /* Levels of indentation */
++ char zBase[100]; /* Initial space */
++};
++
++/* A bitfield type for use inside of structures. Always follow with :N where
++** N is the number of bits.
++*/
++typedef unsigned bft; /* Bit Field Type */
++
++typedef struct ScanStatus ScanStatus;
++struct ScanStatus {
++ int addrExplain; /* OP_Explain for loop */
++ int addrLoop; /* Address of "loops" counter */
++ int addrVisit; /* Address of "rows visited" counter */
++ int iSelectID; /* The "Select-ID" for this loop */
++ LogEst nEst; /* Estimated output rows per loop */
++ char *zName; /* Name of table or index */
++};
++
++/*
++** An instance of the virtual machine. This structure contains the complete
++** state of the virtual machine.
++**
++** The "sqlite3_stmt" structure pointer that is returned by sqlite3_prepare()
++** is really a pointer to an instance of this structure.
++*/
++struct Vdbe {
++ sqlite3 *db; /* The database connection that owns this statement */
++ Op *aOp; /* Space to hold the virtual machine's program */
++ Mem *aMem; /* The memory locations */
++ Mem **apArg; /* Arguments to currently executing user function */
++ Mem *aColName; /* Column names to return */
++ Mem *pResultSet; /* Pointer to an array of results */
++ Parse *pParse; /* Parsing context used to create this Vdbe */
++ int nMem; /* Number of memory locations currently allocated */
++ int nOp; /* Number of instructions in the program */
++ int nCursor; /* Number of slots in apCsr[] */
++ u32 magic; /* Magic number for sanity checking */
++ char *zErrMsg; /* Error message written here */
++ Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
++ VdbeCursor **apCsr; /* One element of this array for each open cursor */
++ Mem *aVar; /* Values for the OP_Variable opcode. */
++ char **azVar; /* Name of variables */
++ ynVar nVar; /* Number of entries in aVar[] */
++ ynVar nzVar; /* Number of entries in azVar[] */
++ u32 cacheCtr; /* VdbeCursor row cache generation counter */
++ int pc; /* The program counter */
++ int rc; /* Value to return */
++#ifdef SQLITE_DEBUG
++ int rcApp; /* errcode set by sqlite3_result_error_code() */
++#endif
++ u16 nResColumn; /* Number of columns in one row of the result set */
++ u8 errorAction; /* Recovery action to do in case of an error */
++ u8 minWriteFileFormat; /* Minimum file format for writable database files */
++ bft explain:2; /* True if EXPLAIN present on SQL command */
++ bft changeCntOn:1; /* True to update the change-counter */
++ bft expired:1; /* True if the VM needs to be recompiled */
++ bft runOnlyOnce:1; /* Automatically expire on reset */
++ bft usesStmtJournal:1; /* True if uses a statement journal */
++ bft readOnly:1; /* True for statements that do not write */
++ bft bIsReader:1; /* True for statements that read */
++ bft isPrepareV2:1; /* True if prepared with prepare_v2() */
++ bft doingRerun:1; /* True if rerunning after an auto-reprepare */
++ int nChange; /* Number of db changes made since last reset */
++ yDbMask btreeMask; /* Bitmask of db->aDb[] entries referenced */
++ yDbMask lockMask; /* Subset of btreeMask that requires a lock */
++ int iStatement; /* Statement number (or 0 if has not opened stmt) */
++ u32 aCounter[5]; /* Counters used by sqlite3_stmt_status() */
++#ifndef SQLITE_OMIT_TRACE
++ i64 startTime; /* Time when query started - used for profiling */
++#endif
++ i64 iCurrentTime; /* Value of julianday('now') for this statement */
++ i64 nFkConstraint; /* Number of imm. FK constraints this VM */
++ i64 nStmtDefCons; /* Number of def. constraints when stmt started */
++ i64 nStmtDefImmCons; /* Number of def. imm constraints when stmt started */
++ char *zSql; /* Text of the SQL statement that generated this */
++ void *pFree; /* Free this when deleting the vdbe */
++ VdbeFrame *pFrame; /* Parent frame */
++ VdbeFrame *pDelFrame; /* List of frame objects to free on VM reset */
++ int nFrame; /* Number of frames in pFrame list */
++ u32 expmask; /* Binding to these vars invalidates VM */
++ SubProgram *pProgram; /* Linked list of all sub-programs used by VM */
++ int nOnceFlag; /* Size of array aOnceFlag[] */
++ u8 *aOnceFlag; /* Flags for OP_Once */
++ AuxData *pAuxData; /* Linked list of auxdata allocations */
++#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
++ i64 *anExec; /* Number of times each op has been executed */
++ int nScan; /* Entries in aScan[] */
++ ScanStatus *aScan; /* Scan definitions for sqlite3_stmt_scanstatus() */
++#endif
++};
++
++/*
++** The following are allowed values for Vdbe.magic
++*/
++#define VDBE_MAGIC_INIT 0x26bceaa5 /* Building a VDBE program */
++#define VDBE_MAGIC_RUN 0xbdf20da3 /* VDBE is ready to execute */
++#define VDBE_MAGIC_HALT 0x519c2973 /* VDBE has completed execution */
++#define VDBE_MAGIC_DEAD 0xb606c3c8 /* The VDBE has been deallocated */
++
++/*
++** Function prototypes
++*/
++SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*);
++void sqliteVdbePopStack(Vdbe*,int);
++SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor*);
++SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor*);
++#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
++SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE*, int, Op*);
++#endif
++SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32);
++SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem*, int);
++SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32);
++SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
++SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(Vdbe*, int, int);
++
++int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
++SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(sqlite3*,VdbeCursor*,UnpackedRecord*,int*);
++SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3*, BtCursor*, i64*);
++SQLITE_PRIVATE int sqlite3VdbeExec(Vdbe*);
++SQLITE_PRIVATE int sqlite3VdbeList(Vdbe*);
++SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe*);
++SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *, int);
++SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem*);
++SQLITE_PRIVATE int sqlite3VdbeMemCopy(Mem*, const Mem*);
++SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem*, const Mem*, int);
++SQLITE_PRIVATE void sqlite3VdbeMemMove(Mem*, Mem*);
++SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem*);
++SQLITE_PRIVATE int sqlite3VdbeMemSetStr(Mem*, const char*, int, u8, void(*)(void*));
++SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem*, i64);
++#ifdef SQLITE_OMIT_FLOATING_POINT
++# define sqlite3VdbeMemSetDouble sqlite3VdbeMemSetInt64
++#else
++SQLITE_PRIVATE void sqlite3VdbeMemSetDouble(Mem*, double);
++#endif
++SQLITE_PRIVATE void sqlite3VdbeMemInit(Mem*,sqlite3*,u16);
++SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem*);
++SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem*,int);
++SQLITE_PRIVATE void sqlite3VdbeMemSetRowSet(Mem*);
++SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem*);
++SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem*, u8, u8);
++SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem*);
++SQLITE_PRIVATE int sqlite3VdbeMemIntegerify(Mem*);
++SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem*);
++SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem*);
++SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem*);
++SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem*);
++SQLITE_PRIVATE void sqlite3VdbeMemCast(Mem*,u8,u8);
++SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,int,Mem*);
++SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p);
++#define VdbeMemDynamic(X) \
++ (((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))!=0)
++SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
++SQLITE_PRIVATE const char *sqlite3OpcodeName(int);
++SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve);
++SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int n);
++SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *, int);
++SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*);
++SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *);
++SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p);
++
++SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *, int, VdbeCursor *);
++SQLITE_PRIVATE void sqlite3VdbeSorterReset(sqlite3 *, VdbeSorter *);
++SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *);
++SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *);
++SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *);
++SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *, int *);
++SQLITE_PRIVATE int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *);
++SQLITE_PRIVATE int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *);
++
++#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0
++SQLITE_PRIVATE void sqlite3VdbeEnter(Vdbe*);
++SQLITE_PRIVATE void sqlite3VdbeLeave(Vdbe*);
++#else
++# define sqlite3VdbeEnter(X)
++# define sqlite3VdbeLeave(X)
++#endif
++
++#ifdef SQLITE_DEBUG
++SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe*,Mem*);
++SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem*);
++#endif
++
++#ifndef SQLITE_OMIT_FOREIGN_KEY
++SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *, int);
++#else
++# define sqlite3VdbeCheckFk(p,i) 0
++#endif
++
++SQLITE_PRIVATE int sqlite3VdbeMemTranslate(Mem*, u8);
++#ifdef SQLITE_DEBUG
++SQLITE_PRIVATE void sqlite3VdbePrintSql(Vdbe*);
++SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf);
++#endif
++SQLITE_PRIVATE int sqlite3VdbeMemHandleBom(Mem *pMem);
++
++#ifndef SQLITE_OMIT_INCRBLOB
++SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *);
++ #define ExpandBlob(P) (((P)->flags&MEM_Zero)?sqlite3VdbeMemExpandBlob(P):0)
++#else
++ #define sqlite3VdbeMemExpandBlob(x) SQLITE_OK
++ #define ExpandBlob(P) SQLITE_OK
++#endif
++
++#endif /* !defined(_VDBEINT_H_) */
++
++/************** End of vdbeInt.h *********************************************/
++/************** Continuing where we left off in status.c *********************/
++
++/*
++** Variables in which to record status information.
++*/
++typedef struct sqlite3StatType sqlite3StatType;
++static SQLITE_WSD struct sqlite3StatType {
++#if SQLITE_PTRSIZE>4
++ sqlite3_int64 nowValue[10]; /* Current value */
++ sqlite3_int64 mxValue[10]; /* Maximum value */
++#else
++ u32 nowValue[10]; /* Current value */
++ u32 mxValue[10]; /* Maximum value */
++#endif
++} sqlite3Stat = { {0,}, {0,} };
++
++/*
++** Elements of sqlite3Stat[] are protected by either the memory allocator
++** mutex, or by the pcache1 mutex. The following array determines which.
++*/
++static const char statMutex[] = {
++ 0, /* SQLITE_STATUS_MEMORY_USED */
++ 1, /* SQLITE_STATUS_PAGECACHE_USED */
++ 1, /* SQLITE_STATUS_PAGECACHE_OVERFLOW */
++ 0, /* SQLITE_STATUS_SCRATCH_USED */
++ 0, /* SQLITE_STATUS_SCRATCH_OVERFLOW */
++ 0, /* SQLITE_STATUS_MALLOC_SIZE */
++ 0, /* SQLITE_STATUS_PARSER_STACK */
++ 1, /* SQLITE_STATUS_PAGECACHE_SIZE */
++ 0, /* SQLITE_STATUS_SCRATCH_SIZE */
++ 0, /* SQLITE_STATUS_MALLOC_COUNT */
++};
++
++
++/* The "wsdStat" macro will resolve to the status information
++** state vector. If writable static data is unsupported on the target,
++** we have to locate the state vector at run-time. In the more common
++** case where writable static data is supported, wsdStat can refer directly
++** to the "sqlite3Stat" state vector declared above.
++*/
++#ifdef SQLITE_OMIT_WSD
++# define wsdStatInit sqlite3StatType *x = &GLOBAL(sqlite3StatType,sqlite3Stat)
++# define wsdStat x[0]
++#else
++# define wsdStatInit
++# define wsdStat sqlite3Stat
++#endif
++
++/*
++** Return the current value of a status parameter. The caller must
++** be holding the appropriate mutex.
++*/
++SQLITE_PRIVATE sqlite3_int64 sqlite3StatusValue(int op){
++ wsdStatInit;
++ assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
++ assert( op>=0 && op<ArraySize(statMutex) );
++ assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
++ : sqlite3MallocMutex()) );
++ return wsdStat.nowValue[op];
++}
++
++/*
++** Add N to the value of a status record. The caller must hold the
++** appropriate mutex. (Locking is checked by assert()).
++**
++** The StatusUp() routine can accept positive or negative values for N.
++** The value of N is added to the current status value and the high-water
++** mark is adjusted if necessary.
++**
++** The StatusDown() routine lowers the current value by N. The highwater
++** mark is unchanged. N must be non-negative for StatusDown().
++*/
++SQLITE_PRIVATE void sqlite3StatusUp(int op, int N){
++ wsdStatInit;
++ assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
++ assert( op>=0 && op<ArraySize(statMutex) );
++ assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
++ : sqlite3MallocMutex()) );
++ wsdStat.nowValue[op] += N;
++ if( wsdStat.nowValue[op]>wsdStat.mxValue[op] ){
++ wsdStat.mxValue[op] = wsdStat.nowValue[op];
++ }
++}
++SQLITE_PRIVATE void sqlite3StatusDown(int op, int N){
++ wsdStatInit;
++ assert( N>=0 );
++ assert( op>=0 && op<ArraySize(statMutex) );
++ assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
++ : sqlite3MallocMutex()) );
++ assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
++ wsdStat.nowValue[op] -= N;
++}
++
++/*
++** Set the value of a status to X. The highwater mark is adjusted if
++** necessary. The caller must hold the appropriate mutex.
++*/
++SQLITE_PRIVATE void sqlite3StatusSet(int op, int X){
++ wsdStatInit;
++ assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
++ assert( op>=0 && op<ArraySize(statMutex) );
++ assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
++ : sqlite3MallocMutex()) );
++ wsdStat.nowValue[op] = X;
++ if( wsdStat.nowValue[op]>wsdStat.mxValue[op] ){
++ wsdStat.mxValue[op] = wsdStat.nowValue[op];
++ }
++}
++
++/*
++** Query status information.
++*/
++SQLITE_API int SQLITE_STDCALL sqlite3_status64(
++ int op,
++ sqlite3_int64 *pCurrent,
++ sqlite3_int64 *pHighwater,
++ int resetFlag
++){
++ sqlite3_mutex *pMutex;
++ wsdStatInit;
++ if( op<0 || op>=ArraySize(wsdStat.nowValue) ){
++ return SQLITE_MISUSE_BKPT;
++ }
++#ifdef SQLITE_ENABLE_API_ARMOR
++ if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT;
++#endif
++ pMutex = statMutex[op] ? sqlite3Pcache1Mutex() : sqlite3MallocMutex();
++ sqlite3_mutex_enter(pMutex);
++ *pCurrent = wsdStat.nowValue[op];
++ *pHighwater = wsdStat.mxValue[op];
++ if( resetFlag ){
++ wsdStat.mxValue[op] = wsdStat.nowValue[op];
++ }
++ sqlite3_mutex_leave(pMutex);
++ (void)pMutex; /* Prevent warning when SQLITE_THREADSAFE=0 */
++ return SQLITE_OK;
++}
++SQLITE_API int SQLITE_STDCALL sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){
++ sqlite3_int64 iCur, iHwtr;
++ int rc;
++#ifdef SQLITE_ENABLE_API_ARMOR
++ if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT;
++#endif
++ rc = sqlite3_status64(op, &iCur, &iHwtr, resetFlag);
++ if( rc==0 ){
++ *pCurrent = (int)iCur;
++ *pHighwater = (int)iHwtr;
++ }
++ return rc;
++}
++
++/*
++** Query status information for a single database connection
++*/
++SQLITE_API int SQLITE_STDCALL sqlite3_db_status(
++ sqlite3 *db, /* The database connection whose status is desired */
++ int op, /* Status verb */
++ int *pCurrent, /* Write current value here */
++ int *pHighwater, /* Write high-water mark here */
++ int resetFlag /* Reset high-water mark if true */
++){
++ int rc = SQLITE_OK; /* Return code */
++#ifdef SQLITE_ENABLE_API_ARMOR
++ if( !sqlite3SafetyCheckOk(db) || pCurrent==0|| pHighwater==0 ){
++ return SQLITE_MISUSE_BKPT;
++ }
++#endif
++ sqlite3_mutex_enter(db->mutex);
++ switch( op ){
++ case SQLITE_DBSTATUS_LOOKASIDE_USED: {
++ *pCurrent = db->lookaside.nOut;
++ *pHighwater = db->lookaside.mxOut;
++ if( resetFlag ){
++ db->lookaside.mxOut = db->lookaside.nOut;
++ }
++ break;
++ }
++
++ case SQLITE_DBSTATUS_LOOKASIDE_HIT:
++ case SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE:
++ case SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL: {
++ testcase( op==SQLITE_DBSTATUS_LOOKASIDE_HIT );
++ testcase( op==SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE );
++ testcase( op==SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL );
++ assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)>=0 );
++ assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)<3 );
++ *pCurrent = 0;
++ *pHighwater = db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT];
++ if( resetFlag ){
++ db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT] = 0;
++ }
++ break;
++ }
++
++ /*
++ ** Return an approximation for the amount of memory currently used
++ ** by all pagers associated with the given database connection. The
++ ** highwater mark is meaningless and is returned as zero.
++ */
++ case SQLITE_DBSTATUS_CACHE_USED: {
++ int totalUsed = 0;
++ int i;
++ sqlite3BtreeEnterAll(db);
++ for(i=0; i<db->nDb; i++){
++ Btree *pBt = db->aDb[i].pBt;
++ if( pBt ){
++ Pager *pPager = sqlite3BtreePager(pBt);
++ totalUsed += sqlite3PagerMemUsed(pPager);
++ }
++ }
++ sqlite3BtreeLeaveAll(db);
++ *pCurrent = totalUsed;
++ *pHighwater = 0;
++ break;
++ }
++
++ /*
++ ** *pCurrent gets an accurate estimate of the amount of memory used
++ ** to store the schema for all databases (main, temp, and any ATTACHed
++ ** databases. *pHighwater is set to zero.
++ */
++ case SQLITE_DBSTATUS_SCHEMA_USED: {
++ int i; /* Used to iterate through schemas */
++ int nByte = 0; /* Used to accumulate return value */
++
++ sqlite3BtreeEnterAll(db);
++ db->pnBytesFreed = &nByte;
++ for(i=0; i<db->nDb; i++){
++ Schema *pSchema = db->aDb[i].pSchema;
++ if( ALWAYS(pSchema!=0) ){
++ HashElem *p;
++
++ nByte += sqlite3GlobalConfig.m.xRoundup(sizeof(HashElem)) * (
++ pSchema->tblHash.count
++ + pSchema->trigHash.count
++ + pSchema->idxHash.count
++ + pSchema->fkeyHash.count
++ );
++ nByte += sqlite3MallocSize(pSchema->tblHash.ht);
++ nByte += sqlite3MallocSize(pSchema->trigHash.ht);
++ nByte += sqlite3MallocSize(pSchema->idxHash.ht);
++ nByte += sqlite3MallocSize(pSchema->fkeyHash.ht);
++
++ for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){
++ sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
++ }
++ for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){
++ sqlite3DeleteTable(db, (Table *)sqliteHashData(p));
++ }
++ }
++ }
++ db->pnBytesFreed = 0;
++ sqlite3BtreeLeaveAll(db);
++
++ *pHighwater = 0;
++ *pCurrent = nByte;
++ break;
++ }
++
++ /*
++ ** *pCurrent gets an accurate estimate of the amount of memory used
++ ** to store all prepared statements.
++ ** *pHighwater is set to zero.
++ */
++ case SQLITE_DBSTATUS_STMT_USED: {
++ struct Vdbe *pVdbe; /* Used to iterate through VMs */
++ int nByte = 0; /* Used to accumulate return value */
++
++ db->pnBytesFreed = &nByte;
++ for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){
++ sqlite3VdbeClearObject(db, pVdbe);
++ sqlite3DbFree(db, pVdbe);
++ }
++ db->pnBytesFreed = 0;
++
++ *pHighwater = 0; /* IMP: R-64479-57858 */
++ *pCurrent = nByte;
++
++ break;
++ }
++
++ /*
++ ** Set *pCurrent to the total cache hits or misses encountered by all
++ ** pagers the database handle is connected to. *pHighwater is always set
++ ** to zero.
++ */
++ case SQLITE_DBSTATUS_CACHE_HIT:
++ case SQLITE_DBSTATUS_CACHE_MISS:
++ case SQLITE_DBSTATUS_CACHE_WRITE:{
++ int i;
++ int nRet = 0;
++ assert( SQLITE_DBSTATUS_CACHE_MISS==SQLITE_DBSTATUS_CACHE_HIT+1 );
++ assert( SQLITE_DBSTATUS_CACHE_WRITE==SQLITE_DBSTATUS_CACHE_HIT+2 );
++
++ for(i=0; i<db->nDb; i++){
++ if( db->aDb[i].pBt ){
++ Pager *pPager = sqlite3BtreePager(db->aDb[i].pBt);
++ sqlite3PagerCacheStat(pPager, op, resetFlag, &nRet);
++ }
++ }
++ *pHighwater = 0; /* IMP: R-42420-56072 */
++ /* IMP: R-54100-20147 */
++ /* IMP: R-29431-39229 */
++ *pCurrent = nRet;
++ break;
++ }
++
++ /* Set *pCurrent to non-zero if there are unresolved deferred foreign
++ ** key constraints. Set *pCurrent to zero if all foreign key constraints
++ ** have been satisfied. The *pHighwater is always set to zero.
++ */
++ case SQLITE_DBSTATUS_DEFERRED_FKS: {
++ *pHighwater = 0; /* IMP: R-11967-56545 */
++ *pCurrent = db->nDeferredImmCons>0 || db->nDeferredCons>0;
++ break;
++ }
++
++ default: {
++ rc = SQLITE_ERROR;
++ }
++ }
++ sqlite3_mutex_leave(db->mutex);
++ return rc;
++}
++
++/************** End of status.c **********************************************/
++/************** Begin file date.c ********************************************/
++/*
++** 2003 October 31
++**
++** The author disclaims copyright to this source code. In place of
++** a legal notice, here is a blessing:
++**
++** May you do good and not evil.
++** May you find forgiveness for yourself and forgive others.
++** May you share freely, never taking more than you give.
++**
++*************************************************************************
++** This file contains the C functions that implement date and time
++** functions for SQLite.
++**
++** There is only one exported symbol in this file - the function
++** sqlite3RegisterDateTimeFunctions() found at the bottom of the file.
++** All other code has file scope.
++**
++** SQLite processes all times and dates as julian day numbers. The
++** dates and times are stored as the number of days since noon
++** in Greenwich on November 24, 4714 B.C. according to the Gregorian
++** calendar system.
++**
++** 1970-01-01 00:00:00 is JD 2440587.5
++** 2000-01-01 00:00:00 is JD 2451544.5
++**
++** This implementation requires years to be expressed as a 4-digit number
++** which means that only dates between 0000-01-01 and 9999-12-31 can
++** be represented, even though julian day numbers allow a much wider
++** range of dates.
++**
++** The Gregorian calendar system is used for all dates and times,
++** even those that predate the Gregorian calendar. Historians usually
++** use the julian calendar for dates prior to 1582-10-15 and for some
++** dates afterwards, depending on locale. Beware of this difference.
++**
++** The conversion algorithms are implemented based on descriptions
++** in the following text:
++**
++** Jean Meeus
++** Astronomical Algorithms, 2nd Edition, 1998
++** ISBM 0-943396-61-1
++** Willmann-Bell, Inc
++** Richmond, Virginia (USA)
++*/
++/* #include <stdlib.h> */
++/* #include <assert.h> */
++#include <time.h>
++
++#ifndef SQLITE_OMIT_DATETIME_FUNCS
++
++
++/*
++** A structure for holding a single date and time.
++*/
++typedef struct DateTime DateTime;
++struct DateTime {
++ sqlite3_int64 iJD; /* The julian day number times 86400000 */
++ int Y, M, D; /* Year, month, and day */
++ int h, m; /* Hour and minutes */
++ int tz; /* Timezone offset in minutes */
++ double s; /* Seconds */
++ char validYMD; /* True (1) if Y,M,D are valid */
++ char validHMS; /* True (1) if h,m,s are valid */
++ char validJD; /* True (1) if iJD is valid */
++ char validTZ; /* True (1) if tz is valid */
++};
++
++
++/*
++** Convert zDate into one or more integers. Additional arguments
++** come in groups of 5 as follows:
++**
++** N number of digits in the integer
++** min minimum allowed value of the integer
++** max maximum allowed value of the integer
++** nextC first character after the integer
++** pVal where to write the integers value.
++**
++** Conversions continue until one with nextC==0 is encountered.
++** The function returns the number of successful conversions.
++*/
++static int getDigits(const char *zDate, ...){
++ va_list ap;
++ int val;
++ int N;
++ int min;
++ int max;
++ int nextC;
++ int *pVal;
++ int cnt = 0;
++ va_start(ap, zDate);
++ do{
++ N = va_arg(ap, int);
++ min = va_arg(ap, int);
++ max = va_arg(ap, int);
++ nextC = va_arg(ap, int);
++ pVal = va_arg(ap, int*);
++ val = 0;
++ while( N-- ){
++ if( !sqlite3Isdigit(*zDate) ){
++ goto end_getDigits;
++ }
++ val = val*10 + *zDate - '0';
++ zDate++;
++ }
++ if( val<min || val>max || (nextC!=0 && nextC!=*zDate) ){
++ goto end_getDigits;
++ }
++ *pVal = val;
++ zDate++;
++ cnt++;
++ }while( nextC );
++end_getDigits:
++ va_end(ap);
++ return cnt;
++}
++
++/*
++** Parse a timezone extension on the end of a date-time.
++** The extension is of the form:
++**
++** (+/-)HH:MM
++**
++** Or the "zulu" notation:
++**
++** Z
++**
++** If the parse is successful, write the number of minutes
++** of change in p->tz and return 0. If a parser error occurs,
++** return non-zero.
++**
++** A missing specifier is not considered an error.
++*/
++static int parseTimezone(const char *zDate, DateTime *p){
++ int sgn = 0;
++ int nHr, nMn;
++ int c;
++ while( sqlite3Isspace(*zDate) ){ zDate++; }
++ p->tz = 0;
++ c = *zDate;
++ if( c=='-' ){
++ sgn = -1;
++ }else if( c=='+' ){
++ sgn = +1;
++ }else if( c=='Z' || c=='z' ){
++ zDate++;
++ goto zulu_time;
++ }else{
++ return c!=0;
++ }
++ zDate++;
++ if( getDigits(zDate, 2, 0, 14, ':', &nHr, 2, 0, 59, 0, &nMn)!=2 ){
++ return 1;
++ }
++ zDate += 5;
++ p->tz = sgn*(nMn + nHr*60);
++zulu_time:
++ while( sqlite3Isspace(*zDate) ){ zDate++; }
++ return *zDate!=0;
++}
++
++/*
++** Parse times of the form HH:MM or HH:MM:SS or HH:MM:SS.FFFF.
++** The HH, MM, and SS must each be exactly 2 digits. The
++** fractional seconds FFFF can be one or more digits.
++**
++** Return 1 if there is a parsing error and 0 on success.
++*/
++static int parseHhMmSs(const char *zDate, DateTime *p){
++ int h, m, s;
++ double ms = 0.0;
++ if( getDigits(zDate, 2, 0, 24, ':', &h, 2, 0, 59, 0, &m)!=2 ){
++ return 1;
++ }
++ zDate += 5;
++ if( *zDate==':' ){
++ zDate++;
++ if( getDigits(zDate, 2, 0, 59, 0, &s)!=1 ){
++ return 1;
++ }
++ zDate += 2;
++ if( *zDate=='.' && sqlite3Isdigit(zDate[1]) ){
++ double rScale = 1.0;
++ zDate++;
++ while( sqlite3Isdigit(*zDate) ){
++ ms = ms*10.0 + *zDate - '0';
++ rScale *= 10.0;
++ zDate++;
++ }
++ ms /= rScale;
++ }
++ }else{
++ s = 0;
++ }
++ p->validJD = 0;
++ p->validHMS = 1;
++ p->h = h;
++ p->m = m;
++ p->s = s + ms;
++ if( parseTimezone(zDate, p) ) return 1;
++ p->validTZ = (p->tz!=0)?1:0;
++ return 0;
++}
++
++/*
++** Convert from YYYY-MM-DD HH:MM:SS to julian day. We always assume
++** that the YYYY-MM-DD is according to the Gregorian calendar.
++**
++** Reference: Meeus page 61
++*/
++static void computeJD(DateTime *p){
++ int Y, M, D, A, B, X1, X2;
++
++ if( p->validJD ) return;
++ if( p->validYMD ){
++ Y = p->Y;
++ M = p->M;
++ D = p->D;
++ }else{
++ Y = 2000; /* If no YMD specified, assume 2000-Jan-01 */
++ M = 1;
++ D = 1;
++ }
++ if( M<=2 ){
++ Y--;
++ M += 12;
++ }
++ A = Y/100;
++ B = 2 - A + (A/4);
++ X1 = 36525*(Y+4716)/100;
++ X2 = 306001*(M+1)/10000;
++ p->iJD = (sqlite3_int64)((X1 + X2 + D + B - 1524.5 ) * 86400000);
++ p->validJD = 1;
++ if( p->validHMS ){
++ p->iJD += p->h*3600000 + p->m*60000 + (sqlite3_int64)(p->s*1000);
++ if( p->validTZ ){
++ p->iJD -= p->tz*60000;
++ p->validYMD = 0;
++ p->validHMS = 0;
++ p->validTZ = 0;
++ }
++ }
++}
++
++/*
++** Parse dates of the form
++**
++** YYYY-MM-DD HH:MM:SS.FFF
++** YYYY-MM-DD HH:MM:SS
++** YYYY-MM-DD HH:MM
++** YYYY-MM-DD
++**
++** Write the result into the DateTime structure and return 0
++** on success and 1 if the input string is not a well-formed
++** date.
++*/
++static int parseYyyyMmDd(const char *zDate, DateTime *p){
++ int Y, M, D, neg;
++
++ if( zDate[0]=='-' ){
++ zDate++;
++ neg = 1;
++ }else{
++ neg = 0;
++ }
++ if( getDigits(zDate,4,0,9999,'-',&Y,2,1,12,'-',&M,2,1,31,0,&D)!=3 ){
++ return 1;
++ }
++ zDate += 10;
++ while( sqlite3Isspace(*zDate) || 'T'==*(u8*)zDate ){ zDate++; }
++ if( parseHhMmSs(zDate, p)==0 ){
++ /* We got the time */
++ }else if( *zDate==0 ){
++ p->validHMS = 0;
++ }else{
++ return 1;
++ }
++ p->validJD = 0;
++ p->validYMD = 1;
++ p->Y = neg ? -Y : Y;
++ p->M = M;
++ p->D = D;
++ if( p->validTZ ){
++ computeJD(p);
++ }
++ return 0;
++}
++
++/*
++** Set the time to the current time reported by the VFS.
++**
++** Return the number of errors.
++*/
++static int setDateTimeToCurrent(sqlite3_context *context, DateTime *p){
++ p->iJD = sqlite3StmtCurrentTime(context);
++ if( p->iJD>0 ){
++ p->validJD = 1;
++ return 0;
++ }else{
++ return 1;
++ }
++}
++
++/*
++** Attempt to parse the given string into a julian day number. Return
++** the number of errors.
++**
++** The following are acceptable forms for the input string:
++**
++** YYYY-MM-DD HH:MM:SS.FFF +/-HH:MM
++** DDDD.DD
++** now
++**
++** In the first form, the +/-HH:MM is always optional. The fractional
++** seconds extension (the ".FFF") is optional. The seconds portion
++** (":SS.FFF") is option. The year and date can be omitted as long
++** as there is a time string. The time string can be omitted as long
++** as there is a year and date.
++*/
++static int parseDateOrTime(
++ sqlite3_context *context,
++ const char *zDate,
++ DateTime *p
++){
++ double r;
++ if( parseYyyyMmDd(zDate,p)==0 ){
++ return 0;
++ }else if( parseHhMmSs(zDate, p)==0 ){
++ return 0;
++ }else if( sqlite3StrICmp(zDate,"now")==0){
++ return setDateTimeToCurrent(context, p);
++ }else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8) ){
++ p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5);
++ p->validJD = 1;
++ return 0;
++ }
++ return 1;
++}
++
++/*
++** Compute the Year, Month, and Day from the julian day number.
++*/
++static void computeYMD(DateTime *p){
++ int Z, A, B, C, D, E, X1;
++ if( p->validYMD ) return;
++ if( !p->validJD ){
++ p->Y = 2000;
++ p->M = 1;
++ p->D = 1;
++ }else{
++ Z = (int)((p->iJD + 43200000)/86400000);
++ A = (int)((Z - 1867216.25)/36524.25);
++ A = Z + 1 + A - (A/4);
++ B = A + 1524;
++ C = (int)((B - 122.1)/365.25);
++ D = (36525*C)/100;
++ E = (int)((B-D)/30.6001);
++ X1 = (int)(30.6001*E);
++ p->D = B - D - X1;
++ p->M = E<14 ? E-1 : E-13;
++ p->Y = p->M>2 ? C - 4716 : C - 4715;
++ }
++ p->validYMD = 1;
++}
++
++/*
++** Compute the Hour, Minute, and Seconds from the julian day number.
++*/
++static void computeHMS(DateTime *p){
++ int s;
++ if( p->validHMS ) return;
++ computeJD(p);
++ s = (int)((p->iJD + 43200000) % 86400000);
++ p->s = s/1000.0;
++ s = (int)p->s;
++ p->s -= s;
++ p->h = s/3600;
++ s -= p->h*3600;
++ p->m = s/60;
++ p->s += s - p->m*60;
++ p->validHMS = 1;
++}
++
++/*
++** Compute both YMD and HMS
++*/
++static void computeYMD_HMS(DateTime *p){
++ computeYMD(p);
++ computeHMS(p);
++}
++
++/*
++** Clear the YMD and HMS and the TZ
++*/
++static void clearYMD_HMS_TZ(DateTime *p){
++ p->validYMD = 0;
++ p->validHMS = 0;
++ p->validTZ = 0;
++}
++
++/*
++** On recent Windows platforms, the localtime_s() function is available
++** as part of the "Secure CRT". It is essentially equivalent to
++** localtime_r() available under most POSIX platforms, except that the
++** order of the parameters is reversed.
++**
++** See http://msdn.microsoft.com/en-us/library/a442x3ye(VS.80).aspx.
++**
++** If the user has not indicated to use localtime_r() or localtime_s()
++** already, check for an MSVC build environment that provides
++** localtime_s().
++*/
++#if !HAVE_LOCALTIME_R && !HAVE_LOCALTIME_S \
++ && defined(_MSC_VER) && defined(_CRT_INSECURE_DEPRECATE)
++#undef HAVE_LOCALTIME_S
++#define HAVE_LOCALTIME_S 1
++#endif
++
++#ifndef SQLITE_OMIT_LOCALTIME
++/*
++** The following routine implements the rough equivalent of localtime_r()
++** using whatever operating-system specific localtime facility that
++** is available. This routine returns 0 on success and
++** non-zero on any kind of error.
++**
++** If the sqlite3GlobalConfig.bLocaltimeFault variable is true then this
++** routine will always fail.
++**
++** EVIDENCE-OF: R-62172-00036 In this implementation, the standard C
++** library function localtime_r() is used to assist in the calculation of
++** local time.
++*/
++static int osLocaltime(time_t *t, struct tm *pTm){
++ int rc;
++#if !HAVE_LOCALTIME_R && !HAVE_LOCALTIME_S
++ struct tm *pX;
++#if SQLITE_THREADSAFE>0
++ sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
++#endif
++ sqlite3_mutex_enter(mutex);
++ pX = localtime(t);
++#ifndef SQLITE_OMIT_BUILTIN_TEST
++ if( sqlite3GlobalConfig.bLocaltimeFault ) pX = 0;
++#endif
++ if( pX ) *pTm = *pX;
++ sqlite3_mutex_leave(mutex);
++ rc = pX==0;
++#else
++#ifndef SQLITE_OMIT_BUILTIN_TEST
++ if( sqlite3GlobalConfig.bLocaltimeFault ) return 1;
++#endif
++#if HAVE_LOCALTIME_R
++ rc = localtime_r(t, pTm)==0;
++#else
++ rc = localtime_s(pTm, t);
++#endif /* HAVE_LOCALTIME_R */
++#endif /* HAVE_LOCALTIME_R || HAVE_LOCALTIME_S */
++ return rc;
++}
++#endif /* SQLITE_OMIT_LOCALTIME */
++
++
++#ifndef SQLITE_OMIT_LOCALTIME
++/*
++** Compute the difference (in milliseconds) between localtime and UTC
++** (a.k.a. GMT) for the time value p where p is in UTC. If no error occurs,
++** return this value and set *pRc to SQLITE_OK.
++**
++** Or, if an error does occur, set *pRc to SQLITE_ERROR. The returned value
++** is undefined in this case.
++*/
++static sqlite3_int64 localtimeOffset(
++ DateTime *p, /* Date at which to calculate offset */
++ sqlite3_context *pCtx, /* Write error here if one occurs */
++ int *pRc /* OUT: Error code. SQLITE_OK or ERROR */
++){
++ DateTime x, y;
++ time_t t;
++ struct tm sLocal;
++
++ /* Initialize the contents of sLocal to avoid a compiler warning. */
++ memset(&sLocal, 0, sizeof(sLocal));
++
++ x = *p;
++ computeYMD_HMS(&x);
++ if( x.Y<1971 || x.Y>=2038 ){
++ /* EVIDENCE-OF: R-55269-29598 The localtime_r() C function normally only
++ ** works for years between 1970 and 2037. For dates outside this range,
++ ** SQLite attempts to map the year into an equivalent year within this
++ ** range, do the calculation, then map the year back.
++ */
++ x.Y = 2000;
++ x.M = 1;
++ x.D = 1;
++ x.h = 0;
++ x.m = 0;
++ x.s = 0.0;
++ } else {
++ int s = (int)(x.s + 0.5);
++ x.s = s;
++ }
++ x.tz = 0;
++ x.validJD = 0;
++ computeJD(&x);
++ t = (time_t)(x.iJD/1000 - 21086676*(i64)10000);
++ if( osLocaltime(&t, &sLocal) ){
++ sqlite3_result_error(pCtx, "local time unavailable", -1);
++ *pRc = SQLITE_ERROR;
++ return 0;
++ }
++ y.Y = sLocal.tm_year + 1900;
++ y.M = sLocal.tm_mon + 1;
++ y.D = sLocal.tm_mday;
++ y.h = sLocal.tm_hour;
++ y.m = sLocal.tm_min;
++ y.s = sLocal.tm_sec;
++ y.validYMD = 1;
++ y.validHMS = 1;
++ y.validJD = 0;
++ y.validTZ = 0;
++ computeJD(&y);
++ *pRc = SQLITE_OK;
++ return y.iJD - x.iJD;
++}
++#endif /* SQLITE_OMIT_LOCALTIME */
++
++/*
++** Process a modifier to a date-time stamp. The modifiers are
++** as follows:
++**
++** NNN days
++** NNN hours
++** NNN minutes
++** NNN.NNNN seconds
++** NNN months
++** NNN years
++** start of month
++** start of year
++** start of week
++** start of day
++** weekday N
++** unixepoch
++** localtime
++** utc
++**
++** Return 0 on success and 1 if there is any kind of error. If the error
++** is in a system call (i.e. localtime()), then an error message is written
++** to context pCtx. If the error is an unrecognized modifier, no error is
++** written to pCtx.
++*/
++static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
++ int rc = 1;
++ int n;
++ double r;
++ char *z, zBuf[30];
++ z = zBuf;
++ for(n=0; n<ArraySize(zBuf)-1 && zMod[n]; n++){
++ z[n] = (char)sqlite3UpperToLower[(u8)zMod[n]];
++ }
++ z[n] = 0;
++ switch( z[0] ){
++#ifndef SQLITE_OMIT_LOCALTIME
++ case 'l': {
++ /* localtime
++ **
++ ** Assuming the current time value is UTC (a.k.a. GMT), shift it to
++ ** show local time.
++ */
++ if( strcmp(z, "localtime")==0 ){
++ computeJD(p);
++ p->iJD += localtimeOffset(p, pCtx, &rc);
++ clearYMD_HMS_TZ(p);
++ }
++ break;
++ }
++#endif
++ case 'u': {
++ /*
++ ** unixepoch
++ **
++ ** Treat the current value of p->iJD as the number of
++ ** seconds since 1970. Convert to a real julian day number.
++ */
++ if( strcmp(z, "unixepoch")==0 && p->validJD ){
++ p->iJD = (p->iJD + 43200)/86400 + 21086676*(i64)10000000;
++ clearYMD_HMS_TZ(p);
++ rc = 0;
++ }
++#ifndef SQLITE_OMIT_LOCALTIME
++ else if( strcmp(z, "utc")==0 ){
++ sqlite3_int64 c1;
++ computeJD(p);
++ c1 = localtimeOffset(p, pCtx, &rc);
++ if( rc==SQLITE_OK ){
++ p->iJD -= c1;
++ clearYMD_HMS_TZ(p);
++ p->iJD += c1 - localtimeOffset(p, pCtx, &rc);
++ }
++ }
++#endif
++ break;
++ }
++ case 'w': {
++ /*
++ ** weekday N
++ **
++ ** Move the date to the same time on the next occurrence of
++ ** weekday N where 0==Sunday, 1==Monday, and so forth. If the
++ ** date is already on the appropriate weekday, this is a no-op.
++ */
++ if( strncmp(z, "weekday ", 8)==0
++ && sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8)
++ && (n=(int)r)==r && n>=0 && r<7 ){
++ sqlite3_int64 Z;
++ computeYMD_HMS(p);
++ p->validTZ = 0;
++ p->validJD = 0;
++ computeJD(p);
++ Z = ((p->iJD + 129600000)/86400000) % 7;
++ if( Z>n ) Z -= 7;
++ p->iJD += (n - Z)*86400000;
++ clearYMD_HMS_TZ(p);
++ rc = 0;
++ }
++ break;
++ }
++ case 's': {
++ /*
++ ** start of TTTTT
++ **
++ ** Move the date backwards to the beginning of the current day,
++ ** or month or year.
++ */
++ if( strncmp(z, "start of ", 9)!=0 ) break;
++ z += 9;
++ computeYMD(p);
++ p->validHMS = 1;
++ p->h = p->m = 0;
++ p->s = 0.0;
++ p->validTZ = 0;
++ p->validJD = 0;
++ if( strcmp(z,"month")==0 ){
++ p->D = 1;
++ rc = 0;
++ }else if( strcmp(z,"year")==0 ){
++ computeYMD(p);
++ p->M = 1;
++ p->D = 1;
++ rc = 0;
++ }else if( strcmp(z,"day")==0 ){
++ rc = 0;
++ }
++ break;
++ }
++ case '+':
++ case '-':
++ case '0':
++ case '1':
++ case '2':
++ case '3':
++ case '4':
++ case '5':
++ case '6':
++ case '7':
++ case '8':
++ case '9': {
++ double rRounder;
++ for(n=1; z[n] && z[n]!=':' && !sqlite3Isspace(z[n]); n++){}
++ if( !sqlite3AtoF(z, &r, n, SQLITE_UTF8) ){
++ rc = 1;
++ break;
++ }
++ if( z[n]==':' ){
++ /* A modifier of the form (+|-)HH:MM:SS.FFF adds (or subtracts) the
++ ** specified number of hours, minutes, seconds, and fractional seconds
++ ** to the time. The ".FFF" may be omitted. The ":SS.FFF" may be
++ ** omitted.
++ */
++ const char *z2 = z;
++ DateTime tx;
++ sqlite3_int64 day;
++ if( !sqlite3Isdigit(*z2) ) z2++;
++ memset(&tx, 0, sizeof(tx));
++ if( parseHhMmSs(z2, &tx) ) break;
++ computeJD(&tx);
++ tx.iJD -= 43200000;
++ day = tx.iJD/86400000;
++ tx.iJD -= day*86400000;
++ if( z[0]=='-' ) tx.iJD = -tx.iJD;
++ computeJD(p);
++ clearYMD_HMS_TZ(p);
++ p->iJD += tx.iJD;
++ rc = 0;
++ break;
++ }
++ z += n;
++ while( sqlite3Isspace(*z) ) z++;
++ n = sqlite3Strlen30(z);
++ if( n>10 || n<3 ) break;
++ if( z[n-1]=='s' ){ z[n-1] = 0; n--; }
++ computeJD(p);
++ rc = 0;
++ rRounder = r<0 ? -0.5 : +0.5;
++ if( n==3 && strcmp(z,"day")==0 ){
++ p->iJD += (sqlite3_int64)(r*86400000.0 + rRounder);
++ }else if( n==4 && strcmp(z,"hour")==0 ){
++ p->iJD += (sqlite3_int64)(r*(86400000.0/24.0) + rRounder);
++ }else if( n==6 && strcmp(z,"minute")==0 ){
++ p->iJD += (sqlite3_int64)(r*(86400000.0/(24.0*60.0)) + rRounder);
++ }else if( n==6 && strcmp(z,"second")==0 ){
++ p->iJD += (sqlite3_int64)(r*(86400000.0/(24.0*60.0*60.0)) + rRounder);
++ }else if( n==5 && strcmp(z,"month")==0 ){
++ int x, y;
++ computeYMD_HMS(p);
++ p->M += (int)r;
++ x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
++ p->Y += x;
++ p->M -= x*12;
++ p->validJD = 0;
++ computeJD(p);
++ y = (int)r;
++ if( y!=r ){
++ p->iJD += (sqlite3_int64)((r - y)*30.0*86400000.0 + rRounder);
++ }
++ }else if( n==4 && strcmp(z,"year")==0 ){
++ int y = (int)r;
++ computeYMD_HMS(p);
++ p->Y += y;
++ p->validJD = 0;
++ computeJD(p);
++ if( y!=r ){
++ p->iJD += (sqlite3_int64)((r - y)*365.0*86400000.0 + rRounder);
++ }
++ }else{
++ rc = 1;
++ }
++ clearYMD_HMS_TZ(p);
++ break;
++ }
++ default: {
++ break;
++ }
++ }
++ return rc;
++}
++
++/*
++** Process time function arguments. argv[0] is a date-time stamp.
++** argv[1] and following are modifiers. Parse them all and write
++** the resulting time into the DateTime structure p. Return 0
++** on success and 1 if there are any errors.
++**
++** If there are zero parameters (if even argv[0] is undefined)
++** then assume a default value of "now" for argv[0].
++*/
++static int isDate(
++ sqlite3_context *context,
++ int argc,
++ sqlite3_value **argv,
++ DateTime *p
++){
++ int i;
++ const unsigned char *z;
++ int eType;
++ memset(p, 0, sizeof(*p));
++ if( argc==0 ){
++ return setDateTimeToCurrent(context, p);
++ }
++ if( (eType = sqlite3_value_type(argv[0]))==SQLITE_FLOAT
++ || eType==SQLITE_INTEGER ){
++ p->iJD = (sqlite3_int64)(sqlite3_value_double(argv[0])*86400000.0 + 0.5);
++ p->validJD = 1;
++ }else{
++ z = sqlite3_value_text(argv[0]);
++ if( !z || parseDateOrTime(context, (char*)z, p) ){
++ return 1;
++ }
++ }
++ for(i=1; i<argc; i++){
++ z = sqlite3_value_text(argv[i]);
++ if( z==0 || parseModifier(context, (char*)z, p) ) return 1;
++ }
++ return 0;
++}
++
++
++/*
++** The following routines implement the various date and time functions
++** of SQLite.
++*/
++
++/*
++** julianday( TIMESTRING, MOD, MOD, ...)
++**
++** Return the julian day number of the date specified in the arguments
++*/
++static void juliandayFunc(
++ sqlite3_context *context,
++ int argc,
++ sqlite3_value **argv
++){
++ DateTime x;
++ if( isDate(context, argc, argv, &x)==0 ){
++ computeJD(&x);
++ sqlite3_result_double(context, x.iJD/86400000.0);
++ }
++}
++
++/*
++** datetime( TIMESTRING, MOD, MOD, ...)
++**
++** Return YYYY-MM-DD HH:MM:SS
++*/
++static void datetimeFunc(
++ sqlite3_context *context,
++ int argc,
++ sqlite3_value **argv
++){
++ DateTime x;
++ if( isDate(context, argc, argv, &x)==0 ){
++ char zBuf[100];
++ computeYMD_HMS(&x);
++ sqlite3_snprintf(sizeof(zBuf), zBuf, "%04d-%02d-%02d %02d:%02d:%02d",
++ x.Y, x.M, x.D, x.h, x.m, (int)(x.s));
++ sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
++ }
++}
++
++/*
++** time( TIMESTRING, MOD, MOD, ...)
++**
++** Return HH:MM:SS
++*/
++static void timeFunc(
++ sqlite3_context *context,
++ int argc,
++ sqlite3_value **argv
++){
++ DateTime x;
++ if( isDate(context, argc, argv, &x)==0 ){
++ char zBuf[100];
++ computeHMS(&x);
++ sqlite3_snprintf(sizeof(zBuf), zBuf, "%02d:%02d:%02d", x.h, x.m, (int)x.s);
++ sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
++ }
++}
++
++/*
++** date( TIMESTRING, MOD, MOD, ...)
++**
++** Return YYYY-MM-DD
++*/
++static void dateFunc(
++ sqlite3_context *context,
++ int argc,
++ sqlite3_value **argv
++){
++ DateTime x;
++ if( isDate(context, argc, argv, &x)==0 ){
++ char zBuf[100];
++ computeYMD(&x);
++ sqlite3_snprintf(sizeof(zBuf), zBuf, "%04d-%02d-%02d", x.Y, x.M, x.D);
++ sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
++ }
++}
++
++/*
++** strftime( FORMAT, TIMESTRING, MOD, MOD, ...)
++**
++** Return a string described by FORMAT. Conversions as follows:
++**
++** %d day of month
++** %f ** fractional seconds SS.SSS
++** %H hour 00-24
++** %j day of year 000-366
++** %J ** julian day number
++** %m month 01-12
++** %M minute 00-59
++** %s seconds since 1970-01-01
++** %S seconds 00-59
++** %w day of week 0-6 sunday==0
++** %W week of year 00-53
++** %Y year 0000-9999
++** %% %
++*/
++static void strftimeFunc(
++ sqlite3_context *context,
++ int argc,
++ sqlite3_value **argv
++){
++ DateTime x;
++ u64 n;
++ size_t i,j;
++ char *z;
++ sqlite3 *db;
++ const char *zFmt;
++ char zBuf[100];
++ if( argc==0 ) return;
++ zFmt = (const char*)sqlite3_value_text(argv[0]);
++ if( zFmt==0 || isDate(context, argc-1, argv+1, &x) ) return;
++ db = sqlite3_context_db_handle(context);
++ for(i=0, n=1; zFmt[i]; i++, n++){
++ if( zFmt[i]=='%' ){
++ switch( zFmt[i+1] ){
++ case 'd':
++ case 'H':
++ case 'm':
++ case 'M':
++ case 'S':
++ case 'W':
++ n++;
++ /* fall thru */
++ case 'w':
++ case '%':
++ break;
++ case 'f':
++ n += 8;
++ break;
++ case 'j':
++ n += 3;
++ break;
++ case 'Y':
++ n += 8;
++ break;
++ case 's':
++ case 'J':
++ n += 50;
++ break;
++ default:
++ return; /* ERROR. return a NULL */
++ }
++ i++;
++ }
++ }
++ testcase( n==sizeof(zBuf)-1 );
++ testcase( n==sizeof(zBuf) );
++ testcase( n==(u64)db->aLimit[SQLITE_LIMIT_LENGTH]+1 );
++ testcase( n==(u64)db->aLimit[SQLITE_LIMIT_LENGTH] );
++ if( n<sizeof(zBuf) ){
++ z = zBuf;
++ }else if( n>(u64)db->aLimit[SQLITE_LIMIT_LENGTH] ){
++ sqlite3_result_error_toobig(context);
++ return;
++ }else{
++ z = sqlite3DbMallocRaw(db, (int)n);
++ if( z==0 ){
++ sqlite3_result_error_nomem(context);
++ return;
++ }
++ }
++ computeJD(&x);
++ computeYMD_HMS(&x);
++ for(i=j=0; zFmt[i]; i++){
++ if( zFmt[i]!='%' ){
++ z[j++] = zFmt[i];
++ }else{
++ i++;
++ switch( zFmt[i] ){
++ case 'd': sqlite3_snprintf(3, &z[j],"%02d",x.D); j+=2; break;
++ case 'f': {
++ double s = x.s;
++ if( s>59.999 ) s = 59.999;
++ sqlite3_snprintf(7, &z[j],"%06.3f", s);
++ j += sqlite3Strlen30(&z[j]);
++ break;
++ }
++ case 'H': sqlite3_snprintf(3, &z[j],"%02d",x.h); j+=2; break;
++ case 'W': /* Fall thru */
++ case 'j': {
++ int nDay; /* Number of days since 1st day of year */
++ DateTime y = x;
++ y.validJD = 0;
++ y.M = 1;
++ y.D = 1;
++ computeJD(&y);
++ nDay = (int)((x.iJD-y.iJD+43200000)/86400000);
++ if( zFmt[i]=='W' ){
++ int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */
++ wd = (int)(((x.iJD+43200000)/86400000)%7);
++ sqlite3_snprintf(3, &z[j],"%02d",(nDay+7-wd)/7);
++ j += 2;
++ }else{
++ sqlite3_snprintf(4, &z[j],"%03d",nDay+1);
++ j += 3;
++ }
++ break;
++ }
++ case 'J': {
++ sqlite3_snprintf(20, &z[j],"%.16g",x.iJD/86400000.0);
++ j+=sqlite3Strlen30(&z[j]);
++ break;
++ }
++ case 'm': sqlite3_snprintf(3, &z[j],"%02d",x.M); j+=2; break;
++ case 'M': sqlite3_snprintf(3, &z[j],"%02d",x.m); j+=2; break;
++ case 's': {
++ sqlite3_snprintf(30,&z[j],"%lld",
++ (i64)(x.iJD/1000 - 21086676*(i64)10000));
++ j += sqlite3Strlen30(&z[j]);
++ break;
++ }
++ case 'S': sqlite3_snprintf(3,&z[j],"%02d",(int)x.s); j+=2; break;
++ case 'w': {
++ z[j++] = (char)(((x.iJD+129600000)/86400000) % 7) + '0';
++ break;
++ }
++ case 'Y': {
++ sqlite3_snprintf(5,&z[j],"%04d",x.Y); j+=sqlite3Strlen30(&z[j]);
++ break;
++ }
++ default: z[j++] = '%'; break;
++ }
++ }
++ }
++ z[j] = 0;
++ sqlite3_result_text(context, z, -1,
++ z==zBuf ? SQLITE_TRANSIENT : SQLITE_DYNAMIC);
++}
++
++/*
++** current_time()
++**
++** This function returns the same value as time('now').
++*/
++static void ctimeFunc(
++ sqlite3_context *context,
++ int NotUsed,
++ sqlite3_value **NotUsed2
++){
++ UNUSED_PARAMETER2(NotUsed, NotUsed2);
++ timeFunc(context, 0, 0);
++}
++
++/*
++** current_date()
++**
++** This function returns the same value as date('now').
++*/
++static void cdateFunc(
++ sqlite3_context *context,
++ int NotUsed,
++ sqlite3_value **NotUsed2
++){
++ UNUSED_PARAMETER2(NotUsed, NotUsed2);
++ dateFunc(context, 0, 0);
++}
++
++/*
++** current_timestamp()
++**
++** This function returns the same value as datetime('now').
++*/
++static void ctimestampFunc(
++ sqlite3_context *context,
++ int NotUsed,
++ sqlite3_value **NotUsed2
++){
++ UNUSED_PARAMETER2(NotUsed, NotUsed2);
++ datetimeFunc(context, 0, 0);
++}
++#endif /* !defined(SQLITE_OMIT_DATETIME_FUNCS) */
++
++#ifdef SQLITE_OMIT_DATETIME_FUNCS
++/*
++** If the library is compiled to omit the full-scale date and time
++** handling (to get a smaller binary), the following minimal version
++** of the functions current_time(), current_date() and current_timestamp()
++** are included instead. This is to support column declarations that
++** include "DEFAULT CURRENT_TIME" etc.
++**
++** This function uses the C-library functions time(), gmtime()
++** and strftime(). The format string to pass to strftime() is supplied
++** as the user-data for the function.
++*/
++static void currentTimeFunc(
++ sqlite3_context *context,
++ int argc,
++ sqlite3_value **argv
++){
++ time_t t;
++ char *zFormat = (char *)sqlite3_user_data(context);
++ sqlite3 *db;
++ sqlite3_int64 iT;
++ struct tm *pTm;
++ struct tm sNow;
++ char zBuf[20];
++
++ UNUSED_PARAMETER(argc);
++ UNUSED_PARAMETER(argv);
++
++ iT = sqlite3StmtCurrentTime(context);
++ if( iT<=0 ) return;
++ t = iT/1000 - 10000*(sqlite3_int64)21086676;
++#if HAVE_GMTIME_R
++ pTm = gmtime_r(&t, &sNow);
++#else
++ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
++ pTm = gmtime(&t);
++ if( pTm ) memcpy(&sNow, pTm, sizeof(sNow));
++ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
++#endif
++ if( pTm ){
++ strftime(zBuf, 20, zFormat, &sNow);
++ sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
++ }
++}
++#endif
++
++/*
++** This function registered all of the above C functions as SQL
++** functions. This should be the only routine in this file with
++** external linkage.
++*/
++SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){
++ static SQLITE_WSD FuncDef aDateTimeFuncs[] = {
++#ifndef SQLITE_OMIT_DATETIME_FUNCS
++ FUNCTION(julianday, -1, 0, 0, juliandayFunc ),
++ FUNCTION(date, -1, 0, 0, dateFunc ),
++ FUNCTION(time, -1, 0, 0, timeFunc ),
++ FUNCTION(datetime, -1, 0, 0, datetimeFunc ),
++ FUNCTION(strftime, -1, 0, 0, strftimeFunc ),
++ FUNCTION(current_time, 0, 0, 0, ctimeFunc ),
++ FUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc),
++ FUNCTION(current_date, 0, 0, 0, cdateFunc ),
++#else
++ STR_FUNCTION(current_time, 0, "%H:%M:%S", 0, currentTimeFunc),
++ STR_FUNCTION(current_date, 0, "%Y-%m-%d", 0, currentTimeFunc),
++ STR_FUNCTION(current_timestamp, 0, "%Y-%m-%d %H:%M:%S", 0, currentTimeFunc),
++#endif
++ };
++ int i;
++ FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
++ FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aDateTimeFuncs);
++
++ for(i=0; i<ArraySize(aDateTimeFuncs); i++){
++ sqlite3FuncDefInsert(pHash, &aFunc[i]);
++ }
++}
++
++/************** End of date.c ************************************************/
++/************** Begin file os.c **********************************************/
++/*
++** 2005 November 29
++**
++** The author disclaims copyright to this source code. In place of
++** a legal notice, here is a blessing:
++**
++** May you do good and not evil.
++** May you find forgiveness for yourself and forgive others.
++** May you share freely, never taking more than you give.
++**
++******************************************************************************
++**
++** This file contains OS interface code that is common to all
++** architectures.
++*/
++#define _SQLITE_OS_C_ 1
++#undef _SQLITE_OS_C_
++
++/*
++** The default SQLite sqlite3_vfs implementations do not allocate
++** memory (actually, os_unix.c allocates a small amount of memory
++** from within OsOpen()), but some third-party implementations may.
++** So we test the effects of a malloc() failing and the sqlite3OsXXX()
++** function returning SQLITE_IOERR_NOMEM using the DO_OS_MALLOC_TEST macro.
++**
++** The following functions are instrumented for malloc() failure
++** testing:
++**
++** sqlite3OsRead()
++** sqlite3OsWrite()
++** sqlite3OsSync()
++** sqlite3OsFileSize()
++** sqlite3OsLock()
++** sqlite3OsCheckReservedLock()
++** sqlite3OsFileControl()
++** sqlite3OsShmMap()
++** sqlite3OsOpen()
++** sqlite3OsDelete()
++** sqlite3OsAccess()
++** sqlite3OsFullPathname()
++**
++*/
++#if defined(SQLITE_TEST)
++SQLITE_API int sqlite3_memdebug_vfs_oom_test = 1;
++ #define DO_OS_MALLOC_TEST(x) \
++ if (sqlite3_memdebug_vfs_oom_test && (!x || !sqlite3IsMemJournal(x))) { \
++ void *pTstAlloc = sqlite3Malloc(10); \
++ if (!pTstAlloc) return SQLITE_IOERR_NOMEM; \
++ sqlite3_free(pTstAlloc); \
++ }
++#else
++ #define DO_OS_MALLOC_TEST(x)
++#endif
++
++/*
++** The following routines are convenience wrappers around methods
++** of the sqlite3_file object. This is mostly just syntactic sugar. All
++** of this would be completely automatic if SQLite were coded using
++** C++ instead of plain old C.
++*/
++SQLITE_PRIVATE int sqlite3OsClose(sqlite3_file *pId){
++ int rc = SQLITE_OK;
++ if( pId->pMethods ){
++ rc = pId->pMethods->xClose(pId);
++ pId->pMethods = 0;
++ }
++ return rc;
++}
++SQLITE_PRIVATE int sqlite3OsRead(sqlite3_file *id, void *pBuf, int amt, i64 offset){
++ DO_OS_MALLOC_TEST(id);
++ return id->pMethods->xRead(id, pBuf, amt, offset);
++}
++SQLITE_PRIVATE int sqlite3OsWrite(sqlite3_file *id, const void *pBuf, int amt, i64 offset){
++ DO_OS_MALLOC_TEST(id);
++ return id->pMethods->xWrite(id, pBuf, amt, offset);
++}
++SQLITE_PRIVATE int sqlite3OsTruncate(sqlite3_file *id, i64 size){
++ return id->pMethods->xTruncate(id, size);
++}
++SQLITE_PRIVATE int sqlite3OsSync(sqlite3_file *id, int flags){
++ DO_OS_MALLOC_TEST(id);
++ return id->pMethods->xSync(id, flags);
++}
++SQLITE_PRIVATE int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){
++ DO_OS_MALLOC_TEST(id);
++ return id->pMethods->xFileSize(id, pSize);
++}
++SQLITE_PRIVATE int sqlite3OsLock(sqlite3_file *id, int lockType){
++ DO_OS_MALLOC_TEST(id);
++ return id->pMethods->xLock(id, lockType);
++}
++SQLITE_PRIVATE int sqlite3OsUnlock(sqlite3_file *id, int lockType){
++ return id->pMethods->xUnlock(id, lockType);
++}
++SQLITE_PRIVATE int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut){
++ DO_OS_MALLOC_TEST(id);
++ return id->pMethods->xCheckReservedLock(id, pResOut);
++}
++
++/*
++** Use sqlite3OsFileControl() when we are doing something that might fail
++** and we need to know about the failures. Use sqlite3OsFileControlHint()
++** when simply tossing information over the wall to the VFS and we do not
++** really care if the VFS receives and understands the information since it
++** is only a hint and can be safely ignored. The sqlite3OsFileControlHint()
++** routine has no return value since the return value would be meaningless.
++*/
++SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){
++#ifdef SQLITE_TEST
++ if( op!=SQLITE_FCNTL_COMMIT_PHASETWO ){
++ /* Faults are not injected into COMMIT_PHASETWO because, assuming SQLite
++ ** is using a regular VFS, it is called after the corresponding
++ ** transaction has been committed. Injecting a fault at this point
++ ** confuses the test scripts - the COMMIT comand returns SQLITE_NOMEM
++ ** but the transaction is committed anyway.
++ **
++ ** The core must call OsFileControl() though, not OsFileControlHint(),
++ ** as if a custom VFS (e.g. zipvfs) returns an error here, it probably
++ ** means the commit really has failed and an error should be returned
++ ** to the user. */
++ DO_OS_MALLOC_TEST(id);
++ }
++#endif
++ return id->pMethods->xFileControl(id, op, pArg);
++}
++SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file *id, int op, void *pArg){
++ (void)id->pMethods->xFileControl(id, op, pArg);
++}
++
++SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id){
++ int (*xSectorSize)(sqlite3_file*) = id->pMethods->xSectorSize;
++ return (xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE);
++}
++SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id){
++ return id->pMethods->xDeviceCharacteristics(id);
++}
++SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int offset, int n, int flags){
++ return id->pMethods->xShmLock(id, offset, n, flags);
++}
++SQLITE_PRIVATE void sqlite3OsShmBarrier(sqlite3_file *id){
++ id->pMethods->xShmBarrier(id);
++}
++SQLITE_PRIVATE int sqlite3OsShmUnmap(sqlite3_file *id, int deleteFlag){
++ return id->pMethods->xShmUnmap(id, deleteFlag);
++}
++SQLITE_PRIVATE int sqlite3OsShmMap(
++ sqlite3_file *id, /* Database file handle */
++ int iPage,
++ int pgsz,
++ int bExtend, /* True to extend file if necessary */
++ void volatile **pp /* OUT: Pointer to mapping */
++){
++ DO_OS_MALLOC_TEST(id);
++ return id->pMethods->xShmMap(id, iPage, pgsz, bExtend, pp);
++}
++
++#if SQLITE_MAX_MMAP_SIZE>0
++/* The real implementation of xFetch and xUnfetch */
++SQLITE_PRIVATE int sqlite3OsFetch(sqlite3_file *id, i64 iOff, int iAmt, void **pp){
++ DO_OS_MALLOC_TEST(id);
++ return id->pMethods->xFetch(id, iOff, iAmt, pp);
+ }
+ SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *id, i64 iOff, void *p){
+ return id->pMethods->xUnfetch(id, iOff, p);
+@@ -20088,7 +23720,7 @@
/*
** Include the primary Windows SDK header file.
*/
@@ -4055,7 +9035,7 @@
#ifdef __CYGWIN__
# include <sys/cygwin.h>
-@@ -24157,7 +27708,7 @@
+@@ -25328,7 +28960,7 @@
#include <sys/time.h>
#include <errno.h>
#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
@@ -4063,76 +9043,27895 @@
+/* # include <sys/mman.h> */
#endif
- #if SQLITE_ENABLE_LOCKING_STYLE || OS_VXWORKS
-@@ -47475,7 +51026,39 @@
+ #if SQLITE_ENABLE_LOCKING_STYLE
+@@ -33657,6275 +37289,5194 @@
+ #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
+ { "AreFileApisANSI", (SYSCALL)AreFileApisANSI, 0 },
+ #else
+- { "AreFileApisANSI", (SYSCALL)0, 0 },
+-#endif
+-
+-#ifndef osAreFileApisANSI
+-#define osAreFileApisANSI ((BOOL(WINAPI*)(VOID))aSyscall[0].pCurrent)
+-#endif
+-
+-#if SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE)
+- { "CharLowerW", (SYSCALL)CharLowerW, 0 },
+-#else
+- { "CharLowerW", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osCharLowerW ((LPWSTR(WINAPI*)(LPWSTR))aSyscall[1].pCurrent)
+-
+-#if SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE)
+- { "CharUpperW", (SYSCALL)CharUpperW, 0 },
+-#else
+- { "CharUpperW", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osCharUpperW ((LPWSTR(WINAPI*)(LPWSTR))aSyscall[2].pCurrent)
+-
+- { "CloseHandle", (SYSCALL)CloseHandle, 0 },
+-
+-#define osCloseHandle ((BOOL(WINAPI*)(HANDLE))aSyscall[3].pCurrent)
+-
+-#if defined(SQLITE_WIN32_HAS_ANSI)
+- { "CreateFileA", (SYSCALL)CreateFileA, 0 },
+-#else
+- { "CreateFileA", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osCreateFileA ((HANDLE(WINAPI*)(LPCSTR,DWORD,DWORD, \
+- LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[4].pCurrent)
+-
+-#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
+- { "CreateFileW", (SYSCALL)CreateFileW, 0 },
+-#else
+- { "CreateFileW", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osCreateFileW ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD, \
+- LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[5].pCurrent)
+-
+-#if (!SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_ANSI) && \
+- (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0))
+- { "CreateFileMappingA", (SYSCALL)CreateFileMappingA, 0 },
+-#else
+- { "CreateFileMappingA", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osCreateFileMappingA ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \
+- DWORD,DWORD,DWORD,LPCSTR))aSyscall[6].pCurrent)
+-
+-#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \
+- (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0))
+- { "CreateFileMappingW", (SYSCALL)CreateFileMappingW, 0 },
+-#else
+- { "CreateFileMappingW", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osCreateFileMappingW ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \
+- DWORD,DWORD,DWORD,LPCWSTR))aSyscall[7].pCurrent)
+-
+-#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
+- { "CreateMutexW", (SYSCALL)CreateMutexW, 0 },
+-#else
+- { "CreateMutexW", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osCreateMutexW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,BOOL, \
+- LPCWSTR))aSyscall[8].pCurrent)
+-
+-#if defined(SQLITE_WIN32_HAS_ANSI)
+- { "DeleteFileA", (SYSCALL)DeleteFileA, 0 },
+-#else
+- { "DeleteFileA", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osDeleteFileA ((BOOL(WINAPI*)(LPCSTR))aSyscall[9].pCurrent)
+-
+-#if defined(SQLITE_WIN32_HAS_WIDE)
+- { "DeleteFileW", (SYSCALL)DeleteFileW, 0 },
+-#else
+- { "DeleteFileW", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osDeleteFileW ((BOOL(WINAPI*)(LPCWSTR))aSyscall[10].pCurrent)
+-
+-#if SQLITE_OS_WINCE
+- { "FileTimeToLocalFileTime", (SYSCALL)FileTimeToLocalFileTime, 0 },
+-#else
+- { "FileTimeToLocalFileTime", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osFileTimeToLocalFileTime ((BOOL(WINAPI*)(CONST FILETIME*, \
+- LPFILETIME))aSyscall[11].pCurrent)
+-
+-#if SQLITE_OS_WINCE
+- { "FileTimeToSystemTime", (SYSCALL)FileTimeToSystemTime, 0 },
+-#else
+- { "FileTimeToSystemTime", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osFileTimeToSystemTime ((BOOL(WINAPI*)(CONST FILETIME*, \
+- LPSYSTEMTIME))aSyscall[12].pCurrent)
+-
+- { "FlushFileBuffers", (SYSCALL)FlushFileBuffers, 0 },
+-
+-#define osFlushFileBuffers ((BOOL(WINAPI*)(HANDLE))aSyscall[13].pCurrent)
+-
+-#if defined(SQLITE_WIN32_HAS_ANSI)
+- { "FormatMessageA", (SYSCALL)FormatMessageA, 0 },
+-#else
+- { "FormatMessageA", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osFormatMessageA ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPSTR, \
+- DWORD,va_list*))aSyscall[14].pCurrent)
+-
+-#if defined(SQLITE_WIN32_HAS_WIDE)
+- { "FormatMessageW", (SYSCALL)FormatMessageW, 0 },
+-#else
+- { "FormatMessageW", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osFormatMessageW ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPWSTR, \
+- DWORD,va_list*))aSyscall[15].pCurrent)
+-
+-#if !defined(SQLITE_OMIT_LOAD_EXTENSION)
+- { "FreeLibrary", (SYSCALL)FreeLibrary, 0 },
+-#else
+- { "FreeLibrary", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osFreeLibrary ((BOOL(WINAPI*)(HMODULE))aSyscall[16].pCurrent)
+-
+- { "GetCurrentProcessId", (SYSCALL)GetCurrentProcessId, 0 },
+-
+-#define osGetCurrentProcessId ((DWORD(WINAPI*)(VOID))aSyscall[17].pCurrent)
+-
+-#if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_ANSI)
+- { "GetDiskFreeSpaceA", (SYSCALL)GetDiskFreeSpaceA, 0 },
+-#else
+- { "GetDiskFreeSpaceA", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osGetDiskFreeSpaceA ((BOOL(WINAPI*)(LPCSTR,LPDWORD,LPDWORD,LPDWORD, \
+- LPDWORD))aSyscall[18].pCurrent)
+-
+-#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
+- { "GetDiskFreeSpaceW", (SYSCALL)GetDiskFreeSpaceW, 0 },
+-#else
+- { "GetDiskFreeSpaceW", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osGetDiskFreeSpaceW ((BOOL(WINAPI*)(LPCWSTR,LPDWORD,LPDWORD,LPDWORD, \
+- LPDWORD))aSyscall[19].pCurrent)
+-
+-#if defined(SQLITE_WIN32_HAS_ANSI)
+- { "GetFileAttributesA", (SYSCALL)GetFileAttributesA, 0 },
+-#else
+- { "GetFileAttributesA", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osGetFileAttributesA ((DWORD(WINAPI*)(LPCSTR))aSyscall[20].pCurrent)
+-
+-#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
+- { "GetFileAttributesW", (SYSCALL)GetFileAttributesW, 0 },
+-#else
+- { "GetFileAttributesW", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osGetFileAttributesW ((DWORD(WINAPI*)(LPCWSTR))aSyscall[21].pCurrent)
+-
+-#if defined(SQLITE_WIN32_HAS_WIDE)
+- { "GetFileAttributesExW", (SYSCALL)GetFileAttributesExW, 0 },
+-#else
+- { "GetFileAttributesExW", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osGetFileAttributesExW ((BOOL(WINAPI*)(LPCWSTR,GET_FILEEX_INFO_LEVELS, \
+- LPVOID))aSyscall[22].pCurrent)
+-
+-#if !SQLITE_OS_WINRT
+- { "GetFileSize", (SYSCALL)GetFileSize, 0 },
+-#else
+- { "GetFileSize", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osGetFileSize ((DWORD(WINAPI*)(HANDLE,LPDWORD))aSyscall[23].pCurrent)
+-
+-#if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_ANSI)
+- { "GetFullPathNameA", (SYSCALL)GetFullPathNameA, 0 },
+-#else
+- { "GetFullPathNameA", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osGetFullPathNameA ((DWORD(WINAPI*)(LPCSTR,DWORD,LPSTR, \
+- LPSTR*))aSyscall[24].pCurrent)
+-
+-#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
+- { "GetFullPathNameW", (SYSCALL)GetFullPathNameW, 0 },
+-#else
+- { "GetFullPathNameW", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osGetFullPathNameW ((DWORD(WINAPI*)(LPCWSTR,DWORD,LPWSTR, \
+- LPWSTR*))aSyscall[25].pCurrent)
+-
+- { "GetLastError", (SYSCALL)GetLastError, 0 },
+-
+-#define osGetLastError ((DWORD(WINAPI*)(VOID))aSyscall[26].pCurrent)
+-
+-#if !defined(SQLITE_OMIT_LOAD_EXTENSION)
+-#if SQLITE_OS_WINCE
+- /* The GetProcAddressA() routine is only available on Windows CE. */
+- { "GetProcAddressA", (SYSCALL)GetProcAddressA, 0 },
+-#else
+- /* All other Windows platforms expect GetProcAddress() to take
+- ** an ANSI string regardless of the _UNICODE setting */
+- { "GetProcAddressA", (SYSCALL)GetProcAddress, 0 },
+-#endif
+-#else
+- { "GetProcAddressA", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osGetProcAddressA ((FARPROC(WINAPI*)(HMODULE, \
+- LPCSTR))aSyscall[27].pCurrent)
+-
+-#if !SQLITE_OS_WINRT
+- { "GetSystemInfo", (SYSCALL)GetSystemInfo, 0 },
+-#else
+- { "GetSystemInfo", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osGetSystemInfo ((VOID(WINAPI*)(LPSYSTEM_INFO))aSyscall[28].pCurrent)
+-
+- { "GetSystemTime", (SYSCALL)GetSystemTime, 0 },
+-
+-#define osGetSystemTime ((VOID(WINAPI*)(LPSYSTEMTIME))aSyscall[29].pCurrent)
+-
+-#if !SQLITE_OS_WINCE
+- { "GetSystemTimeAsFileTime", (SYSCALL)GetSystemTimeAsFileTime, 0 },
+-#else
+- { "GetSystemTimeAsFileTime", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osGetSystemTimeAsFileTime ((VOID(WINAPI*)( \
+- LPFILETIME))aSyscall[30].pCurrent)
+-
+-#if defined(SQLITE_WIN32_HAS_ANSI)
+- { "GetTempPathA", (SYSCALL)GetTempPathA, 0 },
+-#else
+- { "GetTempPathA", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osGetTempPathA ((DWORD(WINAPI*)(DWORD,LPSTR))aSyscall[31].pCurrent)
+-
+-#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
+- { "GetTempPathW", (SYSCALL)GetTempPathW, 0 },
+-#else
+- { "GetTempPathW", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osGetTempPathW ((DWORD(WINAPI*)(DWORD,LPWSTR))aSyscall[32].pCurrent)
+-
+-#if !SQLITE_OS_WINRT
+- { "GetTickCount", (SYSCALL)GetTickCount, 0 },
+-#else
+- { "GetTickCount", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osGetTickCount ((DWORD(WINAPI*)(VOID))aSyscall[33].pCurrent)
+-
+-#if defined(SQLITE_WIN32_HAS_ANSI) && defined(SQLITE_WIN32_GETVERSIONEX) && \
+- SQLITE_WIN32_GETVERSIONEX
+- { "GetVersionExA", (SYSCALL)GetVersionExA, 0 },
+-#else
+- { "GetVersionExA", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osGetVersionExA ((BOOL(WINAPI*)( \
+- LPOSVERSIONINFOA))aSyscall[34].pCurrent)
+-
+-#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \
+- defined(SQLITE_WIN32_GETVERSIONEX) && SQLITE_WIN32_GETVERSIONEX
+- { "GetVersionExW", (SYSCALL)GetVersionExW, 0 },
+-#else
+- { "GetVersionExW", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osGetVersionExW ((BOOL(WINAPI*)( \
+- LPOSVERSIONINFOW))aSyscall[35].pCurrent)
+-
+- { "HeapAlloc", (SYSCALL)HeapAlloc, 0 },
+-
+-#define osHeapAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD, \
+- SIZE_T))aSyscall[36].pCurrent)
+-
+-#if !SQLITE_OS_WINRT
+- { "HeapCreate", (SYSCALL)HeapCreate, 0 },
+-#else
+- { "HeapCreate", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osHeapCreate ((HANDLE(WINAPI*)(DWORD,SIZE_T, \
+- SIZE_T))aSyscall[37].pCurrent)
+-
+-#if !SQLITE_OS_WINRT
+- { "HeapDestroy", (SYSCALL)HeapDestroy, 0 },
+-#else
+- { "HeapDestroy", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osHeapDestroy ((BOOL(WINAPI*)(HANDLE))aSyscall[38].pCurrent)
+-
+- { "HeapFree", (SYSCALL)HeapFree, 0 },
+-
+-#define osHeapFree ((BOOL(WINAPI*)(HANDLE,DWORD,LPVOID))aSyscall[39].pCurrent)
+-
+- { "HeapReAlloc", (SYSCALL)HeapReAlloc, 0 },
+-
+-#define osHeapReAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD,LPVOID, \
+- SIZE_T))aSyscall[40].pCurrent)
+-
+- { "HeapSize", (SYSCALL)HeapSize, 0 },
+-
+-#define osHeapSize ((SIZE_T(WINAPI*)(HANDLE,DWORD, \
+- LPCVOID))aSyscall[41].pCurrent)
+-
+-#if !SQLITE_OS_WINRT
+- { "HeapValidate", (SYSCALL)HeapValidate, 0 },
+-#else
+- { "HeapValidate", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osHeapValidate ((BOOL(WINAPI*)(HANDLE,DWORD, \
+- LPCVOID))aSyscall[42].pCurrent)
+-
+-#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
+- { "HeapCompact", (SYSCALL)HeapCompact, 0 },
+-#else
+- { "HeapCompact", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osHeapCompact ((UINT(WINAPI*)(HANDLE,DWORD))aSyscall[43].pCurrent)
+-
+-#if defined(SQLITE_WIN32_HAS_ANSI) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
+- { "LoadLibraryA", (SYSCALL)LoadLibraryA, 0 },
+-#else
+- { "LoadLibraryA", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osLoadLibraryA ((HMODULE(WINAPI*)(LPCSTR))aSyscall[44].pCurrent)
+-
+-#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \
+- !defined(SQLITE_OMIT_LOAD_EXTENSION)
+- { "LoadLibraryW", (SYSCALL)LoadLibraryW, 0 },
+-#else
+- { "LoadLibraryW", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osLoadLibraryW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[45].pCurrent)
+-
+-#if !SQLITE_OS_WINRT
+- { "LocalFree", (SYSCALL)LocalFree, 0 },
+-#else
+- { "LocalFree", (SYSCALL)0, 0 },
+-#endif
+-
+-#define osLocalFree ((HLOCAL(WINAPI*)(HLOCAL))aSyscall[46].pCurrent)
+-
+-#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
+- { "LockFile", (SYSCALL)LockFile, 0 },
+-#else
+- { "LockFile", (SYSCALL)0, 0 },
++ { "AreFileApisANSI", (SYSCALL)0, 0 },
+ #endif
+
+-#ifndef osLockFile
+-#define osLockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
+- DWORD))aSyscall[47].pCurrent)
++#ifndef osAreFileApisANSI
++#define osAreFileApisANSI ((BOOL(WINAPI*)(VOID))aSyscall[0].pCurrent)
+ #endif
+
+-#if !SQLITE_OS_WINCE
+- { "LockFileEx", (SYSCALL)LockFileEx, 0 },
++#if SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE)
++ { "CharLowerW", (SYSCALL)CharLowerW, 0 },
+ #else
+- { "LockFileEx", (SYSCALL)0, 0 },
++ { "CharLowerW", (SYSCALL)0, 0 },
+ #endif
+
+-#ifndef osLockFileEx
+-#define osLockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD,DWORD, \
+- LPOVERLAPPED))aSyscall[48].pCurrent)
+-#endif
++#define osCharLowerW ((LPWSTR(WINAPI*)(LPWSTR))aSyscall[1].pCurrent)
+
+-#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && \
+- (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0))
+- { "MapViewOfFile", (SYSCALL)MapViewOfFile, 0 },
++#if SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE)
++ { "CharUpperW", (SYSCALL)CharUpperW, 0 },
+ #else
+- { "MapViewOfFile", (SYSCALL)0, 0 },
++ { "CharUpperW", (SYSCALL)0, 0 },
+ #endif
+
+-#define osMapViewOfFile ((LPVOID(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
+- SIZE_T))aSyscall[49].pCurrent)
+-
+- { "MultiByteToWideChar", (SYSCALL)MultiByteToWideChar, 0 },
+-
+-#define osMultiByteToWideChar ((int(WINAPI*)(UINT,DWORD,LPCSTR,int,LPWSTR, \
+- int))aSyscall[50].pCurrent)
+-
+- { "QueryPerformanceCounter", (SYSCALL)QueryPerformanceCounter, 0 },
+-
+-#define osQueryPerformanceCounter ((BOOL(WINAPI*)( \
+- LARGE_INTEGER*))aSyscall[51].pCurrent)
+-
+- { "ReadFile", (SYSCALL)ReadFile, 0 },
+-
+-#define osReadFile ((BOOL(WINAPI*)(HANDLE,LPVOID,DWORD,LPDWORD, \
+- LPOVERLAPPED))aSyscall[52].pCurrent)
++#define osCharUpperW ((LPWSTR(WINAPI*)(LPWSTR))aSyscall[2].pCurrent)
+
+- { "SetEndOfFile", (SYSCALL)SetEndOfFile, 0 },
++ { "CloseHandle", (SYSCALL)CloseHandle, 0 },
+
+-#define osSetEndOfFile ((BOOL(WINAPI*)(HANDLE))aSyscall[53].pCurrent)
++#define osCloseHandle ((BOOL(WINAPI*)(HANDLE))aSyscall[3].pCurrent)
+
+-#if !SQLITE_OS_WINRT
+- { "SetFilePointer", (SYSCALL)SetFilePointer, 0 },
++#if defined(SQLITE_WIN32_HAS_ANSI)
++ { "CreateFileA", (SYSCALL)CreateFileA, 0 },
+ #else
+- { "SetFilePointer", (SYSCALL)0, 0 },
++ { "CreateFileA", (SYSCALL)0, 0 },
+ #endif
+
+-#define osSetFilePointer ((DWORD(WINAPI*)(HANDLE,LONG,PLONG, \
+- DWORD))aSyscall[54].pCurrent)
++#define osCreateFileA ((HANDLE(WINAPI*)(LPCSTR,DWORD,DWORD, \
++ LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[4].pCurrent)
+
+-#if !SQLITE_OS_WINRT
+- { "Sleep", (SYSCALL)Sleep, 0 },
++#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
++ { "CreateFileW", (SYSCALL)CreateFileW, 0 },
+ #else
+- { "Sleep", (SYSCALL)0, 0 },
++ { "CreateFileW", (SYSCALL)0, 0 },
+ #endif
+
+-#define osSleep ((VOID(WINAPI*)(DWORD))aSyscall[55].pCurrent)
+-
+- { "SystemTimeToFileTime", (SYSCALL)SystemTimeToFileTime, 0 },
+-
+-#define osSystemTimeToFileTime ((BOOL(WINAPI*)(CONST SYSTEMTIME*, \
+- LPFILETIME))aSyscall[56].pCurrent)
++#define osCreateFileW ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD, \
++ LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[5].pCurrent)
+
+-#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
+- { "UnlockFile", (SYSCALL)UnlockFile, 0 },
++#if (!SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_ANSI) && \
++ (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0))
++ { "CreateFileMappingA", (SYSCALL)CreateFileMappingA, 0 },
+ #else
+- { "UnlockFile", (SYSCALL)0, 0 },
++ { "CreateFileMappingA", (SYSCALL)0, 0 },
+ #endif
+
+-#ifndef osUnlockFile
+-#define osUnlockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
+- DWORD))aSyscall[57].pCurrent)
+-#endif
++#define osCreateFileMappingA ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \
++ DWORD,DWORD,DWORD,LPCSTR))aSyscall[6].pCurrent)
+
+-#if !SQLITE_OS_WINCE
+- { "UnlockFileEx", (SYSCALL)UnlockFileEx, 0 },
++#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \
++ (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0))
++ { "CreateFileMappingW", (SYSCALL)CreateFileMappingW, 0 },
+ #else
+- { "UnlockFileEx", (SYSCALL)0, 0 },
++ { "CreateFileMappingW", (SYSCALL)0, 0 },
+ #endif
+
+-#define osUnlockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
+- LPOVERLAPPED))aSyscall[58].pCurrent)
++#define osCreateFileMappingW ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \
++ DWORD,DWORD,DWORD,LPCWSTR))aSyscall[7].pCurrent)
+
+-#if SQLITE_OS_WINCE || !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
+- { "UnmapViewOfFile", (SYSCALL)UnmapViewOfFile, 0 },
++#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
++ { "CreateMutexW", (SYSCALL)CreateMutexW, 0 },
+ #else
+- { "UnmapViewOfFile", (SYSCALL)0, 0 },
++ { "CreateMutexW", (SYSCALL)0, 0 },
+ #endif
+
+-#define osUnmapViewOfFile ((BOOL(WINAPI*)(LPCVOID))aSyscall[59].pCurrent)
+-
+- { "WideCharToMultiByte", (SYSCALL)WideCharToMultiByte, 0 },
+-
+-#define osWideCharToMultiByte ((int(WINAPI*)(UINT,DWORD,LPCWSTR,int,LPSTR,int, \
+- LPCSTR,LPBOOL))aSyscall[60].pCurrent)
+-
+- { "WriteFile", (SYSCALL)WriteFile, 0 },
+-
+-#define osWriteFile ((BOOL(WINAPI*)(HANDLE,LPCVOID,DWORD,LPDWORD, \
+- LPOVERLAPPED))aSyscall[61].pCurrent)
++#define osCreateMutexW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,BOOL, \
++ LPCWSTR))aSyscall[8].pCurrent)
+
+-#if SQLITE_OS_WINRT
+- { "CreateEventExW", (SYSCALL)CreateEventExW, 0 },
++#if defined(SQLITE_WIN32_HAS_ANSI)
++ { "DeleteFileA", (SYSCALL)DeleteFileA, 0 },
+ #else
+- { "CreateEventExW", (SYSCALL)0, 0 },
++ { "DeleteFileA", (SYSCALL)0, 0 },
+ #endif
+
+-#define osCreateEventExW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,LPCWSTR, \
+- DWORD,DWORD))aSyscall[62].pCurrent)
++#define osDeleteFileA ((BOOL(WINAPI*)(LPCSTR))aSyscall[9].pCurrent)
+
+-#if !SQLITE_OS_WINRT
+- { "WaitForSingleObject", (SYSCALL)WaitForSingleObject, 0 },
++#if defined(SQLITE_WIN32_HAS_WIDE)
++ { "DeleteFileW", (SYSCALL)DeleteFileW, 0 },
+ #else
+- { "WaitForSingleObject", (SYSCALL)0, 0 },
++ { "DeleteFileW", (SYSCALL)0, 0 },
+ #endif
+
+-#define osWaitForSingleObject ((DWORD(WINAPI*)(HANDLE, \
+- DWORD))aSyscall[63].pCurrent)
++#define osDeleteFileW ((BOOL(WINAPI*)(LPCWSTR))aSyscall[10].pCurrent)
+
+-#if !SQLITE_OS_WINCE
+- { "WaitForSingleObjectEx", (SYSCALL)WaitForSingleObjectEx, 0 },
++#if SQLITE_OS_WINCE
++ { "FileTimeToLocalFileTime", (SYSCALL)FileTimeToLocalFileTime, 0 },
+ #else
+- { "WaitForSingleObjectEx", (SYSCALL)0, 0 },
++ { "FileTimeToLocalFileTime", (SYSCALL)0, 0 },
+ #endif
+
+-#define osWaitForSingleObjectEx ((DWORD(WINAPI*)(HANDLE,DWORD, \
+- BOOL))aSyscall[64].pCurrent)
++#define osFileTimeToLocalFileTime ((BOOL(WINAPI*)(CONST FILETIME*, \
++ LPFILETIME))aSyscall[11].pCurrent)
+
+-#if SQLITE_OS_WINRT
+- { "SetFilePointerEx", (SYSCALL)SetFilePointerEx, 0 },
++#if SQLITE_OS_WINCE
++ { "FileTimeToSystemTime", (SYSCALL)FileTimeToSystemTime, 0 },
+ #else
+- { "SetFilePointerEx", (SYSCALL)0, 0 },
++ { "FileTimeToSystemTime", (SYSCALL)0, 0 },
+ #endif
+
+-#define osSetFilePointerEx ((BOOL(WINAPI*)(HANDLE,LARGE_INTEGER, \
+- PLARGE_INTEGER,DWORD))aSyscall[65].pCurrent)
++#define osFileTimeToSystemTime ((BOOL(WINAPI*)(CONST FILETIME*, \
++ LPSYSTEMTIME))aSyscall[12].pCurrent)
+
+-#if SQLITE_OS_WINRT
+- { "GetFileInformationByHandleEx", (SYSCALL)GetFileInformationByHandleEx, 0 },
+-#else
+- { "GetFileInformationByHandleEx", (SYSCALL)0, 0 },
+-#endif
++ { "FlushFileBuffers", (SYSCALL)FlushFileBuffers, 0 },
+
+-#define osGetFileInformationByHandleEx ((BOOL(WINAPI*)(HANDLE, \
+- FILE_INFO_BY_HANDLE_CLASS,LPVOID,DWORD))aSyscall[66].pCurrent)
++#define osFlushFileBuffers ((BOOL(WINAPI*)(HANDLE))aSyscall[13].pCurrent)
+
+-#if SQLITE_OS_WINRT && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)
+- { "MapViewOfFileFromApp", (SYSCALL)MapViewOfFileFromApp, 0 },
++#if defined(SQLITE_WIN32_HAS_ANSI)
++ { "FormatMessageA", (SYSCALL)FormatMessageA, 0 },
+ #else
+- { "MapViewOfFileFromApp", (SYSCALL)0, 0 },
++ { "FormatMessageA", (SYSCALL)0, 0 },
+ #endif
+
+-#define osMapViewOfFileFromApp ((LPVOID(WINAPI*)(HANDLE,ULONG,ULONG64, \
+- SIZE_T))aSyscall[67].pCurrent)
++#define osFormatMessageA ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPSTR, \
++ DWORD,va_list*))aSyscall[14].pCurrent)
+
+-#if SQLITE_OS_WINRT
+- { "CreateFile2", (SYSCALL)CreateFile2, 0 },
++#if defined(SQLITE_WIN32_HAS_WIDE)
++ { "FormatMessageW", (SYSCALL)FormatMessageW, 0 },
+ #else
+- { "CreateFile2", (SYSCALL)0, 0 },
++ { "FormatMessageW", (SYSCALL)0, 0 },
+ #endif
+
+-#define osCreateFile2 ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD,DWORD, \
+- LPCREATEFILE2_EXTENDED_PARAMETERS))aSyscall[68].pCurrent)
++#define osFormatMessageW ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPWSTR, \
++ DWORD,va_list*))aSyscall[15].pCurrent)
+
+-#if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_LOAD_EXTENSION)
+- { "LoadPackagedLibrary", (SYSCALL)LoadPackagedLibrary, 0 },
++#if !defined(SQLITE_OMIT_LOAD_EXTENSION)
++ { "FreeLibrary", (SYSCALL)FreeLibrary, 0 },
+ #else
+- { "LoadPackagedLibrary", (SYSCALL)0, 0 },
++ { "FreeLibrary", (SYSCALL)0, 0 },
+ #endif
+
+-#define osLoadPackagedLibrary ((HMODULE(WINAPI*)(LPCWSTR, \
+- DWORD))aSyscall[69].pCurrent)
++#define osFreeLibrary ((BOOL(WINAPI*)(HMODULE))aSyscall[16].pCurrent)
+
+-#if SQLITE_OS_WINRT
+- { "GetTickCount64", (SYSCALL)GetTickCount64, 0 },
+-#else
+- { "GetTickCount64", (SYSCALL)0, 0 },
+-#endif
++ { "GetCurrentProcessId", (SYSCALL)GetCurrentProcessId, 0 },
+
+-#define osGetTickCount64 ((ULONGLONG(WINAPI*)(VOID))aSyscall[70].pCurrent)
++#define osGetCurrentProcessId ((DWORD(WINAPI*)(VOID))aSyscall[17].pCurrent)
+
+-#if SQLITE_OS_WINRT
+- { "GetNativeSystemInfo", (SYSCALL)GetNativeSystemInfo, 0 },
++#if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_ANSI)
++ { "GetDiskFreeSpaceA", (SYSCALL)GetDiskFreeSpaceA, 0 },
+ #else
+- { "GetNativeSystemInfo", (SYSCALL)0, 0 },
++ { "GetDiskFreeSpaceA", (SYSCALL)0, 0 },
+ #endif
+
+-#define osGetNativeSystemInfo ((VOID(WINAPI*)( \
+- LPSYSTEM_INFO))aSyscall[71].pCurrent)
++#define osGetDiskFreeSpaceA ((BOOL(WINAPI*)(LPCSTR,LPDWORD,LPDWORD,LPDWORD, \
++ LPDWORD))aSyscall[18].pCurrent)
+
+-#if defined(SQLITE_WIN32_HAS_ANSI)
+- { "OutputDebugStringA", (SYSCALL)OutputDebugStringA, 0 },
++#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
++ { "GetDiskFreeSpaceW", (SYSCALL)GetDiskFreeSpaceW, 0 },
+ #else
+- { "OutputDebugStringA", (SYSCALL)0, 0 },
++ { "GetDiskFreeSpaceW", (SYSCALL)0, 0 },
+ #endif
+
+-#define osOutputDebugStringA ((VOID(WINAPI*)(LPCSTR))aSyscall[72].pCurrent)
++#define osGetDiskFreeSpaceW ((BOOL(WINAPI*)(LPCWSTR,LPDWORD,LPDWORD,LPDWORD, \
++ LPDWORD))aSyscall[19].pCurrent)
+
+-#if defined(SQLITE_WIN32_HAS_WIDE)
+- { "OutputDebugStringW", (SYSCALL)OutputDebugStringW, 0 },
++#if defined(SQLITE_WIN32_HAS_ANSI)
++ { "GetFileAttributesA", (SYSCALL)GetFileAttributesA, 0 },
+ #else
+- { "OutputDebugStringW", (SYSCALL)0, 0 },
++ { "GetFileAttributesA", (SYSCALL)0, 0 },
+ #endif
+
+-#define osOutputDebugStringW ((VOID(WINAPI*)(LPCWSTR))aSyscall[73].pCurrent)
+-
+- { "GetProcessHeap", (SYSCALL)GetProcessHeap, 0 },
+-
+-#define osGetProcessHeap ((HANDLE(WINAPI*)(VOID))aSyscall[74].pCurrent)
++#define osGetFileAttributesA ((DWORD(WINAPI*)(LPCSTR))aSyscall[20].pCurrent)
+
+-#if SQLITE_OS_WINRT && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)
+- { "CreateFileMappingFromApp", (SYSCALL)CreateFileMappingFromApp, 0 },
++#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
++ { "GetFileAttributesW", (SYSCALL)GetFileAttributesW, 0 },
+ #else
+- { "CreateFileMappingFromApp", (SYSCALL)0, 0 },
++ { "GetFileAttributesW", (SYSCALL)0, 0 },
+ #endif
+
+-#define osCreateFileMappingFromApp ((HANDLE(WINAPI*)(HANDLE, \
+- LPSECURITY_ATTRIBUTES,ULONG,ULONG64,LPCWSTR))aSyscall[75].pCurrent)
+-
+-/*
+-** NOTE: On some sub-platforms, the InterlockedCompareExchange "function"
+-** is really just a macro that uses a compiler intrinsic (e.g. x64).
+-** So do not try to make this is into a redefinable interface.
+-*/
+-#if defined(InterlockedCompareExchange)
+- { "InterlockedCompareExchange", (SYSCALL)0, 0 },
++#define osGetFileAttributesW ((DWORD(WINAPI*)(LPCWSTR))aSyscall[21].pCurrent)
+
+-#define osInterlockedCompareExchange InterlockedCompareExchange
++#if defined(SQLITE_WIN32_HAS_WIDE)
++ { "GetFileAttributesExW", (SYSCALL)GetFileAttributesExW, 0 },
+ #else
+- { "InterlockedCompareExchange", (SYSCALL)InterlockedCompareExchange, 0 },
++ { "GetFileAttributesExW", (SYSCALL)0, 0 },
++#endif
+
+-#define osInterlockedCompareExchange ((LONG(WINAPI*)(LONG \
+- SQLITE_WIN32_VOLATILE*, LONG,LONG))aSyscall[76].pCurrent)
+-#endif /* defined(InterlockedCompareExchange) */
++#define osGetFileAttributesExW ((BOOL(WINAPI*)(LPCWSTR,GET_FILEEX_INFO_LEVELS, \
++ LPVOID))aSyscall[22].pCurrent)
+
+-#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID
+- { "UuidCreate", (SYSCALL)UuidCreate, 0 },
++#if !SQLITE_OS_WINRT
++ { "GetFileSize", (SYSCALL)GetFileSize, 0 },
+ #else
+- { "UuidCreate", (SYSCALL)0, 0 },
++ { "GetFileSize", (SYSCALL)0, 0 },
+ #endif
+
+-#define osUuidCreate ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[77].pCurrent)
++#define osGetFileSize ((DWORD(WINAPI*)(HANDLE,LPDWORD))aSyscall[23].pCurrent)
+
+-#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID
+- { "UuidCreateSequential", (SYSCALL)UuidCreateSequential, 0 },
++#if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_ANSI)
++ { "GetFullPathNameA", (SYSCALL)GetFullPathNameA, 0 },
+ #else
+- { "UuidCreateSequential", (SYSCALL)0, 0 },
++ { "GetFullPathNameA", (SYSCALL)0, 0 },
+ #endif
+
+-#define osUuidCreateSequential \
+- ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[78].pCurrent)
++#define osGetFullPathNameA ((DWORD(WINAPI*)(LPCSTR,DWORD,LPSTR, \
++ LPSTR*))aSyscall[24].pCurrent)
+
+-#if !defined(SQLITE_NO_SYNC) && SQLITE_MAX_MMAP_SIZE>0
+- { "FlushViewOfFile", (SYSCALL)FlushViewOfFile, 0 },
++#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
++ { "GetFullPathNameW", (SYSCALL)GetFullPathNameW, 0 },
+ #else
+- { "FlushViewOfFile", (SYSCALL)0, 0 },
++ { "GetFullPathNameW", (SYSCALL)0, 0 },
+ #endif
+
+-#define osFlushViewOfFile \
+- ((BOOL(WINAPI*)(LPCVOID,SIZE_T))aSyscall[79].pCurrent)
++#define osGetFullPathNameW ((DWORD(WINAPI*)(LPCWSTR,DWORD,LPWSTR, \
++ LPWSTR*))aSyscall[25].pCurrent)
+
+-}; /* End of the overrideable system calls */
++ { "GetLastError", (SYSCALL)GetLastError, 0 },
+
+-/*
+-** This is the xSetSystemCall() method of sqlite3_vfs for all of the
+-** "win32" VFSes. Return SQLITE_OK opon successfully updating the
+-** system call pointer, or SQLITE_NOTFOUND if there is no configurable
+-** system call named zName.
+-*/
+-static int winSetSystemCall(
+- sqlite3_vfs *pNotUsed, /* The VFS pointer. Not used */
+- const char *zName, /* Name of system call to override */
+- sqlite3_syscall_ptr pNewFunc /* Pointer to new system call value */
+-){
+- unsigned int i;
+- int rc = SQLITE_NOTFOUND;
++#define osGetLastError ((DWORD(WINAPI*)(VOID))aSyscall[26].pCurrent)
+
+- UNUSED_PARAMETER(pNotUsed);
+- if( zName==0 ){
+- /* If no zName is given, restore all system calls to their default
+- ** settings and return NULL
+- */
+- rc = SQLITE_OK;
+- for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
+- if( aSyscall[i].pDefault ){
+- aSyscall[i].pCurrent = aSyscall[i].pDefault;
+- }
+- }
+- }else{
+- /* If zName is specified, operate on only the one system call
+- ** specified.
+- */
+- for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
+- if( strcmp(zName, aSyscall[i].zName)==0 ){
+- if( aSyscall[i].pDefault==0 ){
+- aSyscall[i].pDefault = aSyscall[i].pCurrent;
+- }
+- rc = SQLITE_OK;
+- if( pNewFunc==0 ) pNewFunc = aSyscall[i].pDefault;
+- aSyscall[i].pCurrent = pNewFunc;
+- break;
+- }
+- }
+- }
+- return rc;
+-}
++#if !defined(SQLITE_OMIT_LOAD_EXTENSION)
++#if SQLITE_OS_WINCE
++ /* The GetProcAddressA() routine is only available on Windows CE. */
++ { "GetProcAddressA", (SYSCALL)GetProcAddressA, 0 },
++#else
++ /* All other Windows platforms expect GetProcAddress() to take
++ ** an ANSI string regardless of the _UNICODE setting */
++ { "GetProcAddressA", (SYSCALL)GetProcAddress, 0 },
++#endif
++#else
++ { "GetProcAddressA", (SYSCALL)0, 0 },
++#endif
+
+-/*
+-** Return the value of a system call. Return NULL if zName is not a
+-** recognized system call name. NULL is also returned if the system call
+-** is currently undefined.
+-*/
+-static sqlite3_syscall_ptr winGetSystemCall(
+- sqlite3_vfs *pNotUsed,
+- const char *zName
+-){
+- unsigned int i;
++#define osGetProcAddressA ((FARPROC(WINAPI*)(HMODULE, \
++ LPCSTR))aSyscall[27].pCurrent)
+
+- UNUSED_PARAMETER(pNotUsed);
+- for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
+- if( strcmp(zName, aSyscall[i].zName)==0 ) return aSyscall[i].pCurrent;
+- }
+- return 0;
+-}
++#if !SQLITE_OS_WINRT
++ { "GetSystemInfo", (SYSCALL)GetSystemInfo, 0 },
++#else
++ { "GetSystemInfo", (SYSCALL)0, 0 },
++#endif
+
+-/*
+-** Return the name of the first system call after zName. If zName==NULL
+-** then return the name of the first system call. Return NULL if zName
+-** is the last system call or if zName is not the name of a valid
+-** system call.
+-*/
+-static const char *winNextSystemCall(sqlite3_vfs *p, const char *zName){
+- int i = -1;
++#define osGetSystemInfo ((VOID(WINAPI*)(LPSYSTEM_INFO))aSyscall[28].pCurrent)
+
+- UNUSED_PARAMETER(p);
+- if( zName ){
+- for(i=0; i<ArraySize(aSyscall)-1; i++){
+- if( strcmp(zName, aSyscall[i].zName)==0 ) break;
+- }
+- }
+- for(i++; i<ArraySize(aSyscall); i++){
+- if( aSyscall[i].pCurrent!=0 ) return aSyscall[i].zName;
+- }
+- return 0;
+-}
++ { "GetSystemTime", (SYSCALL)GetSystemTime, 0 },
+
+-#ifdef SQLITE_WIN32_MALLOC
+-/*
+-** If a Win32 native heap has been configured, this function will attempt to
+-** compact it. Upon success, SQLITE_OK will be returned. Upon failure, one
+-** of SQLITE_NOMEM, SQLITE_ERROR, or SQLITE_NOTFOUND will be returned. The
+-** "pnLargest" argument, if non-zero, will be used to return the size of the
+-** largest committed free block in the heap, in bytes.
+-*/
+-SQLITE_API int SQLITE_STDCALL sqlite3_win32_compact_heap(LPUINT pnLargest){
+- int rc = SQLITE_OK;
+- UINT nLargest = 0;
+- HANDLE hHeap;
++#define osGetSystemTime ((VOID(WINAPI*)(LPSYSTEMTIME))aSyscall[29].pCurrent)
+
+- winMemAssertMagic();
+- hHeap = winMemGetHeap();
+- assert( hHeap!=0 );
+- assert( hHeap!=INVALID_HANDLE_VALUE );
+-#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE)
+- assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
+-#endif
+-#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
+- if( (nLargest=osHeapCompact(hHeap, SQLITE_WIN32_HEAP_FLAGS))==0 ){
+- DWORD lastErrno = osGetLastError();
+- if( lastErrno==NO_ERROR ){
+- sqlite3_log(SQLITE_NOMEM, "failed to HeapCompact (no space), heap=%p",
+- (void*)hHeap);
+- rc = SQLITE_NOMEM;
+- }else{
+- sqlite3_log(SQLITE_ERROR, "failed to HeapCompact (%lu), heap=%p",
+- osGetLastError(), (void*)hHeap);
+- rc = SQLITE_ERROR;
+- }
+- }
++#if !SQLITE_OS_WINCE
++ { "GetSystemTimeAsFileTime", (SYSCALL)GetSystemTimeAsFileTime, 0 },
+ #else
+- sqlite3_log(SQLITE_NOTFOUND, "failed to HeapCompact, heap=%p",
+- (void*)hHeap);
+- rc = SQLITE_NOTFOUND;
++ { "GetSystemTimeAsFileTime", (SYSCALL)0, 0 },
+ #endif
+- if( pnLargest ) *pnLargest = nLargest;
+- return rc;
+-}
+-
+-/*
+-** If a Win32 native heap has been configured, this function will attempt to
+-** destroy and recreate it. If the Win32 native heap is not isolated and/or
+-** the sqlite3_memory_used() function does not return zero, SQLITE_BUSY will
+-** be returned and no changes will be made to the Win32 native heap.
+-*/
+-SQLITE_API int SQLITE_STDCALL sqlite3_win32_reset_heap(){
+- int rc;
+- MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */
+- MUTEX_LOGIC( sqlite3_mutex *pMem; ) /* The memsys static mutex */
+- MUTEX_LOGIC( pMaster = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); )
+- MUTEX_LOGIC( pMem = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM); )
+- sqlite3_mutex_enter(pMaster);
+- sqlite3_mutex_enter(pMem);
+- winMemAssertMagic();
+- if( winMemGetHeap()!=NULL && winMemGetOwned() && sqlite3_memory_used()==0 ){
+- /*
+- ** At this point, there should be no outstanding memory allocations on
+- ** the heap. Also, since both the master and memsys locks are currently
+- ** being held by us, no other function (i.e. from another thread) should
+- ** be able to even access the heap. Attempt to destroy and recreate our
+- ** isolated Win32 native heap now.
+- */
+- assert( winMemGetHeap()!=NULL );
+- assert( winMemGetOwned() );
+- assert( sqlite3_memory_used()==0 );
+- winMemShutdown(winMemGetDataPtr());
+- assert( winMemGetHeap()==NULL );
+- assert( !winMemGetOwned() );
+- assert( sqlite3_memory_used()==0 );
+- rc = winMemInit(winMemGetDataPtr());
+- assert( rc!=SQLITE_OK || winMemGetHeap()!=NULL );
+- assert( rc!=SQLITE_OK || winMemGetOwned() );
+- assert( rc!=SQLITE_OK || sqlite3_memory_used()==0 );
+- }else{
+- /*
+- ** The Win32 native heap cannot be modified because it may be in use.
+- */
+- rc = SQLITE_BUSY;
+- }
+- sqlite3_mutex_leave(pMem);
+- sqlite3_mutex_leave(pMaster);
+- return rc;
+-}
+-#endif /* SQLITE_WIN32_MALLOC */
+
+-/*
+-** This function outputs the specified (ANSI) string to the Win32 debugger
+-** (if available).
+-*/
++#define osGetSystemTimeAsFileTime ((VOID(WINAPI*)( \
++ LPFILETIME))aSyscall[30].pCurrent)
+
+-SQLITE_API void SQLITE_STDCALL sqlite3_win32_write_debug(const char *zBuf, int nBuf){
+- char zDbgBuf[SQLITE_WIN32_DBG_BUF_SIZE];
+- int nMin = MIN(nBuf, (SQLITE_WIN32_DBG_BUF_SIZE - 1)); /* may be negative. */
+- if( nMin<-1 ) nMin = -1; /* all negative values become -1. */
+- assert( nMin==-1 || nMin==0 || nMin<SQLITE_WIN32_DBG_BUF_SIZE );
+ #if defined(SQLITE_WIN32_HAS_ANSI)
+- if( nMin>0 ){
+- memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE);
+- memcpy(zDbgBuf, zBuf, nMin);
+- osOutputDebugStringA(zDbgBuf);
+- }else{
+- osOutputDebugStringA(zBuf);
+- }
+-#elif defined(SQLITE_WIN32_HAS_WIDE)
+- memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE);
+- if ( osMultiByteToWideChar(
+- osAreFileApisANSI() ? CP_ACP : CP_OEMCP, 0, zBuf,
+- nMin, (LPWSTR)zDbgBuf, SQLITE_WIN32_DBG_BUF_SIZE/sizeof(WCHAR))<=0 ){
+- return;
+- }
+- osOutputDebugStringW((LPCWSTR)zDbgBuf);
++ { "GetTempPathA", (SYSCALL)GetTempPathA, 0 },
+ #else
+- if( nMin>0 ){
+- memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE);
+- memcpy(zDbgBuf, zBuf, nMin);
+- fprintf(stderr, "%s", zDbgBuf);
+- }else{
+- fprintf(stderr, "%s", zBuf);
+- }
++ { "GetTempPathA", (SYSCALL)0, 0 },
++#endif
++
++#define osGetTempPathA ((DWORD(WINAPI*)(DWORD,LPSTR))aSyscall[31].pCurrent)
++
++#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
++ { "GetTempPathW", (SYSCALL)GetTempPathW, 0 },
++#else
++ { "GetTempPathW", (SYSCALL)0, 0 },
+ #endif
+-}
+
+-/*
+-** The following routine suspends the current thread for at least ms
+-** milliseconds. This is equivalent to the Win32 Sleep() interface.
+-*/
+-#if SQLITE_OS_WINRT
+-static HANDLE sleepObj = NULL;
++#define osGetTempPathW ((DWORD(WINAPI*)(DWORD,LPWSTR))aSyscall[32].pCurrent)
++
++#if !SQLITE_OS_WINRT
++ { "GetTickCount", (SYSCALL)GetTickCount, 0 },
++#else
++ { "GetTickCount", (SYSCALL)0, 0 },
+ #endif
+
+-SQLITE_API void SQLITE_STDCALL sqlite3_win32_sleep(DWORD milliseconds){
+-#if SQLITE_OS_WINRT
+- if ( sleepObj==NULL ){
+- sleepObj = osCreateEventExW(NULL, NULL, CREATE_EVENT_MANUAL_RESET,
+- SYNCHRONIZE);
+- }
+- assert( sleepObj!=NULL );
+- osWaitForSingleObjectEx(sleepObj, milliseconds, FALSE);
++#define osGetTickCount ((DWORD(WINAPI*)(VOID))aSyscall[33].pCurrent)
++
++#if defined(SQLITE_WIN32_HAS_ANSI) && defined(SQLITE_WIN32_GETVERSIONEX) && \
++ SQLITE_WIN32_GETVERSIONEX
++ { "GetVersionExA", (SYSCALL)GetVersionExA, 0 },
+ #else
+- osSleep(milliseconds);
++ { "GetVersionExA", (SYSCALL)0, 0 },
+ #endif
+-}
+
+-#if SQLITE_MAX_WORKER_THREADS>0 && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \
+- SQLITE_THREADSAFE>0
+-SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject){
+- DWORD rc;
+- while( (rc = osWaitForSingleObjectEx(hObject, INFINITE,
+- TRUE))==WAIT_IO_COMPLETION ){}
+- return rc;
+-}
++#define osGetVersionExA ((BOOL(WINAPI*)( \
++ LPOSVERSIONINFOA))aSyscall[34].pCurrent)
++
++#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \
++ defined(SQLITE_WIN32_GETVERSIONEX) && SQLITE_WIN32_GETVERSIONEX
++ { "GetVersionExW", (SYSCALL)GetVersionExW, 0 },
++#else
++ { "GetVersionExW", (SYSCALL)0, 0 },
+ #endif
+
+-/*
+-** Return true (non-zero) if we are running under WinNT, Win2K, WinXP,
+-** or WinCE. Return false (zero) for Win95, Win98, or WinME.
+-**
+-** Here is an interesting observation: Win95, Win98, and WinME lack
+-** the LockFileEx() API. But we can still statically link against that
+-** API as long as we don't call it when running Win95/98/ME. A call to
+-** this routine is used to determine if the host is Win95/98/ME or
+-** WinNT/2K/XP so that we will know whether or not we can safely call
+-** the LockFileEx() API.
+-*/
++#define osGetVersionExW ((BOOL(WINAPI*)( \
++ LPOSVERSIONINFOW))aSyscall[35].pCurrent)
+
+-#if !defined(SQLITE_WIN32_GETVERSIONEX) || !SQLITE_WIN32_GETVERSIONEX
+-# define osIsNT() (1)
+-#elif SQLITE_OS_WINCE || SQLITE_OS_WINRT || !defined(SQLITE_WIN32_HAS_ANSI)
+-# define osIsNT() (1)
+-#elif !defined(SQLITE_WIN32_HAS_WIDE)
+-# define osIsNT() (0)
++ { "HeapAlloc", (SYSCALL)HeapAlloc, 0 },
++
++#define osHeapAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD, \
++ SIZE_T))aSyscall[36].pCurrent)
++
++#if !SQLITE_OS_WINRT
++ { "HeapCreate", (SYSCALL)HeapCreate, 0 },
+ #else
+-# define osIsNT() ((sqlite3_os_type==2) || sqlite3_win32_is_nt())
++ { "HeapCreate", (SYSCALL)0, 0 },
+ #endif
+
+-/*
+-** This function determines if the machine is running a version of Windows
+-** based on the NT kernel.
+-*/
+-SQLITE_API int SQLITE_STDCALL sqlite3_win32_is_nt(void){
+-#if SQLITE_OS_WINRT
+- /*
+- ** NOTE: The WinRT sub-platform is always assumed to be based on the NT
+- ** kernel.
+- */
+- return 1;
+-#elif defined(SQLITE_WIN32_GETVERSIONEX) && SQLITE_WIN32_GETVERSIONEX
+- if( osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0 ){
+-#if defined(SQLITE_WIN32_HAS_ANSI)
+- OSVERSIONINFOA sInfo;
+- sInfo.dwOSVersionInfoSize = sizeof(sInfo);
+- osGetVersionExA(&sInfo);
+- osInterlockedCompareExchange(&sqlite3_os_type,
+- (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0);
+-#elif defined(SQLITE_WIN32_HAS_WIDE)
+- OSVERSIONINFOW sInfo;
+- sInfo.dwOSVersionInfoSize = sizeof(sInfo);
+- osGetVersionExW(&sInfo);
+- osInterlockedCompareExchange(&sqlite3_os_type,
+- (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0);
++#define osHeapCreate ((HANDLE(WINAPI*)(DWORD,SIZE_T, \
++ SIZE_T))aSyscall[37].pCurrent)
++
++#if !SQLITE_OS_WINRT
++ { "HeapDestroy", (SYSCALL)HeapDestroy, 0 },
++#else
++ { "HeapDestroy", (SYSCALL)0, 0 },
+ #endif
+- }
+- return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2;
+-#elif SQLITE_TEST
+- return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2;
++
++#define osHeapDestroy ((BOOL(WINAPI*)(HANDLE))aSyscall[38].pCurrent)
++
++ { "HeapFree", (SYSCALL)HeapFree, 0 },
++
++#define osHeapFree ((BOOL(WINAPI*)(HANDLE,DWORD,LPVOID))aSyscall[39].pCurrent)
++
++ { "HeapReAlloc", (SYSCALL)HeapReAlloc, 0 },
++
++#define osHeapReAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD,LPVOID, \
++ SIZE_T))aSyscall[40].pCurrent)
++
++ { "HeapSize", (SYSCALL)HeapSize, 0 },
++
++#define osHeapSize ((SIZE_T(WINAPI*)(HANDLE,DWORD, \
++ LPCVOID))aSyscall[41].pCurrent)
++
++#if !SQLITE_OS_WINRT
++ { "HeapValidate", (SYSCALL)HeapValidate, 0 },
+ #else
+- /*
+- ** NOTE: All sub-platforms where the GetVersionEx[AW] functions are
+- ** deprecated are always assumed to be based on the NT kernel.
+- */
+- return 1;
++ { "HeapValidate", (SYSCALL)0, 0 },
+ #endif
+-}
+
+-#ifdef SQLITE_WIN32_MALLOC
+-/*
+-** Allocate nBytes of memory.
+-*/
+-static void *winMemMalloc(int nBytes){
+- HANDLE hHeap;
+- void *p;
++#define osHeapValidate ((BOOL(WINAPI*)(HANDLE,DWORD, \
++ LPCVOID))aSyscall[42].pCurrent)
+
+- winMemAssertMagic();
+- hHeap = winMemGetHeap();
+- assert( hHeap!=0 );
+- assert( hHeap!=INVALID_HANDLE_VALUE );
+-#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE)
+- assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
++#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
++ { "HeapCompact", (SYSCALL)HeapCompact, 0 },
++#else
++ { "HeapCompact", (SYSCALL)0, 0 },
+ #endif
+- assert( nBytes>=0 );
+- p = osHeapAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, (SIZE_T)nBytes);
+- if( !p ){
+- sqlite3_log(SQLITE_NOMEM, "failed to HeapAlloc %u bytes (%lu), heap=%p",
+- nBytes, osGetLastError(), (void*)hHeap);
+- }
+- return p;
+-}
+
+-/*
+-** Free memory.
+-*/
+-static void winMemFree(void *pPrior){
+- HANDLE hHeap;
++#define osHeapCompact ((UINT(WINAPI*)(HANDLE,DWORD))aSyscall[43].pCurrent)
+
+- winMemAssertMagic();
+- hHeap = winMemGetHeap();
+- assert( hHeap!=0 );
+- assert( hHeap!=INVALID_HANDLE_VALUE );
+-#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE)
+- assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) );
++#if defined(SQLITE_WIN32_HAS_ANSI) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
++ { "LoadLibraryA", (SYSCALL)LoadLibraryA, 0 },
++#else
++ { "LoadLibraryA", (SYSCALL)0, 0 },
+ #endif
+- if( !pPrior ) return; /* Passing NULL to HeapFree is undefined. */
+- if( !osHeapFree(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) ){
+- sqlite3_log(SQLITE_NOMEM, "failed to HeapFree block %p (%lu), heap=%p",
+- pPrior, osGetLastError(), (void*)hHeap);
+- }
+-}
+
+-/*
+-** Change the size of an existing memory allocation
+-*/
+-static void *winMemRealloc(void *pPrior, int nBytes){
+- HANDLE hHeap;
+- void *p;
++#define osLoadLibraryA ((HMODULE(WINAPI*)(LPCSTR))aSyscall[44].pCurrent)
+
+- winMemAssertMagic();
+- hHeap = winMemGetHeap();
+- assert( hHeap!=0 );
+- assert( hHeap!=INVALID_HANDLE_VALUE );
+-#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE)
+- assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) );
++#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \
++ !defined(SQLITE_OMIT_LOAD_EXTENSION)
++ { "LoadLibraryW", (SYSCALL)LoadLibraryW, 0 },
++#else
++ { "LoadLibraryW", (SYSCALL)0, 0 },
+ #endif
+- assert( nBytes>=0 );
+- if( !pPrior ){
+- p = osHeapAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, (SIZE_T)nBytes);
+- }else{
+- p = osHeapReAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior, (SIZE_T)nBytes);
+- }
+- if( !p ){
+- sqlite3_log(SQLITE_NOMEM, "failed to %s %u bytes (%lu), heap=%p",
+- pPrior ? "HeapReAlloc" : "HeapAlloc", nBytes, osGetLastError(),
+- (void*)hHeap);
+- }
+- return p;
+-}
+
+-/*
+-** Return the size of an outstanding allocation, in bytes.
+-*/
+-static int winMemSize(void *p){
+- HANDLE hHeap;
+- SIZE_T n;
++#define osLoadLibraryW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[45].pCurrent)
+
+- winMemAssertMagic();
+- hHeap = winMemGetHeap();
+- assert( hHeap!=0 );
+- assert( hHeap!=INVALID_HANDLE_VALUE );
+-#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE)
+- assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, p) );
++#if !SQLITE_OS_WINRT
++ { "LocalFree", (SYSCALL)LocalFree, 0 },
++#else
++ { "LocalFree", (SYSCALL)0, 0 },
+ #endif
+- if( !p ) return 0;
+- n = osHeapSize(hHeap, SQLITE_WIN32_HEAP_FLAGS, p);
+- if( n==(SIZE_T)-1 ){
+- sqlite3_log(SQLITE_NOMEM, "failed to HeapSize block %p (%lu), heap=%p",
+- p, osGetLastError(), (void*)hHeap);
+- return 0;
+- }
+- return (int)n;
+-}
+
+-/*
+-** Round up a request size to the next valid allocation size.
+-*/
+-static int winMemRoundup(int n){
+- return n;
+-}
++#define osLocalFree ((HLOCAL(WINAPI*)(HLOCAL))aSyscall[46].pCurrent)
+
+-/*
+-** Initialize this module.
+-*/
+-static int winMemInit(void *pAppData){
+- winMemData *pWinMemData = (winMemData *)pAppData;
++#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
++ { "LockFile", (SYSCALL)LockFile, 0 },
++#else
++ { "LockFile", (SYSCALL)0, 0 },
++#endif
+
+- if( !pWinMemData ) return SQLITE_ERROR;
+- assert( pWinMemData->magic1==WINMEM_MAGIC1 );
+- assert( pWinMemData->magic2==WINMEM_MAGIC2 );
++#ifndef osLockFile
++#define osLockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
++ DWORD))aSyscall[47].pCurrent)
++#endif
+
+-#if !SQLITE_OS_WINRT && SQLITE_WIN32_HEAP_CREATE
+- if( !pWinMemData->hHeap ){
+- DWORD dwInitialSize = SQLITE_WIN32_HEAP_INIT_SIZE;
+- DWORD dwMaximumSize = (DWORD)sqlite3GlobalConfig.nHeap;
+- if( dwMaximumSize==0 ){
+- dwMaximumSize = SQLITE_WIN32_HEAP_MAX_SIZE;
+- }else if( dwInitialSize>dwMaximumSize ){
+- dwInitialSize = dwMaximumSize;
+- }
+- pWinMemData->hHeap = osHeapCreate(SQLITE_WIN32_HEAP_FLAGS,
+- dwInitialSize, dwMaximumSize);
+- if( !pWinMemData->hHeap ){
+- sqlite3_log(SQLITE_NOMEM,
+- "failed to HeapCreate (%lu), flags=%u, initSize=%lu, maxSize=%lu",
+- osGetLastError(), SQLITE_WIN32_HEAP_FLAGS, dwInitialSize,
+- dwMaximumSize);
+- return SQLITE_NOMEM;
+- }
+- pWinMemData->bOwned = TRUE;
+- assert( pWinMemData->bOwned );
+- }
++#if !SQLITE_OS_WINCE
++ { "LockFileEx", (SYSCALL)LockFileEx, 0 },
+ #else
+- pWinMemData->hHeap = osGetProcessHeap();
+- if( !pWinMemData->hHeap ){
+- sqlite3_log(SQLITE_NOMEM,
+- "failed to GetProcessHeap (%lu)", osGetLastError());
+- return SQLITE_NOMEM;
+- }
+- pWinMemData->bOwned = FALSE;
+- assert( !pWinMemData->bOwned );
++ { "LockFileEx", (SYSCALL)0, 0 },
+ #endif
+- assert( pWinMemData->hHeap!=0 );
+- assert( pWinMemData->hHeap!=INVALID_HANDLE_VALUE );
+-#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE)
+- assert( osHeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
++
++#ifndef osLockFileEx
++#define osLockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD,DWORD, \
++ LPOVERLAPPED))aSyscall[48].pCurrent)
+ #endif
+- return SQLITE_OK;
+-}
+
+-/*
+-** Deinitialize this module.
+-*/
+-static void winMemShutdown(void *pAppData){
+- winMemData *pWinMemData = (winMemData *)pAppData;
++#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && \
++ (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0))
++ { "MapViewOfFile", (SYSCALL)MapViewOfFile, 0 },
++#else
++ { "MapViewOfFile", (SYSCALL)0, 0 },
++#endif
+
+- if( !pWinMemData ) return;
+- assert( pWinMemData->magic1==WINMEM_MAGIC1 );
+- assert( pWinMemData->magic2==WINMEM_MAGIC2 );
++#define osMapViewOfFile ((LPVOID(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
++ SIZE_T))aSyscall[49].pCurrent)
+
+- if( pWinMemData->hHeap ){
+- assert( pWinMemData->hHeap!=INVALID_HANDLE_VALUE );
+-#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE)
+- assert( osHeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
++ { "MultiByteToWideChar", (SYSCALL)MultiByteToWideChar, 0 },
++
++#define osMultiByteToWideChar ((int(WINAPI*)(UINT,DWORD,LPCSTR,int,LPWSTR, \
++ int))aSyscall[50].pCurrent)
++
++ { "QueryPerformanceCounter", (SYSCALL)QueryPerformanceCounter, 0 },
++
++#define osQueryPerformanceCounter ((BOOL(WINAPI*)( \
++ LARGE_INTEGER*))aSyscall[51].pCurrent)
++
++ { "ReadFile", (SYSCALL)ReadFile, 0 },
++
++#define osReadFile ((BOOL(WINAPI*)(HANDLE,LPVOID,DWORD,LPDWORD, \
++ LPOVERLAPPED))aSyscall[52].pCurrent)
++
++ { "SetEndOfFile", (SYSCALL)SetEndOfFile, 0 },
++
++#define osSetEndOfFile ((BOOL(WINAPI*)(HANDLE))aSyscall[53].pCurrent)
++
++#if !SQLITE_OS_WINRT
++ { "SetFilePointer", (SYSCALL)SetFilePointer, 0 },
++#else
++ { "SetFilePointer", (SYSCALL)0, 0 },
+ #endif
+- if( pWinMemData->bOwned ){
+- if( !osHeapDestroy(pWinMemData->hHeap) ){
+- sqlite3_log(SQLITE_NOMEM, "failed to HeapDestroy (%lu), heap=%p",
+- osGetLastError(), (void*)pWinMemData->hHeap);
+- }
+- pWinMemData->bOwned = FALSE;
+- }
+- pWinMemData->hHeap = NULL;
+- }
+-}
+
+-/*
+-** Populate the low-level memory allocation function pointers in
+-** sqlite3GlobalConfig.m with pointers to the routines in this file. The
+-** arguments specify the block of memory to manage.
+-**
+-** This routine is only called by sqlite3_config(), and therefore
+-** is not required to be threadsafe (it is not).
+-*/
+-SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetWin32(void){
+- static const sqlite3_mem_methods winMemMethods = {
+- winMemMalloc,
+- winMemFree,
+- winMemRealloc,
+- winMemSize,
+- winMemRoundup,
+- winMemInit,
+- winMemShutdown,
+- &win_mem_data
+- };
+- return &winMemMethods;
+-}
++#define osSetFilePointer ((DWORD(WINAPI*)(HANDLE,LONG,PLONG, \
++ DWORD))aSyscall[54].pCurrent)
+
+-SQLITE_PRIVATE void sqlite3MemSetDefault(void){
+- sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetWin32());
+-}
+-#endif /* SQLITE_WIN32_MALLOC */
++#if !SQLITE_OS_WINRT
++ { "Sleep", (SYSCALL)Sleep, 0 },
++#else
++ { "Sleep", (SYSCALL)0, 0 },
++#endif
+
+-/*
+-** Convert a UTF-8 string to Microsoft Unicode (UTF-16?).
+-**
+-** Space to hold the returned string is obtained from malloc.
+-*/
+-static LPWSTR winUtf8ToUnicode(const char *zFilename){
+- int nChar;
+- LPWSTR zWideFilename;
++#define osSleep ((VOID(WINAPI*)(DWORD))aSyscall[55].pCurrent)
+
+- nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
+- if( nChar==0 ){
+- return 0;
+- }
+- zWideFilename = sqlite3MallocZero( nChar*sizeof(zWideFilename[0]) );
+- if( zWideFilename==0 ){
+- return 0;
+- }
+- nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename,
+- nChar);
+- if( nChar==0 ){
+- sqlite3_free(zWideFilename);
+- zWideFilename = 0;
+- }
+- return zWideFilename;
+-}
++ { "SystemTimeToFileTime", (SYSCALL)SystemTimeToFileTime, 0 },
+
+-/*
+-** Convert Microsoft Unicode to UTF-8. Space to hold the returned string is
+-** obtained from sqlite3_malloc().
+-*/
+-static char *winUnicodeToUtf8(LPCWSTR zWideFilename){
+- int nByte;
+- char *zFilename;
++#define osSystemTimeToFileTime ((BOOL(WINAPI*)(CONST SYSTEMTIME*, \
++ LPFILETIME))aSyscall[56].pCurrent)
+
+- nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0);
+- if( nByte == 0 ){
+- return 0;
+- }
+- zFilename = sqlite3MallocZero( nByte );
+- if( zFilename==0 ){
+- return 0;
+- }
+- nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, zFilename, nByte,
+- 0, 0);
+- if( nByte == 0 ){
+- sqlite3_free(zFilename);
+- zFilename = 0;
+- }
+- return zFilename;
+-}
++#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
++ { "UnlockFile", (SYSCALL)UnlockFile, 0 },
++#else
++ { "UnlockFile", (SYSCALL)0, 0 },
++#endif
+
+-/*
+-** Convert an ANSI string to Microsoft Unicode, based on the
+-** current codepage settings for file apis.
+-**
+-** Space to hold the returned string is obtained
+-** from sqlite3_malloc.
+-*/
+-static LPWSTR winMbcsToUnicode(const char *zFilename){
+- int nByte;
+- LPWSTR zMbcsFilename;
+- int codepage = osAreFileApisANSI() ? CP_ACP : CP_OEMCP;
++#ifndef osUnlockFile
++#define osUnlockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
++ DWORD))aSyscall[57].pCurrent)
++#endif
+
+- nByte = osMultiByteToWideChar(codepage, 0, zFilename, -1, NULL,
+- 0)*sizeof(WCHAR);
+- if( nByte==0 ){
+- return 0;
+- }
+- zMbcsFilename = sqlite3MallocZero( nByte*sizeof(zMbcsFilename[0]) );
+- if( zMbcsFilename==0 ){
+- return 0;
+- }
+- nByte = osMultiByteToWideChar(codepage, 0, zFilename, -1, zMbcsFilename,
+- nByte);
+- if( nByte==0 ){
+- sqlite3_free(zMbcsFilename);
+- zMbcsFilename = 0;
+- }
+- return zMbcsFilename;
+-}
++#if !SQLITE_OS_WINCE
++ { "UnlockFileEx", (SYSCALL)UnlockFileEx, 0 },
++#else
++ { "UnlockFileEx", (SYSCALL)0, 0 },
++#endif
+
+-/*
+-** Convert Microsoft Unicode to multi-byte character string, based on the
+-** user's ANSI codepage.
+-**
+-** Space to hold the returned string is obtained from
+-** sqlite3_malloc().
+-*/
+-static char *winUnicodeToMbcs(LPCWSTR zWideFilename){
+- int nByte;
+- char *zFilename;
+- int codepage = osAreFileApisANSI() ? CP_ACP : CP_OEMCP;
++#define osUnlockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
++ LPOVERLAPPED))aSyscall[58].pCurrent)
++
++#if SQLITE_OS_WINCE || !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
++ { "UnmapViewOfFile", (SYSCALL)UnmapViewOfFile, 0 },
++#else
++ { "UnmapViewOfFile", (SYSCALL)0, 0 },
++#endif
++
++#define osUnmapViewOfFile ((BOOL(WINAPI*)(LPCVOID))aSyscall[59].pCurrent)
++
++ { "WideCharToMultiByte", (SYSCALL)WideCharToMultiByte, 0 },
+
+- nByte = osWideCharToMultiByte(codepage, 0, zWideFilename, -1, 0, 0, 0, 0);
+- if( nByte == 0 ){
+- return 0;
+- }
+- zFilename = sqlite3MallocZero( nByte );
+- if( zFilename==0 ){
+- return 0;
+- }
+- nByte = osWideCharToMultiByte(codepage, 0, zWideFilename, -1, zFilename,
+- nByte, 0, 0);
+- if( nByte == 0 ){
+- sqlite3_free(zFilename);
+- zFilename = 0;
+- }
+- return zFilename;
+-}
++#define osWideCharToMultiByte ((int(WINAPI*)(UINT,DWORD,LPCWSTR,int,LPSTR,int, \
++ LPCSTR,LPBOOL))aSyscall[60].pCurrent)
+
+-/*
+-** Convert multibyte character string to UTF-8. Space to hold the
+-** returned string is obtained from sqlite3_malloc().
+-*/
+-SQLITE_API char *SQLITE_STDCALL sqlite3_win32_mbcs_to_utf8(const char *zFilename){
+- char *zFilenameUtf8;
+- LPWSTR zTmpWide;
++ { "WriteFile", (SYSCALL)WriteFile, 0 },
+
+- zTmpWide = winMbcsToUnicode(zFilename);
+- if( zTmpWide==0 ){
+- return 0;
+- }
+- zFilenameUtf8 = winUnicodeToUtf8(zTmpWide);
+- sqlite3_free(zTmpWide);
+- return zFilenameUtf8;
+-}
++#define osWriteFile ((BOOL(WINAPI*)(HANDLE,LPCVOID,DWORD,LPDWORD, \
++ LPOVERLAPPED))aSyscall[61].pCurrent)
+
+-/*
+-** Convert UTF-8 to multibyte character string. Space to hold the
+-** returned string is obtained from sqlite3_malloc().
+-*/
+-SQLITE_API char *SQLITE_STDCALL sqlite3_win32_utf8_to_mbcs(const char *zFilename){
+- char *zFilenameMbcs;
+- LPWSTR zTmpWide;
++#if SQLITE_OS_WINRT
++ { "CreateEventExW", (SYSCALL)CreateEventExW, 0 },
++#else
++ { "CreateEventExW", (SYSCALL)0, 0 },
++#endif
+
+- zTmpWide = winUtf8ToUnicode(zFilename);
+- if( zTmpWide==0 ){
+- return 0;
+- }
+- zFilenameMbcs = winUnicodeToMbcs(zTmpWide);
+- sqlite3_free(zTmpWide);
+- return zFilenameMbcs;
+-}
++#define osCreateEventExW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,LPCWSTR, \
++ DWORD,DWORD))aSyscall[62].pCurrent)
+
+-/*
+-** This function sets the data directory or the temporary directory based on
+-** the provided arguments. The type argument must be 1 in order to set the
+-** data directory or 2 in order to set the temporary directory. The zValue
+-** argument is the name of the directory to use. The return value will be
+-** SQLITE_OK if successful.
+-*/
+-SQLITE_API int SQLITE_STDCALL sqlite3_win32_set_directory(DWORD type, LPCWSTR zValue){
+- char **ppDirectory = 0;
+-#ifndef SQLITE_OMIT_AUTOINIT
+- int rc = sqlite3_initialize();
+- if( rc ) return rc;
++#if !SQLITE_OS_WINRT
++ { "WaitForSingleObject", (SYSCALL)WaitForSingleObject, 0 },
++#else
++ { "WaitForSingleObject", (SYSCALL)0, 0 },
+ #endif
+- if( type==SQLITE_WIN32_DATA_DIRECTORY_TYPE ){
+- ppDirectory = &sqlite3_data_directory;
+- }else if( type==SQLITE_WIN32_TEMP_DIRECTORY_TYPE ){
+- ppDirectory = &sqlite3_temp_directory;
+- }
+- assert( !ppDirectory || type==SQLITE_WIN32_DATA_DIRECTORY_TYPE
+- || type==SQLITE_WIN32_TEMP_DIRECTORY_TYPE
+- );
+- assert( !ppDirectory || sqlite3MemdebugHasType(*ppDirectory, MEMTYPE_HEAP) );
+- if( ppDirectory ){
+- char *zValueUtf8 = 0;
+- if( zValue && zValue[0] ){
+- zValueUtf8 = winUnicodeToUtf8(zValue);
+- if ( zValueUtf8==0 ){
+- return SQLITE_NOMEM;
+- }
+- }
+- sqlite3_free(*ppDirectory);
+- *ppDirectory = zValueUtf8;
+- return SQLITE_OK;
+- }
+- return SQLITE_ERROR;
+-}
+
+-/*
+-** The return value of winGetLastErrorMsg
+-** is zero if the error message fits in the buffer, or non-zero
+-** otherwise (if the message was truncated).
+-*/
+-static int winGetLastErrorMsg(DWORD lastErrno, int nBuf, char *zBuf){
+- /* FormatMessage returns 0 on failure. Otherwise it
+- ** returns the number of TCHARs written to the output
+- ** buffer, excluding the terminating null char.
+- */
+- DWORD dwLen = 0;
+- char *zOut = 0;
++#define osWaitForSingleObject ((DWORD(WINAPI*)(HANDLE, \
++ DWORD))aSyscall[63].pCurrent)
++
++#if !SQLITE_OS_WINCE
++ { "WaitForSingleObjectEx", (SYSCALL)WaitForSingleObjectEx, 0 },
++#else
++ { "WaitForSingleObjectEx", (SYSCALL)0, 0 },
++#endif
++
++#define osWaitForSingleObjectEx ((DWORD(WINAPI*)(HANDLE,DWORD, \
++ BOOL))aSyscall[64].pCurrent)
+
+- if( osIsNT() ){
+ #if SQLITE_OS_WINRT
+- WCHAR zTempWide[SQLITE_WIN32_MAX_ERRMSG_CHARS+1];
+- dwLen = osFormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
+- FORMAT_MESSAGE_IGNORE_INSERTS,
+- NULL,
+- lastErrno,
+- 0,
+- zTempWide,
+- SQLITE_WIN32_MAX_ERRMSG_CHARS,
+- 0);
++ { "SetFilePointerEx", (SYSCALL)SetFilePointerEx, 0 },
+ #else
+- LPWSTR zTempWide = NULL;
+- dwLen = osFormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+- FORMAT_MESSAGE_FROM_SYSTEM |
+- FORMAT_MESSAGE_IGNORE_INSERTS,
+- NULL,
+- lastErrno,
+- 0,
+- (LPWSTR) &zTempWide,
+- 0,
+- 0);
++ { "SetFilePointerEx", (SYSCALL)0, 0 },
+ #endif
+- if( dwLen > 0 ){
+- /* allocate a buffer and convert to UTF8 */
+- sqlite3BeginBenignMalloc();
+- zOut = winUnicodeToUtf8(zTempWide);
+- sqlite3EndBenignMalloc();
+-#if !SQLITE_OS_WINRT
+- /* free the system buffer allocated by FormatMessage */
+- osLocalFree(zTempWide);
++
++#define osSetFilePointerEx ((BOOL(WINAPI*)(HANDLE,LARGE_INTEGER, \
++ PLARGE_INTEGER,DWORD))aSyscall[65].pCurrent)
++
++#if SQLITE_OS_WINRT
++ { "GetFileInformationByHandleEx", (SYSCALL)GetFileInformationByHandleEx, 0 },
++#else
++ { "GetFileInformationByHandleEx", (SYSCALL)0, 0 },
+ #endif
+- }
+- }
+-#ifdef SQLITE_WIN32_HAS_ANSI
+- else{
+- char *zTemp = NULL;
+- dwLen = osFormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+- FORMAT_MESSAGE_FROM_SYSTEM |
+- FORMAT_MESSAGE_IGNORE_INSERTS,
+- NULL,
+- lastErrno,
+- 0,
+- (LPSTR) &zTemp,
+- 0,
+- 0);
+- if( dwLen > 0 ){
+- /* allocate a buffer and convert to UTF8 */
+- sqlite3BeginBenignMalloc();
+- zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
+- sqlite3EndBenignMalloc();
+- /* free the system buffer allocated by FormatMessage */
+- osLocalFree(zTemp);
+- }
+- }
++
++#define osGetFileInformationByHandleEx ((BOOL(WINAPI*)(HANDLE, \
++ FILE_INFO_BY_HANDLE_CLASS,LPVOID,DWORD))aSyscall[66].pCurrent)
++
++#if SQLITE_OS_WINRT && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)
++ { "MapViewOfFileFromApp", (SYSCALL)MapViewOfFileFromApp, 0 },
++#else
++ { "MapViewOfFileFromApp", (SYSCALL)0, 0 },
+ #endif
+- if( 0 == dwLen ){
+- sqlite3_snprintf(nBuf, zBuf, "OsError 0x%lx (%lu)", lastErrno, lastErrno);
+- }else{
+- /* copy a maximum of nBuf chars to output buffer */
+- sqlite3_snprintf(nBuf, zBuf, "%s", zOut);
+- /* free the UTF8 buffer */
+- sqlite3_free(zOut);
+- }
+- return 0;
+-}
+
+-/*
+-**
+-** This function - winLogErrorAtLine() - is only ever called via the macro
+-** winLogError().
+-**
+-** This routine is invoked after an error occurs in an OS function.
+-** It logs a message using sqlite3_log() containing the current value of
+-** error code and, if possible, the human-readable equivalent from
+-** FormatMessage.
+-**
+-** The first argument passed to the macro should be the error code that
+-** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN).
+-** The two subsequent arguments should be the name of the OS function that
+-** failed and the associated file-system path, if any.
+-*/
+-#define winLogError(a,b,c,d) winLogErrorAtLine(a,b,c,d,__LINE__)
+-static int winLogErrorAtLine(
+- int errcode, /* SQLite error code */
+- DWORD lastErrno, /* Win32 last error */
+- const char *zFunc, /* Name of OS function that failed */
+- const char *zPath, /* File path associated with error */
+- int iLine /* Source line number where error occurred */
+-){
+- char zMsg[500]; /* Human readable error text */
+- int i; /* Loop counter */
++#define osMapViewOfFileFromApp ((LPVOID(WINAPI*)(HANDLE,ULONG,ULONG64, \
++ SIZE_T))aSyscall[67].pCurrent)
+
+- zMsg[0] = 0;
+- winGetLastErrorMsg(lastErrno, sizeof(zMsg), zMsg);
+- assert( errcode!=SQLITE_OK );
+- if( zPath==0 ) zPath = "";
+- for(i=0; zMsg[i] && zMsg[i]!='\r' && zMsg[i]!='\n'; i++){}
+- zMsg[i] = 0;
+- sqlite3_log(errcode,
+- "os_win.c:%d: (%lu) %s(%s) - %s",
+- iLine, lastErrno, zFunc, zPath, zMsg
+- );
++#if SQLITE_OS_WINRT
++ { "CreateFile2", (SYSCALL)CreateFile2, 0 },
++#else
++ { "CreateFile2", (SYSCALL)0, 0 },
++#endif
+
+- return errcode;
+-}
++#define osCreateFile2 ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD,DWORD, \
++ LPCREATEFILE2_EXTENDED_PARAMETERS))aSyscall[68].pCurrent)
+
+-/*
+-** The number of times that a ReadFile(), WriteFile(), and DeleteFile()
+-** will be retried following a locking error - probably caused by
+-** antivirus software. Also the initial delay before the first retry.
+-** The delay increases linearly with each retry.
+-*/
+-#ifndef SQLITE_WIN32_IOERR_RETRY
+-# define SQLITE_WIN32_IOERR_RETRY 10
++#if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_LOAD_EXTENSION)
++ { "LoadPackagedLibrary", (SYSCALL)LoadPackagedLibrary, 0 },
++#else
++ { "LoadPackagedLibrary", (SYSCALL)0, 0 },
+ #endif
+-#ifndef SQLITE_WIN32_IOERR_RETRY_DELAY
+-# define SQLITE_WIN32_IOERR_RETRY_DELAY 25
++
++#define osLoadPackagedLibrary ((HMODULE(WINAPI*)(LPCWSTR, \
++ DWORD))aSyscall[69].pCurrent)
++
++#if SQLITE_OS_WINRT
++ { "GetTickCount64", (SYSCALL)GetTickCount64, 0 },
++#else
++ { "GetTickCount64", (SYSCALL)0, 0 },
+ #endif
+-static int winIoerrRetry = SQLITE_WIN32_IOERR_RETRY;
+-static int winIoerrRetryDelay = SQLITE_WIN32_IOERR_RETRY_DELAY;
+
+-/*
+-** The "winIoerrCanRetry1" macro is used to determine if a particular I/O
+-** error code obtained via GetLastError() is eligible to be retried. It
+-** must accept the error code DWORD as its only argument and should return
+-** non-zero if the error code is transient in nature and the operation
+-** responsible for generating the original error might succeed upon being
+-** retried. The argument to this macro should be a variable.
+-**
+-** Additionally, a macro named "winIoerrCanRetry2" may be defined. If it
+-** is defined, it will be consulted only when the macro "winIoerrCanRetry1"
+-** returns zero. The "winIoerrCanRetry2" macro is completely optional and
+-** may be used to include additional error codes in the set that should
+-** result in the failing I/O operation being retried by the caller. If
+-** defined, the "winIoerrCanRetry2" macro must exhibit external semantics
+-** identical to those of the "winIoerrCanRetry1" macro.
+-*/
+-#if !defined(winIoerrCanRetry1)
+-#define winIoerrCanRetry1(a) (((a)==ERROR_ACCESS_DENIED) || \
+- ((a)==ERROR_SHARING_VIOLATION) || \
+- ((a)==ERROR_LOCK_VIOLATION) || \
+- ((a)==ERROR_DEV_NOT_EXIST) || \
+- ((a)==ERROR_NETNAME_DELETED) || \
+- ((a)==ERROR_SEM_TIMEOUT) || \
+- ((a)==ERROR_NETWORK_UNREACHABLE))
++#define osGetTickCount64 ((ULONGLONG(WINAPI*)(VOID))aSyscall[70].pCurrent)
++
++#if SQLITE_OS_WINRT
++ { "GetNativeSystemInfo", (SYSCALL)GetNativeSystemInfo, 0 },
++#else
++ { "GetNativeSystemInfo", (SYSCALL)0, 0 },
+ #endif
+
+-/*
+-** If a ReadFile() or WriteFile() error occurs, invoke this routine
+-** to see if it should be retried. Return TRUE to retry. Return FALSE
+-** to give up with an error.
+-*/
+-static int winRetryIoerr(int *pnRetry, DWORD *pError){
+- DWORD e = osGetLastError();
+- if( *pnRetry>=winIoerrRetry ){
+- if( pError ){
+- *pError = e;
+- }
+- return 0;
+- }
+- if( winIoerrCanRetry1(e) ){
+- sqlite3_win32_sleep(winIoerrRetryDelay*(1+*pnRetry));
+- ++*pnRetry;
+- return 1;
+- }
+-#if defined(winIoerrCanRetry2)
+- else if( winIoerrCanRetry2(e) ){
+- sqlite3_win32_sleep(winIoerrRetryDelay*(1+*pnRetry));
+- ++*pnRetry;
+- return 1;
+- }
++#define osGetNativeSystemInfo ((VOID(WINAPI*)( \
++ LPSYSTEM_INFO))aSyscall[71].pCurrent)
++
++#if defined(SQLITE_WIN32_HAS_ANSI)
++ { "OutputDebugStringA", (SYSCALL)OutputDebugStringA, 0 },
++#else
++ { "OutputDebugStringA", (SYSCALL)0, 0 },
+ #endif
+- if( pError ){
+- *pError = e;
+- }
+- return 0;
+-}
+
+-/*
+-** Log a I/O error retry episode.
+-*/
+-static void winLogIoerr(int nRetry, int lineno){
+- if( nRetry ){
+- sqlite3_log(SQLITE_NOTICE,
+- "delayed %dms for lock/sharing conflict at line %d",
+- winIoerrRetryDelay*nRetry*(nRetry+1)/2, lineno
+- );
+- }
+-}
++#define osOutputDebugStringA ((VOID(WINAPI*)(LPCSTR))aSyscall[72].pCurrent)
+
+-#if SQLITE_OS_WINCE
+-/*************************************************************************
+-** This section contains code for WinCE only.
+-*/
+-#if !defined(SQLITE_MSVC_LOCALTIME_API) || !SQLITE_MSVC_LOCALTIME_API
+-/*
+-** The MSVC CRT on Windows CE may not have a localtime() function. So
+-** create a substitute.
+-*/
+-/* #include <time.h> */
+-struct tm *__cdecl localtime(const time_t *t)
+-{
+- static struct tm y;
+- FILETIME uTm, lTm;
+- SYSTEMTIME pTm;
+- sqlite3_int64 t64;
+- t64 = *t;
+- t64 = (t64 + 11644473600)*10000000;
+- uTm.dwLowDateTime = (DWORD)(t64 & 0xFFFFFFFF);
+- uTm.dwHighDateTime= (DWORD)(t64 >> 32);
+- osFileTimeToLocalFileTime(&uTm,&lTm);
+- osFileTimeToSystemTime(&lTm,&pTm);
+- y.tm_year = pTm.wYear - 1900;
+- y.tm_mon = pTm.wMonth - 1;
+- y.tm_wday = pTm.wDayOfWeek;
+- y.tm_mday = pTm.wDay;
+- y.tm_hour = pTm.wHour;
+- y.tm_min = pTm.wMinute;
+- y.tm_sec = pTm.wSecond;
+- return &y;
+-}
++#if defined(SQLITE_WIN32_HAS_WIDE)
++ { "OutputDebugStringW", (SYSCALL)OutputDebugStringW, 0 },
++#else
++ { "OutputDebugStringW", (SYSCALL)0, 0 },
+ #endif
+
+-#define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-(int)offsetof(winFile,h)]
++#define osOutputDebugStringW ((VOID(WINAPI*)(LPCWSTR))aSyscall[73].pCurrent)
+
+-/*
+-** Acquire a lock on the handle h
+-*/
+-static void winceMutexAcquire(HANDLE h){
+- DWORD dwErr;
+- do {
+- dwErr = osWaitForSingleObject(h, INFINITE);
+- } while (dwErr != WAIT_OBJECT_0 && dwErr != WAIT_ABANDONED);
+-}
+-/*
+-** Release a lock acquired by winceMutexAcquire()
+-*/
+-#define winceMutexRelease(h) ReleaseMutex(h)
++ { "GetProcessHeap", (SYSCALL)GetProcessHeap, 0 },
+
+-/*
+-** Create the mutex and shared memory used for locking in the file
+-** descriptor pFile
+-*/
+-static int winceCreateLock(const char *zFilename, winFile *pFile){
+- LPWSTR zTok;
+- LPWSTR zName;
+- DWORD lastErrno;
+- BOOL bLogged = FALSE;
+- BOOL bInit = TRUE;
++#define osGetProcessHeap ((HANDLE(WINAPI*)(VOID))aSyscall[74].pCurrent)
+
+- zName = winUtf8ToUnicode(zFilename);
+- if( zName==0 ){
+- /* out of memory */
+- return SQLITE_IOERR_NOMEM;
+- }
++#if SQLITE_OS_WINRT && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)
++ { "CreateFileMappingFromApp", (SYSCALL)CreateFileMappingFromApp, 0 },
++#else
++ { "CreateFileMappingFromApp", (SYSCALL)0, 0 },
++#endif
+
+- /* Initialize the local lockdata */
+- memset(&pFile->local, 0, sizeof(pFile->local));
++#define osCreateFileMappingFromApp ((HANDLE(WINAPI*)(HANDLE, \
++ LPSECURITY_ATTRIBUTES,ULONG,ULONG64,LPCWSTR))aSyscall[75].pCurrent)
+
+- /* Replace the backslashes from the filename and lowercase it
+- ** to derive a mutex name. */
+- zTok = osCharLowerW(zName);
+- for (;*zTok;zTok++){
+- if (*zTok == '\\') *zTok = '_';
+- }
++/*
++** NOTE: On some sub-platforms, the InterlockedCompareExchange "function"
++** is really just a macro that uses a compiler intrinsic (e.g. x64).
++** So do not try to make this is into a redefinable interface.
++*/
++#if defined(InterlockedCompareExchange)
++ { "InterlockedCompareExchange", (SYSCALL)0, 0 },
+
+- /* Create/open the named mutex */
+- pFile->hMutex = osCreateMutexW(NULL, FALSE, zName);
+- if (!pFile->hMutex){
+- pFile->lastErrno = osGetLastError();
+- sqlite3_free(zName);
+- return winLogError(SQLITE_IOERR, pFile->lastErrno,
+- "winceCreateLock1", zFilename);
+- }
++#define osInterlockedCompareExchange InterlockedCompareExchange
++#else
++ { "InterlockedCompareExchange", (SYSCALL)InterlockedCompareExchange, 0 },
+
+- /* Acquire the mutex before continuing */
+- winceMutexAcquire(pFile->hMutex);
++#define osInterlockedCompareExchange ((LONG(WINAPI*)(LONG \
++ SQLITE_WIN32_VOLATILE*, LONG,LONG))aSyscall[76].pCurrent)
++#endif /* defined(InterlockedCompareExchange) */
+
+- /* Since the names of named mutexes, semaphores, file mappings etc are
+- ** case-sensitive, take advantage of that by uppercasing the mutex name
+- ** and using that as the shared filemapping name.
+- */
+- osCharUpperW(zName);
+- pFile->hShared = osCreateFileMappingW(INVALID_HANDLE_VALUE, NULL,
+- PAGE_READWRITE, 0, sizeof(winceLock),
+- zName);
++#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID
++ { "UuidCreate", (SYSCALL)UuidCreate, 0 },
++#else
++ { "UuidCreate", (SYSCALL)0, 0 },
++#endif
+
+- /* Set a flag that indicates we're the first to create the memory so it
+- ** must be zero-initialized */
+- lastErrno = osGetLastError();
+- if (lastErrno == ERROR_ALREADY_EXISTS){
+- bInit = FALSE;
+- }
++#define osUuidCreate ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[77].pCurrent)
+
+- sqlite3_free(zName);
++#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID
++ { "UuidCreateSequential", (SYSCALL)UuidCreateSequential, 0 },
++#else
++ { "UuidCreateSequential", (SYSCALL)0, 0 },
++#endif
+
+- /* If we succeeded in making the shared memory handle, map it. */
+- if( pFile->hShared ){
+- pFile->shared = (winceLock*)osMapViewOfFile(pFile->hShared,
+- FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(winceLock));
+- /* If mapping failed, close the shared memory handle and erase it */
+- if( !pFile->shared ){
+- pFile->lastErrno = osGetLastError();
+- winLogError(SQLITE_IOERR, pFile->lastErrno,
+- "winceCreateLock2", zFilename);
+- bLogged = TRUE;
+- osCloseHandle(pFile->hShared);
+- pFile->hShared = NULL;
+- }
+- }
++#define osUuidCreateSequential \
++ ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[78].pCurrent)
+
+- /* If shared memory could not be created, then close the mutex and fail */
+- if( pFile->hShared==NULL ){
+- if( !bLogged ){
+- pFile->lastErrno = lastErrno;
+- winLogError(SQLITE_IOERR, pFile->lastErrno,
+- "winceCreateLock3", zFilename);
+- bLogged = TRUE;
+- }
+- winceMutexRelease(pFile->hMutex);
+- osCloseHandle(pFile->hMutex);
+- pFile->hMutex = NULL;
+- return SQLITE_IOERR;
+- }
++#if !defined(SQLITE_NO_SYNC) && SQLITE_MAX_MMAP_SIZE>0
++ { "FlushViewOfFile", (SYSCALL)FlushViewOfFile, 0 },
++#else
++ { "FlushViewOfFile", (SYSCALL)0, 0 },
++#endif
+
+- /* Initialize the shared memory if we're supposed to */
+- if( bInit ){
+- memset(pFile->shared, 0, sizeof(winceLock));
+- }
++#define osFlushViewOfFile \
++ ((BOOL(WINAPI*)(LPCVOID,SIZE_T))aSyscall[79].pCurrent)
+
+- winceMutexRelease(pFile->hMutex);
+- return SQLITE_OK;
+-}
++}; /* End of the overrideable system calls */
+
+ /*
+-** Destroy the part of winFile that deals with wince locks
++** This is the xSetSystemCall() method of sqlite3_vfs for all of the
++** "win32" VFSes. Return SQLITE_OK opon successfully updating the
++** system call pointer, or SQLITE_NOTFOUND if there is no configurable
++** system call named zName.
+ */
+-static void winceDestroyLock(winFile *pFile){
+- if (pFile->hMutex){
+- /* Acquire the mutex */
+- winceMutexAcquire(pFile->hMutex);
++static int winSetSystemCall(
++ sqlite3_vfs *pNotUsed, /* The VFS pointer. Not used */
++ const char *zName, /* Name of system call to override */
++ sqlite3_syscall_ptr pNewFunc /* Pointer to new system call value */
++){
++ unsigned int i;
++ int rc = SQLITE_NOTFOUND;
+
+- /* The following blocks should probably assert in debug mode, but they
+- are to cleanup in case any locks remained open */
+- if (pFile->local.nReaders){
+- pFile->shared->nReaders --;
+- }
+- if (pFile->local.bReserved){
+- pFile->shared->bReserved = FALSE;
+- }
+- if (pFile->local.bPending){
+- pFile->shared->bPending = FALSE;
++ UNUSED_PARAMETER(pNotUsed);
++ if( zName==0 ){
++ /* If no zName is given, restore all system calls to their default
++ ** settings and return NULL
++ */
++ rc = SQLITE_OK;
++ for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
++ if( aSyscall[i].pDefault ){
++ aSyscall[i].pCurrent = aSyscall[i].pDefault;
++ }
+ }
+- if (pFile->local.bExclusive){
+- pFile->shared->bExclusive = FALSE;
++ }else{
++ /* If zName is specified, operate on only the one system call
++ ** specified.
++ */
++ for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
++ if( strcmp(zName, aSyscall[i].zName)==0 ){
++ if( aSyscall[i].pDefault==0 ){
++ aSyscall[i].pDefault = aSyscall[i].pCurrent;
++ }
++ rc = SQLITE_OK;
++ if( pNewFunc==0 ) pNewFunc = aSyscall[i].pDefault;
++ aSyscall[i].pCurrent = pNewFunc;
++ break;
++ }
+ }
+-
+- /* De-reference and close our copy of the shared memory handle */
+- osUnmapViewOfFile(pFile->shared);
+- osCloseHandle(pFile->hShared);
+-
+- /* Done with the mutex */
+- winceMutexRelease(pFile->hMutex);
+- osCloseHandle(pFile->hMutex);
+- pFile->hMutex = NULL;
+ }
++ return rc;
}
+
+ /*
+-** An implementation of the LockFile() API of Windows for CE
++** Return the value of a system call. Return NULL if zName is not a
++** recognized system call name. NULL is also returned if the system call
++** is currently undefined.
+ */
+-static BOOL winceLockFile(
+- LPHANDLE phFile,
+- DWORD dwFileOffsetLow,
+- DWORD dwFileOffsetHigh,
+- DWORD nNumberOfBytesToLockLow,
+- DWORD nNumberOfBytesToLockHigh
++static sqlite3_syscall_ptr winGetSystemCall(
++ sqlite3_vfs *pNotUsed,
++ const char *zName
+ ){
+- winFile *pFile = HANDLE_TO_WINFILE(phFile);
+- BOOL bReturn = FALSE;
++ unsigned int i;
+
+- UNUSED_PARAMETER(dwFileOffsetHigh);
+- UNUSED_PARAMETER(nNumberOfBytesToLockHigh);
++ UNUSED_PARAMETER(pNotUsed);
++ for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
++ if( strcmp(zName, aSyscall[i].zName)==0 ) return aSyscall[i].pCurrent;
++ }
++ return 0;
++}
+
+- if (!pFile->hMutex) return TRUE;
+- winceMutexAcquire(pFile->hMutex);
++/*
++** Return the name of the first system call after zName. If zName==NULL
++** then return the name of the first system call. Return NULL if zName
++** is the last system call or if zName is not the name of a valid
++** system call.
++*/
++static const char *winNextSystemCall(sqlite3_vfs *p, const char *zName){
++ int i = -1;
+
+- /* Wanting an exclusive lock? */
+- if (dwFileOffsetLow == (DWORD)SHARED_FIRST
+- && nNumberOfBytesToLockLow == (DWORD)SHARED_SIZE){
+- if (pFile->shared->nReaders == 0 && pFile->shared->bExclusive == 0){
+- pFile->shared->bExclusive = TRUE;
+- pFile->local.bExclusive = TRUE;
+- bReturn = TRUE;
++ UNUSED_PARAMETER(p);
++ if( zName ){
++ for(i=0; i<ArraySize(aSyscall)-1; i++){
++ if( strcmp(zName, aSyscall[i].zName)==0 ) break;
+ }
+ }
+-
+- /* Want a read-only lock? */
+- else if (dwFileOffsetLow == (DWORD)SHARED_FIRST &&
+- nNumberOfBytesToLockLow == 1){
+- if (pFile->shared->bExclusive == 0){
+- pFile->local.nReaders ++;
+- if (pFile->local.nReaders == 1){
+- pFile->shared->nReaders ++;
+- }
+- bReturn = TRUE;
+- }
++ for(i++; i<ArraySize(aSyscall); i++){
++ if( aSyscall[i].pCurrent!=0 ) return aSyscall[i].zName;
+ }
++ return 0;
++}
+
+- /* Want a pending lock? */
+- else if (dwFileOffsetLow == (DWORD)PENDING_BYTE
+- && nNumberOfBytesToLockLow == 1){
+- /* If no pending lock has been acquired, then acquire it */
+- if (pFile->shared->bPending == 0) {
+- pFile->shared->bPending = TRUE;
+- pFile->local.bPending = TRUE;
+- bReturn = TRUE;
+- }
+- }
++#ifdef SQLITE_WIN32_MALLOC
++/*
++** If a Win32 native heap has been configured, this function will attempt to
++** compact it. Upon success, SQLITE_OK will be returned. Upon failure, one
++** of SQLITE_NOMEM, SQLITE_ERROR, or SQLITE_NOTFOUND will be returned. The
++** "pnLargest" argument, if non-zero, will be used to return the size of the
++** largest committed free block in the heap, in bytes.
++*/
++SQLITE_API int SQLITE_STDCALL sqlite3_win32_compact_heap(LPUINT pnLargest){
++ int rc = SQLITE_OK;
++ UINT nLargest = 0;
++ HANDLE hHeap;
+
+- /* Want a reserved lock? */
+- else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE
+- && nNumberOfBytesToLockLow == 1){
+- if (pFile->shared->bReserved == 0) {
+- pFile->shared->bReserved = TRUE;
+- pFile->local.bReserved = TRUE;
+- bReturn = TRUE;
++ winMemAssertMagic();
++ hHeap = winMemGetHeap();
++ assert( hHeap!=0 );
++ assert( hHeap!=INVALID_HANDLE_VALUE );
++#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE)
++ assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
++#endif
++#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
++ if( (nLargest=osHeapCompact(hHeap, SQLITE_WIN32_HEAP_FLAGS))==0 ){
++ DWORD lastErrno = osGetLastError();
++ if( lastErrno==NO_ERROR ){
++ sqlite3_log(SQLITE_NOMEM, "failed to HeapCompact (no space), heap=%p",
++ (void*)hHeap);
++ rc = SQLITE_NOMEM;
++ }else{
++ sqlite3_log(SQLITE_ERROR, "failed to HeapCompact (%lu), heap=%p",
++ osGetLastError(), (void*)hHeap);
++ rc = SQLITE_ERROR;
+ }
+ }
+-
+- winceMutexRelease(pFile->hMutex);
+- return bReturn;
++#else
++ sqlite3_log(SQLITE_NOTFOUND, "failed to HeapCompact, heap=%p",
++ (void*)hHeap);
++ rc = SQLITE_NOTFOUND;
++#endif
++ if( pnLargest ) *pnLargest = nLargest;
++ return rc;
+ }
+
+ /*
+-** An implementation of the UnlockFile API of Windows for CE
++** If a Win32 native heap has been configured, this function will attempt to
++** destroy and recreate it. If the Win32 native heap is not isolated and/or
++** the sqlite3_memory_used() function does not return zero, SQLITE_BUSY will
++** be returned and no changes will be made to the Win32 native heap.
+ */
+-static BOOL winceUnlockFile(
+- LPHANDLE phFile,
+- DWORD dwFileOffsetLow,
+- DWORD dwFileOffsetHigh,
+- DWORD nNumberOfBytesToUnlockLow,
+- DWORD nNumberOfBytesToUnlockHigh
+-){
+- winFile *pFile = HANDLE_TO_WINFILE(phFile);
+- BOOL bReturn = FALSE;
+-
+- UNUSED_PARAMETER(dwFileOffsetHigh);
+- UNUSED_PARAMETER(nNumberOfBytesToUnlockHigh);
+-
+- if (!pFile->hMutex) return TRUE;
+- winceMutexAcquire(pFile->hMutex);
++SQLITE_API int SQLITE_STDCALL sqlite3_win32_reset_heap(){
++ int rc;
++ MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */
++ MUTEX_LOGIC( sqlite3_mutex *pMem; ) /* The memsys static mutex */
++ MUTEX_LOGIC( pMaster = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); )
++ MUTEX_LOGIC( pMem = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM); )
++ sqlite3_mutex_enter(pMaster);
++ sqlite3_mutex_enter(pMem);
++ winMemAssertMagic();
++ if( winMemGetHeap()!=NULL && winMemGetOwned() && sqlite3_memory_used()==0 ){
++ /*
++ ** At this point, there should be no outstanding memory allocations on
++ ** the heap. Also, since both the master and memsys locks are currently
++ ** being held by us, no other function (i.e. from another thread) should
++ ** be able to even access the heap. Attempt to destroy and recreate our
++ ** isolated Win32 native heap now.
++ */
++ assert( winMemGetHeap()!=NULL );
++ assert( winMemGetOwned() );
++ assert( sqlite3_memory_used()==0 );
++ winMemShutdown(winMemGetDataPtr());
++ assert( winMemGetHeap()==NULL );
++ assert( !winMemGetOwned() );
++ assert( sqlite3_memory_used()==0 );
++ rc = winMemInit(winMemGetDataPtr());
++ assert( rc!=SQLITE_OK || winMemGetHeap()!=NULL );
++ assert( rc!=SQLITE_OK || winMemGetOwned() );
++ assert( rc!=SQLITE_OK || sqlite3_memory_used()==0 );
++ }else{
++ /*
++ ** The Win32 native heap cannot be modified because it may be in use.
++ */
++ rc = SQLITE_BUSY;
++ }
++ sqlite3_mutex_leave(pMem);
++ sqlite3_mutex_leave(pMaster);
++ return rc;
++}
++#endif /* SQLITE_WIN32_MALLOC */
+
+- /* Releasing a reader lock or an exclusive lock */
+- if (dwFileOffsetLow == (DWORD)SHARED_FIRST){
+- /* Did we have an exclusive lock? */
+- if (pFile->local.bExclusive){
+- assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE);
+- pFile->local.bExclusive = FALSE;
+- pFile->shared->bExclusive = FALSE;
+- bReturn = TRUE;
+- }
++/*
++** This function outputs the specified (ANSI) string to the Win32 debugger
++** (if available).
++*/
+
+- /* Did we just have a reader lock? */
+- else if (pFile->local.nReaders){
+- assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE
+- || nNumberOfBytesToUnlockLow == 1);
+- pFile->local.nReaders --;
+- if (pFile->local.nReaders == 0)
+- {
+- pFile->shared->nReaders --;
+- }
+- bReturn = TRUE;
+- }
++SQLITE_API void SQLITE_STDCALL sqlite3_win32_write_debug(const char *zBuf, int nBuf){
++ char zDbgBuf[SQLITE_WIN32_DBG_BUF_SIZE];
++ int nMin = MIN(nBuf, (SQLITE_WIN32_DBG_BUF_SIZE - 1)); /* may be negative. */
++ if( nMin<-1 ) nMin = -1; /* all negative values become -1. */
++ assert( nMin==-1 || nMin==0 || nMin<SQLITE_WIN32_DBG_BUF_SIZE );
++#if defined(SQLITE_WIN32_HAS_ANSI)
++ if( nMin>0 ){
++ memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE);
++ memcpy(zDbgBuf, zBuf, nMin);
++ osOutputDebugStringA(zDbgBuf);
++ }else{
++ osOutputDebugStringA(zBuf);
+ }
+-
+- /* Releasing a pending lock */
+- else if (dwFileOffsetLow == (DWORD)PENDING_BYTE
+- && nNumberOfBytesToUnlockLow == 1){
+- if (pFile->local.bPending){
+- pFile->local.bPending = FALSE;
+- pFile->shared->bPending = FALSE;
+- bReturn = TRUE;
+- }
++#elif defined(SQLITE_WIN32_HAS_WIDE)
++ memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE);
++ if ( osMultiByteToWideChar(
++ osAreFileApisANSI() ? CP_ACP : CP_OEMCP, 0, zBuf,
++ nMin, (LPWSTR)zDbgBuf, SQLITE_WIN32_DBG_BUF_SIZE/sizeof(WCHAR))<=0 ){
++ return;
+ }
+- /* Releasing a reserved lock */
+- else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE
+- && nNumberOfBytesToUnlockLow == 1){
+- if (pFile->local.bReserved) {
+- pFile->local.bReserved = FALSE;
+- pFile->shared->bReserved = FALSE;
+- bReturn = TRUE;
+- }
++ osOutputDebugStringW((LPCWSTR)zDbgBuf);
++#else
++ if( nMin>0 ){
++ memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE);
++ memcpy(zDbgBuf, zBuf, nMin);
++ fprintf(stderr, "%s", zDbgBuf);
++ }else{
++ fprintf(stderr, "%s", zBuf);
+ }
++#endif
++}
+
+- winceMutexRelease(pFile->hMutex);
+- return bReturn;
++/*
++** The following routine suspends the current thread for at least ms
++** milliseconds. This is equivalent to the Win32 Sleep() interface.
++*/
++#if SQLITE_OS_WINRT
++static HANDLE sleepObj = NULL;
++#endif
++
++SQLITE_API void SQLITE_STDCALL sqlite3_win32_sleep(DWORD milliseconds){
++#if SQLITE_OS_WINRT
++ if ( sleepObj==NULL ){
++ sleepObj = osCreateEventExW(NULL, NULL, CREATE_EVENT_MANUAL_RESET,
++ SYNCHRONIZE);
++ }
++ assert( sleepObj!=NULL );
++ osWaitForSingleObjectEx(sleepObj, milliseconds, FALSE);
++#else
++ osSleep(milliseconds);
++#endif
++}
++
++#if SQLITE_MAX_WORKER_THREADS>0 && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \
++ SQLITE_THREADSAFE>0
++SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject){
++ DWORD rc;
++ while( (rc = osWaitForSingleObjectEx(hObject, INFINITE,
++ TRUE))==WAIT_IO_COMPLETION ){}
++ return rc;
+ }
++#endif
++
+ /*
+-** End of the special code for wince
+-*****************************************************************************/
+-#endif /* SQLITE_OS_WINCE */
++** Return true (non-zero) if we are running under WinNT, Win2K, WinXP,
++** or WinCE. Return false (zero) for Win95, Win98, or WinME.
++**
++** Here is an interesting observation: Win95, Win98, and WinME lack
++** the LockFileEx() API. But we can still statically link against that
++** API as long as we don't call it when running Win95/98/ME. A call to
++** this routine is used to determine if the host is Win95/98/ME or
++** WinNT/2K/XP so that we will know whether or not we can safely call
++** the LockFileEx() API.
++*/
++
++#if !defined(SQLITE_WIN32_GETVERSIONEX) || !SQLITE_WIN32_GETVERSIONEX
++# define osIsNT() (1)
++#elif SQLITE_OS_WINCE || SQLITE_OS_WINRT || !defined(SQLITE_WIN32_HAS_ANSI)
++# define osIsNT() (1)
++#elif !defined(SQLITE_WIN32_HAS_WIDE)
++# define osIsNT() (0)
++#else
++# define osIsNT() ((sqlite3_os_type==2) || sqlite3_win32_is_nt())
++#endif
+
+ /*
+-** Lock a file region.
++** This function determines if the machine is running a version of Windows
++** based on the NT kernel.
+ */
+-static BOOL winLockFile(
+- LPHANDLE phFile,
+- DWORD flags,
+- DWORD offsetLow,
+- DWORD offsetHigh,
+- DWORD numBytesLow,
+- DWORD numBytesHigh
+-){
+-#if SQLITE_OS_WINCE
++SQLITE_API int SQLITE_STDCALL sqlite3_win32_is_nt(void){
++#if SQLITE_OS_WINRT
+ /*
+- ** NOTE: Windows CE is handled differently here due its lack of the Win32
+- ** API LockFile.
++ ** NOTE: The WinRT sub-platform is always assumed to be based on the NT
++ ** kernel.
+ */
+- return winceLockFile(phFile, offsetLow, offsetHigh,
+- numBytesLow, numBytesHigh);
++ return 1;
++#elif defined(SQLITE_WIN32_GETVERSIONEX) && SQLITE_WIN32_GETVERSIONEX
++ if( osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0 ){
++#if defined(SQLITE_WIN32_HAS_ANSI)
++ OSVERSIONINFOA sInfo;
++ sInfo.dwOSVersionInfoSize = sizeof(sInfo);
++ osGetVersionExA(&sInfo);
++ osInterlockedCompareExchange(&sqlite3_os_type,
++ (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0);
++#elif defined(SQLITE_WIN32_HAS_WIDE)
++ OSVERSIONINFOW sInfo;
++ sInfo.dwOSVersionInfoSize = sizeof(sInfo);
++ osGetVersionExW(&sInfo);
++ osInterlockedCompareExchange(&sqlite3_os_type,
++ (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0);
++#endif
++ }
++ return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2;
++#elif SQLITE_TEST
++ return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2;
+ #else
+- if( osIsNT() ){
+- OVERLAPPED ovlp;
+- memset(&ovlp, 0, sizeof(OVERLAPPED));
+- ovlp.Offset = offsetLow;
+- ovlp.OffsetHigh = offsetHigh;
+- return osLockFileEx(*phFile, flags, 0, numBytesLow, numBytesHigh, &ovlp);
+- }else{
+- return osLockFile(*phFile, offsetLow, offsetHigh, numBytesLow,
+- numBytesHigh);
++ /*
++ ** NOTE: All sub-platforms where the GetVersionEx[AW] functions are
++ ** deprecated are always assumed to be based on the NT kernel.
++ */
++ return 1;
++#endif
++}
++
++#ifdef SQLITE_WIN32_MALLOC
++/*
++** Allocate nBytes of memory.
++*/
++static void *winMemMalloc(int nBytes){
++ HANDLE hHeap;
++ void *p;
++
++ winMemAssertMagic();
++ hHeap = winMemGetHeap();
++ assert( hHeap!=0 );
++ assert( hHeap!=INVALID_HANDLE_VALUE );
++#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE)
++ assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
++#endif
++ assert( nBytes>=0 );
++ p = osHeapAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, (SIZE_T)nBytes);
++ if( !p ){
++ sqlite3_log(SQLITE_NOMEM, "failed to HeapAlloc %u bytes (%lu), heap=%p",
++ nBytes, osGetLastError(), (void*)hHeap);
+ }
++ return p;
++}
++
++/*
++** Free memory.
++*/
++static void winMemFree(void *pPrior){
++ HANDLE hHeap;
++
++ winMemAssertMagic();
++ hHeap = winMemGetHeap();
++ assert( hHeap!=0 );
++ assert( hHeap!=INVALID_HANDLE_VALUE );
++#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE)
++ assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) );
#endif
++ if( !pPrior ) return; /* Passing NULL to HeapFree is undefined. */
++ if( !osHeapFree(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) ){
++ sqlite3_log(SQLITE_NOMEM, "failed to HeapFree block %p (%lu), heap=%p",
++ pPrior, osGetLastError(), (void*)hHeap);
++ }
+ }
--#endif /* SQLITE_OMIT_DISKIO */
-+#endif /* SQLITE_OMIT_DISKIO */
+ /*
+-** Unlock a file region.
+- */
+-static BOOL winUnlockFile(
+- LPHANDLE phFile,
+- DWORD offsetLow,
+- DWORD offsetHigh,
+- DWORD numBytesLow,
+- DWORD numBytesHigh
+-){
+-#if SQLITE_OS_WINCE
+- /*
+- ** NOTE: Windows CE is handled differently here due its lack of the Win32
+- ** API UnlockFile.
+- */
+- return winceUnlockFile(phFile, offsetLow, offsetHigh,
+- numBytesLow, numBytesHigh);
+-#else
+- if( osIsNT() ){
+- OVERLAPPED ovlp;
+- memset(&ovlp, 0, sizeof(OVERLAPPED));
+- ovlp.Offset = offsetLow;
+- ovlp.OffsetHigh = offsetHigh;
+- return osUnlockFileEx(*phFile, 0, numBytesLow, numBytesHigh, &ovlp);
+- }else{
+- return osUnlockFile(*phFile, offsetLow, offsetHigh, numBytesLow,
+- numBytesHigh);
++** Change the size of an existing memory allocation
++*/
++static void *winMemRealloc(void *pPrior, int nBytes){
++ HANDLE hHeap;
++ void *p;
++
++ winMemAssertMagic();
++ hHeap = winMemGetHeap();
++ assert( hHeap!=0 );
++ assert( hHeap!=INVALID_HANDLE_VALUE );
++#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE)
++ assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) );
++#endif
++ assert( nBytes>=0 );
++ if( !pPrior ){
++ p = osHeapAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, (SIZE_T)nBytes);
++ }else{
++ p = osHeapReAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior, (SIZE_T)nBytes);
+ }
+-#endif
++ if( !p ){
++ sqlite3_log(SQLITE_NOMEM, "failed to %s %u bytes (%lu), heap=%p",
++ pPrior ? "HeapReAlloc" : "HeapAlloc", nBytes, osGetLastError(),
++ (void*)hHeap);
++ }
++ return p;
+ }
+
+-/*****************************************************************************
+-** The next group of routines implement the I/O methods specified
+-** by the sqlite3_io_methods object.
+-******************************************************************************/
+-
+ /*
+-** Some Microsoft compilers lack this definition.
++** Return the size of an outstanding allocation, in bytes.
+ */
+-#ifndef INVALID_SET_FILE_POINTER
+-# define INVALID_SET_FILE_POINTER ((DWORD)-1)
++static int winMemSize(void *p){
++ HANDLE hHeap;
++ SIZE_T n;
++
++ winMemAssertMagic();
++ hHeap = winMemGetHeap();
++ assert( hHeap!=0 );
++ assert( hHeap!=INVALID_HANDLE_VALUE );
++#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE)
++ assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, p) );
+ #endif
++ if( !p ) return 0;
++ n = osHeapSize(hHeap, SQLITE_WIN32_HEAP_FLAGS, p);
++ if( n==(SIZE_T)-1 ){
++ sqlite3_log(SQLITE_NOMEM, "failed to HeapSize block %p (%lu), heap=%p",
++ p, osGetLastError(), (void*)hHeap);
++ return 0;
++ }
++ return (int)n;
++}
+
+ /*
+-** Move the current position of the file handle passed as the first
+-** argument to offset iOffset within the file. If successful, return 0.
+-** Otherwise, set pFile->lastErrno and return non-zero.
++** Round up a request size to the next valid allocation size.
+ */
+-static int winSeekFile(winFile *pFile, sqlite3_int64 iOffset){
+-#if !SQLITE_OS_WINRT
+- LONG upperBits; /* Most sig. 32 bits of new offset */
+- LONG lowerBits; /* Least sig. 32 bits of new offset */
+- DWORD dwRet; /* Value returned by SetFilePointer() */
+- DWORD lastErrno; /* Value returned by GetLastError() */
+-
+- OSTRACE(("SEEK file=%p, offset=%lld\n", pFile->h, iOffset));
++static int winMemRoundup(int n){
++ return n;
++}
+
+- upperBits = (LONG)((iOffset>>32) & 0x7fffffff);
+- lowerBits = (LONG)(iOffset & 0xffffffff);
++/*
++** Initialize this module.
++*/
++static int winMemInit(void *pAppData){
++ winMemData *pWinMemData = (winMemData *)pAppData;
+
+- /* API oddity: If successful, SetFilePointer() returns a dword
+- ** containing the lower 32-bits of the new file-offset. Or, if it fails,
+- ** it returns INVALID_SET_FILE_POINTER. However according to MSDN,
+- ** INVALID_SET_FILE_POINTER may also be a valid new offset. So to determine
+- ** whether an error has actually occurred, it is also necessary to call
+- ** GetLastError().
+- */
+- dwRet = osSetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
++ if( !pWinMemData ) return SQLITE_ERROR;
++ assert( pWinMemData->magic1==WINMEM_MAGIC1 );
++ assert( pWinMemData->magic2==WINMEM_MAGIC2 );
+
+- if( (dwRet==INVALID_SET_FILE_POINTER
+- && ((lastErrno = osGetLastError())!=NO_ERROR)) ){
+- pFile->lastErrno = lastErrno;
+- winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno,
+- "winSeekFile", pFile->zPath);
+- OSTRACE(("SEEK file=%p, rc=SQLITE_IOERR_SEEK\n", pFile->h));
+- return 1;
++#if !SQLITE_OS_WINRT && SQLITE_WIN32_HEAP_CREATE
++ if( !pWinMemData->hHeap ){
++ DWORD dwInitialSize = SQLITE_WIN32_HEAP_INIT_SIZE;
++ DWORD dwMaximumSize = (DWORD)sqlite3GlobalConfig.nHeap;
++ if( dwMaximumSize==0 ){
++ dwMaximumSize = SQLITE_WIN32_HEAP_MAX_SIZE;
++ }else if( dwInitialSize>dwMaximumSize ){
++ dwInitialSize = dwMaximumSize;
++ }
++ pWinMemData->hHeap = osHeapCreate(SQLITE_WIN32_HEAP_FLAGS,
++ dwInitialSize, dwMaximumSize);
++ if( !pWinMemData->hHeap ){
++ sqlite3_log(SQLITE_NOMEM,
++ "failed to HeapCreate (%lu), flags=%u, initSize=%lu, maxSize=%lu",
++ osGetLastError(), SQLITE_WIN32_HEAP_FLAGS, dwInitialSize,
++ dwMaximumSize);
++ return SQLITE_NOMEM;
++ }
++ pWinMemData->bOwned = TRUE;
++ assert( pWinMemData->bOwned );
+ }
+-
+- OSTRACE(("SEEK file=%p, rc=SQLITE_OK\n", pFile->h));
+- return 0;
+ #else
+- /*
+- ** Same as above, except that this implementation works for WinRT.
+- */
+-
+- LARGE_INTEGER x; /* The new offset */
+- BOOL bRet; /* Value returned by SetFilePointerEx() */
+-
+- x.QuadPart = iOffset;
+- bRet = osSetFilePointerEx(pFile->h, x, 0, FILE_BEGIN);
+-
+- if(!bRet){
+- pFile->lastErrno = osGetLastError();
+- winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno,
+- "winSeekFile", pFile->zPath);
+- OSTRACE(("SEEK file=%p, rc=SQLITE_IOERR_SEEK\n", pFile->h));
+- return 1;
++ pWinMemData->hHeap = osGetProcessHeap();
++ if( !pWinMemData->hHeap ){
++ sqlite3_log(SQLITE_NOMEM,
++ "failed to GetProcessHeap (%lu)", osGetLastError());
++ return SQLITE_NOMEM;
+ }
+-
+- OSTRACE(("SEEK file=%p, rc=SQLITE_OK\n", pFile->h));
+- return 0;
++ pWinMemData->bOwned = FALSE;
++ assert( !pWinMemData->bOwned );
+ #endif
+-}
+-
+-#if SQLITE_MAX_MMAP_SIZE>0
+-/* Forward references to VFS helper methods used for memory mapped files */
+-static int winMapfile(winFile*, sqlite3_int64);
+-static int winUnmapfile(winFile*);
++ assert( pWinMemData->hHeap!=0 );
++ assert( pWinMemData->hHeap!=INVALID_HANDLE_VALUE );
++#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE)
++ assert( osHeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
+ #endif
++ return SQLITE_OK;
++}
+
+ /*
+-** Close a file.
+-**
+-** It is reported that an attempt to close a handle might sometimes
+-** fail. This is a very unreasonable result, but Windows is notorious
+-** for being unreasonable so I do not doubt that it might happen. If
+-** the close fails, we pause for 100 milliseconds and try again. As
+-** many as MX_CLOSE_ATTEMPT attempts to close the handle are made before
+-** giving up and returning an error.
++** Deinitialize this module.
+ */
+-#define MX_CLOSE_ATTEMPT 3
+-static int winClose(sqlite3_file *id){
+- int rc, cnt = 0;
+- winFile *pFile = (winFile*)id;
++static void winMemShutdown(void *pAppData){
++ winMemData *pWinMemData = (winMemData *)pAppData;
+
+- assert( id!=0 );
+-#ifndef SQLITE_OMIT_WAL
+- assert( pFile->pShm==0 );
+-#endif
+- assert( pFile->h!=NULL && pFile->h!=INVALID_HANDLE_VALUE );
+- OSTRACE(("CLOSE pid=%lu, pFile=%p, file=%p\n",
+- osGetCurrentProcessId(), pFile, pFile->h));
++ if( !pWinMemData ) return;
++ assert( pWinMemData->magic1==WINMEM_MAGIC1 );
++ assert( pWinMemData->magic2==WINMEM_MAGIC2 );
+
+-#if SQLITE_MAX_MMAP_SIZE>0
+- winUnmapfile(pFile);
++ if( pWinMemData->hHeap ){
++ assert( pWinMemData->hHeap!=INVALID_HANDLE_VALUE );
++#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE)
++ assert( osHeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
+ #endif
+-
+- do{
+- rc = osCloseHandle(pFile->h);
+- /* SimulateIOError( rc=0; cnt=MX_CLOSE_ATTEMPT; ); */
+- }while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (sqlite3_win32_sleep(100), 1) );
+-#if SQLITE_OS_WINCE
+-#define WINCE_DELETION_ATTEMPTS 3
+- winceDestroyLock(pFile);
+- if( pFile->zDeleteOnClose ){
+- int cnt = 0;
+- while(
+- osDeleteFileW(pFile->zDeleteOnClose)==0
+- && osGetFileAttributesW(pFile->zDeleteOnClose)!=0xffffffff
+- && cnt++ < WINCE_DELETION_ATTEMPTS
+- ){
+- sqlite3_win32_sleep(100); /* Wait a little before trying again */
++ if( pWinMemData->bOwned ){
++ if( !osHeapDestroy(pWinMemData->hHeap) ){
++ sqlite3_log(SQLITE_NOMEM, "failed to HeapDestroy (%lu), heap=%p",
++ osGetLastError(), (void*)pWinMemData->hHeap);
++ }
++ pWinMemData->bOwned = FALSE;
+ }
+- sqlite3_free(pFile->zDeleteOnClose);
+- }
+-#endif
+- if( rc ){
+- pFile->h = NULL;
++ pWinMemData->hHeap = NULL;
+ }
+- OpenCounter(-1);
+- OSTRACE(("CLOSE pid=%lu, pFile=%p, file=%p, rc=%s\n",
+- osGetCurrentProcessId(), pFile, pFile->h, rc ? "ok" : "failed"));
+- return rc ? SQLITE_OK
+- : winLogError(SQLITE_IOERR_CLOSE, osGetLastError(),
+- "winClose", pFile->zPath);
+ }
+
+ /*
+-** Read data from a file into a buffer. Return SQLITE_OK if all
+-** bytes were read successfully and SQLITE_IOERR if anything goes
+-** wrong.
++** Populate the low-level memory allocation function pointers in
++** sqlite3GlobalConfig.m with pointers to the routines in this file. The
++** arguments specify the block of memory to manage.
++**
++** This routine is only called by sqlite3_config(), and therefore
++** is not required to be threadsafe (it is not).
+ */
+-static int winRead(
+- sqlite3_file *id, /* File to read from */
+- void *pBuf, /* Write content into this buffer */
+- int amt, /* Number of bytes to read */
+- sqlite3_int64 offset /* Begin reading at this offset */
+-){
+-#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
+- OVERLAPPED overlapped; /* The offset for ReadFile. */
+-#endif
+- winFile *pFile = (winFile*)id; /* file handle */
+- DWORD nRead; /* Number of bytes actually read from file */
+- int nRetry = 0; /* Number of retrys */
++SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetWin32(void){
++ static const sqlite3_mem_methods winMemMethods = {
++ winMemMalloc,
++ winMemFree,
++ winMemRealloc,
++ winMemSize,
++ winMemRoundup,
++ winMemInit,
++ winMemShutdown,
++ &win_mem_data
++ };
++ return &winMemMethods;
++}
+
+- assert( id!=0 );
+- assert( amt>0 );
+- assert( offset>=0 );
+- SimulateIOError(return SQLITE_IOERR_READ);
+- OSTRACE(("READ pid=%lu, pFile=%p, file=%p, buffer=%p, amount=%d, "
+- "offset=%lld, lock=%d\n", osGetCurrentProcessId(), pFile,
+- pFile->h, pBuf, amt, offset, pFile->locktype));
++SQLITE_PRIVATE void sqlite3MemSetDefault(void){
++ sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetWin32());
++}
++#endif /* SQLITE_WIN32_MALLOC */
+
+-#if SQLITE_MAX_MMAP_SIZE>0
+- /* Deal with as much of this read request as possible by transfering
+- ** data from the memory mapping using memcpy(). */
+- if( offset<pFile->mmapSize ){
+- if( offset+amt <= pFile->mmapSize ){
+- memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], amt);
+- OSTRACE(("READ-MMAP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
+- osGetCurrentProcessId(), pFile, pFile->h));
+- return SQLITE_OK;
+- }else{
+- int nCopy = (int)(pFile->mmapSize - offset);
+- memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], nCopy);
+- pBuf = &((u8 *)pBuf)[nCopy];
+- amt -= nCopy;
+- offset += nCopy;
+- }
+- }
+-#endif
++/*
++** Convert a UTF-8 string to Microsoft Unicode (UTF-16?).
++**
++** Space to hold the returned string is obtained from malloc.
++*/
++static LPWSTR winUtf8ToUnicode(const char *zFilename){
++ int nChar;
++ LPWSTR zWideFilename;
+
+-#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED)
+- if( winSeekFile(pFile, offset) ){
+- OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_FULL\n",
+- osGetCurrentProcessId(), pFile, pFile->h));
+- return SQLITE_FULL;
++ nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
++ if( nChar==0 ){
++ return 0;
+ }
+- while( !osReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
+-#else
+- memset(&overlapped, 0, sizeof(OVERLAPPED));
+- overlapped.Offset = (LONG)(offset & 0xffffffff);
+- overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
+- while( !osReadFile(pFile->h, pBuf, amt, &nRead, &overlapped) &&
+- osGetLastError()!=ERROR_HANDLE_EOF ){
+-#endif
+- DWORD lastErrno;
+- if( winRetryIoerr(&nRetry, &lastErrno) ) continue;
+- pFile->lastErrno = lastErrno;
+- OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_READ\n",
+- osGetCurrentProcessId(), pFile, pFile->h));
+- return winLogError(SQLITE_IOERR_READ, pFile->lastErrno,
+- "winRead", pFile->zPath);
++ zWideFilename = sqlite3MallocZero( nChar*sizeof(zWideFilename[0]) );
++ if( zWideFilename==0 ){
++ return 0;
+ }
+- winLogIoerr(nRetry, __LINE__);
+- if( nRead<(DWORD)amt ){
+- /* Unread parts of the buffer must be zero-filled */
+- memset(&((char*)pBuf)[nRead], 0, amt-nRead);
+- OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_SHORT_READ\n",
+- osGetCurrentProcessId(), pFile, pFile->h));
+- return SQLITE_IOERR_SHORT_READ;
++ nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename,
++ nChar);
++ if( nChar==0 ){
++ sqlite3_free(zWideFilename);
++ zWideFilename = 0;
+ }
+-
+- OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
+- osGetCurrentProcessId(), pFile, pFile->h));
+- return SQLITE_OK;
++ return zWideFilename;
+ }
+
+ /*
+-** Write data from a buffer into a file. Return SQLITE_OK on success
+-** or some other error code on failure.
++** Convert Microsoft Unicode to UTF-8. Space to hold the returned string is
++** obtained from sqlite3_malloc().
+ */
+-static int winWrite(
+- sqlite3_file *id, /* File to write into */
+- const void *pBuf, /* The bytes to be written */
+- int amt, /* Number of bytes to write */
+- sqlite3_int64 offset /* Offset into the file to begin writing at */
+-){
+- int rc = 0; /* True if error has occurred, else false */
+- winFile *pFile = (winFile*)id; /* File handle */
+- int nRetry = 0; /* Number of retries */
+-
+- assert( amt>0 );
+- assert( pFile );
+- SimulateIOError(return SQLITE_IOERR_WRITE);
+- SimulateDiskfullError(return SQLITE_FULL);
+-
+- OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, buffer=%p, amount=%d, "
+- "offset=%lld, lock=%d\n", osGetCurrentProcessId(), pFile,
+- pFile->h, pBuf, amt, offset, pFile->locktype));
++static char *winUnicodeToUtf8(LPCWSTR zWideFilename){
++ int nByte;
++ char *zFilename;
+
+-#if SQLITE_MAX_MMAP_SIZE>0
+- /* Deal with as much of this write request as possible by transfering
+- ** data from the memory mapping using memcpy(). */
+- if( offset<pFile->mmapSize ){
+- if( offset+amt <= pFile->mmapSize ){
+- memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, amt);
+- OSTRACE(("WRITE-MMAP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
+- osGetCurrentProcessId(), pFile, pFile->h));
+- return SQLITE_OK;
+- }else{
+- int nCopy = (int)(pFile->mmapSize - offset);
+- memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, nCopy);
+- pBuf = &((u8 *)pBuf)[nCopy];
+- amt -= nCopy;
+- offset += nCopy;
+- }
++ nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0);
++ if( nByte == 0 ){
++ return 0;
+ }
+-#endif
+-
+-#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED)
+- rc = winSeekFile(pFile, offset);
+- if( rc==0 ){
+-#else
+- {
+-#endif
+-#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
+- OVERLAPPED overlapped; /* The offset for WriteFile. */
+-#endif
+- u8 *aRem = (u8 *)pBuf; /* Data yet to be written */
+- int nRem = amt; /* Number of bytes yet to be written */
+- DWORD nWrite; /* Bytes written by each WriteFile() call */
+- DWORD lastErrno = NO_ERROR; /* Value returned by GetLastError() */
++ zFilename = sqlite3MallocZero( nByte );
++ if( zFilename==0 ){
++ return 0;
++ }
++ nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, zFilename, nByte,
++ 0, 0);
++ if( nByte == 0 ){
++ sqlite3_free(zFilename);
++ zFilename = 0;
++ }
++ return zFilename;
++}
+
+-#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
+- memset(&overlapped, 0, sizeof(OVERLAPPED));
+- overlapped.Offset = (LONG)(offset & 0xffffffff);
+- overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
+-#endif
++/*
++** Convert an ANSI string to Microsoft Unicode, based on the
++** current codepage settings for file apis.
++**
++** Space to hold the returned string is obtained
++** from sqlite3_malloc.
++*/
++static LPWSTR winMbcsToUnicode(const char *zFilename){
++ int nByte;
++ LPWSTR zMbcsFilename;
++ int codepage = osAreFileApisANSI() ? CP_ACP : CP_OEMCP;
+
+- while( nRem>0 ){
+-#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED)
+- if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, 0) ){
+-#else
+- if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, &overlapped) ){
+-#endif
+- if( winRetryIoerr(&nRetry, &lastErrno) ) continue;
+- break;
+- }
+- assert( nWrite==0 || nWrite<=(DWORD)nRem );
+- if( nWrite==0 || nWrite>(DWORD)nRem ){
+- lastErrno = osGetLastError();
+- break;
+- }
+-#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
+- offset += nWrite;
+- overlapped.Offset = (LONG)(offset & 0xffffffff);
+- overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
+-#endif
+- aRem += nWrite;
+- nRem -= nWrite;
+- }
+- if( nRem>0 ){
+- pFile->lastErrno = lastErrno;
+- rc = 1;
+- }
++ nByte = osMultiByteToWideChar(codepage, 0, zFilename, -1, NULL,
++ 0)*sizeof(WCHAR);
++ if( nByte==0 ){
++ return 0;
+ }
+-
+- if( rc ){
+- if( ( pFile->lastErrno==ERROR_HANDLE_DISK_FULL )
+- || ( pFile->lastErrno==ERROR_DISK_FULL )){
+- OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_FULL\n",
+- osGetCurrentProcessId(), pFile, pFile->h));
+- return winLogError(SQLITE_FULL, pFile->lastErrno,
+- "winWrite1", pFile->zPath);
+- }
+- OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_WRITE\n",
+- osGetCurrentProcessId(), pFile, pFile->h));
+- return winLogError(SQLITE_IOERR_WRITE, pFile->lastErrno,
+- "winWrite2", pFile->zPath);
+- }else{
+- winLogIoerr(nRetry, __LINE__);
++ zMbcsFilename = sqlite3MallocZero( nByte*sizeof(zMbcsFilename[0]) );
++ if( zMbcsFilename==0 ){
++ return 0;
+ }
+- OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
+- osGetCurrentProcessId(), pFile, pFile->h));
+- return SQLITE_OK;
++ nByte = osMultiByteToWideChar(codepage, 0, zFilename, -1, zMbcsFilename,
++ nByte);
++ if( nByte==0 ){
++ sqlite3_free(zMbcsFilename);
++ zMbcsFilename = 0;
++ }
++ return zMbcsFilename;
+ }
+
+ /*
+-** Truncate an open file to a specified size
++** Convert Microsoft Unicode to multi-byte character string, based on the
++** user's ANSI codepage.
++**
++** Space to hold the returned string is obtained from
++** sqlite3_malloc().
+ */
+-static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
+- winFile *pFile = (winFile*)id; /* File handle object */
+- int rc = SQLITE_OK; /* Return code for this function */
+- DWORD lastErrno;
+-
+- assert( pFile );
+- SimulateIOError(return SQLITE_IOERR_TRUNCATE);
+- OSTRACE(("TRUNCATE pid=%lu, pFile=%p, file=%p, size=%lld, lock=%d\n",
+- osGetCurrentProcessId(), pFile, pFile->h, nByte, pFile->locktype));
++static char *winUnicodeToMbcs(LPCWSTR zWideFilename){
++ int nByte;
++ char *zFilename;
++ int codepage = osAreFileApisANSI() ? CP_ACP : CP_OEMCP;
+
+- /* If the user has configured a chunk-size for this file, truncate the
+- ** file so that it consists of an integer number of chunks (i.e. the
+- ** actual file size after the operation may be larger than the requested
+- ** size).
+- */
+- if( pFile->szChunk>0 ){
+- nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
++ nByte = osWideCharToMultiByte(codepage, 0, zWideFilename, -1, 0, 0, 0, 0);
++ if( nByte == 0 ){
++ return 0;
+ }
+-
+- /* SetEndOfFile() returns non-zero when successful, or zero when it fails. */
+- if( winSeekFile(pFile, nByte) ){
+- rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno,
+- "winTruncate1", pFile->zPath);
+- }else if( 0==osSetEndOfFile(pFile->h) &&
+- ((lastErrno = osGetLastError())!=ERROR_USER_MAPPED_FILE) ){
+- pFile->lastErrno = lastErrno;
+- rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno,
+- "winTruncate2", pFile->zPath);
++ zFilename = sqlite3MallocZero( nByte );
++ if( zFilename==0 ){
++ return 0;
+ }
+-
+-#if SQLITE_MAX_MMAP_SIZE>0
+- /* If the file was truncated to a size smaller than the currently
+- ** mapped region, reduce the effective mapping size as well. SQLite will
+- ** use read() and write() to access data beyond this point from now on.
+- */
+- if( pFile->pMapRegion && nByte<pFile->mmapSize ){
+- pFile->mmapSize = nByte;
++ nByte = osWideCharToMultiByte(codepage, 0, zWideFilename, -1, zFilename,
++ nByte, 0, 0);
++ if( nByte == 0 ){
++ sqlite3_free(zFilename);
++ zFilename = 0;
+ }
+-#endif
+-
+- OSTRACE(("TRUNCATE pid=%lu, pFile=%p, file=%p, rc=%s\n",
+- osGetCurrentProcessId(), pFile, pFile->h, sqlite3ErrName(rc)));
+- return rc;
++ return zFilename;
+ }
+
+-#ifdef SQLITE_TEST
+ /*
+-** Count the number of fullsyncs and normal syncs. This is used to test
+-** that syncs and fullsyncs are occuring at the right times.
++** Convert multibyte character string to UTF-8. Space to hold the
++** returned string is obtained from sqlite3_malloc().
+ */
+-SQLITE_API int sqlite3_sync_count = 0;
+-SQLITE_API int sqlite3_fullsync_count = 0;
+-#endif
++SQLITE_API char *SQLITE_STDCALL sqlite3_win32_mbcs_to_utf8(const char *zFilename){
++ char *zFilenameUtf8;
++ LPWSTR zTmpWide;
+
-+/* BEGIN SQLCIPHER */
++ zTmpWide = winMbcsToUnicode(zFilename);
++ if( zTmpWide==0 ){
++ return 0;
++ }
++ zFilenameUtf8 = winUnicodeToUtf8(zTmpWide);
++ sqlite3_free(zTmpWide);
++ return zFilenameUtf8;
++}
+
+ /*
+-** Make sure all writes to a particular file are committed to disk.
++** Convert UTF-8 to multibyte character string. Space to hold the
++** returned string is obtained from sqlite3_malloc().
+ */
+-static int winSync(sqlite3_file *id, int flags){
+-#ifndef SQLITE_NO_SYNC
+- /*
+- ** Used only when SQLITE_NO_SYNC is not defined.
+- */
+- BOOL rc;
+-#endif
+-#if !defined(NDEBUG) || !defined(SQLITE_NO_SYNC) || \
+- defined(SQLITE_HAVE_OS_TRACE)
+- /*
+- ** Used when SQLITE_NO_SYNC is not defined and by the assert() and/or
+- ** OSTRACE() macros.
+- */
+- winFile *pFile = (winFile*)id;
+-#else
+- UNUSED_PARAMETER(id);
+-#endif
+-
+- assert( pFile );
+- /* Check that one of SQLITE_SYNC_NORMAL or FULL was passed */
+- assert((flags&0x0F)==SQLITE_SYNC_NORMAL
+- || (flags&0x0F)==SQLITE_SYNC_FULL
+- );
+-
+- /* Unix cannot, but some systems may return SQLITE_FULL from here. This
+- ** line is to test that doing so does not cause any problems.
+- */
+- SimulateDiskfullError( return SQLITE_FULL );
+-
+- OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, flags=%x, lock=%d\n",
+- osGetCurrentProcessId(), pFile, pFile->h, flags,
+- pFile->locktype));
++SQLITE_API char *SQLITE_STDCALL sqlite3_win32_utf8_to_mbcs(const char *zFilename){
++ char *zFilenameMbcs;
++ LPWSTR zTmpWide;
+
+-#ifndef SQLITE_TEST
+- UNUSED_PARAMETER(flags);
+-#else
+- if( (flags&0x0F)==SQLITE_SYNC_FULL ){
+- sqlite3_fullsync_count++;
++ zTmpWide = winUtf8ToUnicode(zFilename);
++ if( zTmpWide==0 ){
++ return 0;
+ }
+- sqlite3_sync_count++;
+-#endif
++ zFilenameMbcs = winUnicodeToMbcs(zTmpWide);
++ sqlite3_free(zTmpWide);
++ return zFilenameMbcs;
++}
+
+- /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a
+- ** no-op
+- */
+-#ifdef SQLITE_NO_SYNC
+- OSTRACE(("SYNC-NOP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
+- osGetCurrentProcessId(), pFile, pFile->h));
+- return SQLITE_OK;
+-#else
+-#if SQLITE_MAX_MMAP_SIZE>0
+- if( pFile->pMapRegion ){
+- if( osFlushViewOfFile(pFile->pMapRegion, 0) ){
+- OSTRACE(("SYNC-MMAP pid=%lu, pFile=%p, pMapRegion=%p, "
+- "rc=SQLITE_OK\n", osGetCurrentProcessId(),
+- pFile, pFile->pMapRegion));
+- }else{
+- pFile->lastErrno = osGetLastError();
+- OSTRACE(("SYNC-MMAP pid=%lu, pFile=%p, pMapRegion=%p, "
+- "rc=SQLITE_IOERR_MMAP\n", osGetCurrentProcessId(),
+- pFile, pFile->pMapRegion));
+- return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno,
+- "winSync1", pFile->zPath);
+- }
+- }
++/*
++** This function sets the data directory or the temporary directory based on
++** the provided arguments. The type argument must be 1 in order to set the
++** data directory or 2 in order to set the temporary directory. The zValue
++** argument is the name of the directory to use. The return value will be
++** SQLITE_OK if successful.
++*/
++SQLITE_API int SQLITE_STDCALL sqlite3_win32_set_directory(DWORD type, LPCWSTR zValue){
++ char **ppDirectory = 0;
++#ifndef SQLITE_OMIT_AUTOINIT
++ int rc = sqlite3_initialize();
++ if( rc ) return rc;
+ #endif
+- rc = osFlushFileBuffers(pFile->h);
+- SimulateIOError( rc=FALSE );
+- if( rc ){
+- OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
+- osGetCurrentProcessId(), pFile, pFile->h));
++ if( type==SQLITE_WIN32_DATA_DIRECTORY_TYPE ){
++ ppDirectory = &sqlite3_data_directory;
++ }else if( type==SQLITE_WIN32_TEMP_DIRECTORY_TYPE ){
++ ppDirectory = &sqlite3_temp_directory;
++ }
++ assert( !ppDirectory || type==SQLITE_WIN32_DATA_DIRECTORY_TYPE
++ || type==SQLITE_WIN32_TEMP_DIRECTORY_TYPE
++ );
++ assert( !ppDirectory || sqlite3MemdebugHasType(*ppDirectory, MEMTYPE_HEAP) );
++ if( ppDirectory ){
++ char *zValueUtf8 = 0;
++ if( zValue && zValue[0] ){
++ zValueUtf8 = winUnicodeToUtf8(zValue);
++ if ( zValueUtf8==0 ){
++ return SQLITE_NOMEM;
++ }
++ }
++ sqlite3_free(*ppDirectory);
++ *ppDirectory = zValueUtf8;
+ return SQLITE_OK;
+- }else{
+- pFile->lastErrno = osGetLastError();
+- OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_FSYNC\n",
+- osGetCurrentProcessId(), pFile, pFile->h));
+- return winLogError(SQLITE_IOERR_FSYNC, pFile->lastErrno,
+- "winSync2", pFile->zPath);
+ }
+-#endif
++ return SQLITE_ERROR;
+ }
+
+ /*
+-** Determine the current size of a file in bytes
++** The return value of winGetLastErrorMsg
++** is zero if the error message fits in the buffer, or non-zero
++** otherwise (if the message was truncated).
+ */
+-static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){
+- winFile *pFile = (winFile*)id;
+- int rc = SQLITE_OK;
+-
+- assert( id!=0 );
+- assert( pSize!=0 );
+- SimulateIOError(return SQLITE_IOERR_FSTAT);
+- OSTRACE(("SIZE file=%p, pSize=%p\n", pFile->h, pSize));
++static int winGetLastErrorMsg(DWORD lastErrno, int nBuf, char *zBuf){
++ /* FormatMessage returns 0 on failure. Otherwise it
++ ** returns the number of TCHARs written to the output
++ ** buffer, excluding the terminating null char.
++ */
++ DWORD dwLen = 0;
++ char *zOut = 0;
+
++ if( osIsNT() ){
+ #if SQLITE_OS_WINRT
+- {
+- FILE_STANDARD_INFO info;
+- if( osGetFileInformationByHandleEx(pFile->h, FileStandardInfo,
+- &info, sizeof(info)) ){
+- *pSize = info.EndOfFile.QuadPart;
+- }else{
+- pFile->lastErrno = osGetLastError();
+- rc = winLogError(SQLITE_IOERR_FSTAT, pFile->lastErrno,
+- "winFileSize", pFile->zPath);
++ WCHAR zTempWide[SQLITE_WIN32_MAX_ERRMSG_CHARS+1];
++ dwLen = osFormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
++ FORMAT_MESSAGE_IGNORE_INSERTS,
++ NULL,
++ lastErrno,
++ 0,
++ zTempWide,
++ SQLITE_WIN32_MAX_ERRMSG_CHARS,
++ 0);
++#else
++ LPWSTR zTempWide = NULL;
++ dwLen = osFormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
++ FORMAT_MESSAGE_FROM_SYSTEM |
++ FORMAT_MESSAGE_IGNORE_INSERTS,
++ NULL,
++ lastErrno,
++ 0,
++ (LPWSTR) &zTempWide,
++ 0,
++ 0);
++#endif
++ if( dwLen > 0 ){
++ /* allocate a buffer and convert to UTF8 */
++ sqlite3BeginBenignMalloc();
++ zOut = winUnicodeToUtf8(zTempWide);
++ sqlite3EndBenignMalloc();
++#if !SQLITE_OS_WINRT
++ /* free the system buffer allocated by FormatMessage */
++ osLocalFree(zTempWide);
++#endif
+ }
+ }
+-#else
+- {
+- DWORD upperBits;
+- DWORD lowerBits;
+- DWORD lastErrno;
+-
+- lowerBits = osGetFileSize(pFile->h, &upperBits);
+- *pSize = (((sqlite3_int64)upperBits)<<32) + lowerBits;
+- if( (lowerBits == INVALID_FILE_SIZE)
+- && ((lastErrno = osGetLastError())!=NO_ERROR) ){
+- pFile->lastErrno = lastErrno;
+- rc = winLogError(SQLITE_IOERR_FSTAT, pFile->lastErrno,
+- "winFileSize", pFile->zPath);
++#ifdef SQLITE_WIN32_HAS_ANSI
++ else{
++ char *zTemp = NULL;
++ dwLen = osFormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
++ FORMAT_MESSAGE_FROM_SYSTEM |
++ FORMAT_MESSAGE_IGNORE_INSERTS,
++ NULL,
++ lastErrno,
++ 0,
++ (LPSTR) &zTemp,
++ 0,
++ 0);
++ if( dwLen > 0 ){
++ /* allocate a buffer and convert to UTF8 */
++ sqlite3BeginBenignMalloc();
++ zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
++ sqlite3EndBenignMalloc();
++ /* free the system buffer allocated by FormatMessage */
++ osLocalFree(zTemp);
+ }
+ }
+ #endif
+- OSTRACE(("SIZE file=%p, pSize=%p, *pSize=%lld, rc=%s\n",
+- pFile->h, pSize, *pSize, sqlite3ErrName(rc)));
+- return rc;
++ if( 0 == dwLen ){
++ sqlite3_snprintf(nBuf, zBuf, "OsError 0x%lx (%lu)", lastErrno, lastErrno);
++ }else{
++ /* copy a maximum of nBuf chars to output buffer */
++ sqlite3_snprintf(nBuf, zBuf, "%s", zOut);
++ /* free the UTF8 buffer */
++ sqlite3_free(zOut);
++ }
++ return 0;
+ }
+
+ /*
+-** LOCKFILE_FAIL_IMMEDIATELY is undefined on some Windows systems.
++**
++** This function - winLogErrorAtLine() - is only ever called via the macro
++** winLogError().
++**
++** This routine is invoked after an error occurs in an OS function.
++** It logs a message using sqlite3_log() containing the current value of
++** error code and, if possible, the human-readable equivalent from
++** FormatMessage.
++**
++** The first argument passed to the macro should be the error code that
++** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN).
++** The two subsequent arguments should be the name of the OS function that
++** failed and the associated file-system path, if any.
+ */
+-#ifndef LOCKFILE_FAIL_IMMEDIATELY
+-# define LOCKFILE_FAIL_IMMEDIATELY 1
+-#endif
++#define winLogError(a,b,c,d) winLogErrorAtLine(a,b,c,d,__LINE__)
++static int winLogErrorAtLine(
++ int errcode, /* SQLite error code */
++ DWORD lastErrno, /* Win32 last error */
++ const char *zFunc, /* Name of OS function that failed */
++ const char *zPath, /* File path associated with error */
++ int iLine /* Source line number where error occurred */
++){
++ char zMsg[500]; /* Human readable error text */
++ int i; /* Loop counter */
+
+-#ifndef LOCKFILE_EXCLUSIVE_LOCK
+-# define LOCKFILE_EXCLUSIVE_LOCK 2
+-#endif
++ zMsg[0] = 0;
++ winGetLastErrorMsg(lastErrno, sizeof(zMsg), zMsg);
++ assert( errcode!=SQLITE_OK );
++ if( zPath==0 ) zPath = "";
++ for(i=0; zMsg[i] && zMsg[i]!='\r' && zMsg[i]!='\n'; i++){}
++ zMsg[i] = 0;
++ sqlite3_log(errcode,
++ "os_win.c:%d: (%lu) %s(%s) - %s",
++ iLine, lastErrno, zFunc, zPath, zMsg
++ );
++
++ return errcode;
++}
+
+ /*
+-** Historically, SQLite has used both the LockFile and LockFileEx functions.
+-** When the LockFile function was used, it was always expected to fail
+-** immediately if the lock could not be obtained. Also, it always expected to
+-** obtain an exclusive lock. These flags are used with the LockFileEx function
+-** and reflect those expectations; therefore, they should not be changed.
++** The number of times that a ReadFile(), WriteFile(), and DeleteFile()
++** will be retried following a locking error - probably caused by
++** antivirus software. Also the initial delay before the first retry.
++** The delay increases linearly with each retry.
+ */
+-#ifndef SQLITE_LOCKFILE_FLAGS
+-# define SQLITE_LOCKFILE_FLAGS (LOCKFILE_FAIL_IMMEDIATELY | \
+- LOCKFILE_EXCLUSIVE_LOCK)
++#ifndef SQLITE_WIN32_IOERR_RETRY
++# define SQLITE_WIN32_IOERR_RETRY 10
++#endif
++#ifndef SQLITE_WIN32_IOERR_RETRY_DELAY
++# define SQLITE_WIN32_IOERR_RETRY_DELAY 25
+ #endif
++static int winIoerrRetry = SQLITE_WIN32_IOERR_RETRY;
++static int winIoerrRetryDelay = SQLITE_WIN32_IOERR_RETRY_DELAY;
+
+ /*
+-** Currently, SQLite never calls the LockFileEx function without wanting the
+-** call to fail immediately if the lock cannot be obtained.
++** The "winIoerrCanRetry1" macro is used to determine if a particular I/O
++** error code obtained via GetLastError() is eligible to be retried. It
++** must accept the error code DWORD as its only argument and should return
++** non-zero if the error code is transient in nature and the operation
++** responsible for generating the original error might succeed upon being
++** retried. The argument to this macro should be a variable.
++**
++** Additionally, a macro named "winIoerrCanRetry2" may be defined. If it
++** is defined, it will be consulted only when the macro "winIoerrCanRetry1"
++** returns zero. The "winIoerrCanRetry2" macro is completely optional and
++** may be used to include additional error codes in the set that should
++** result in the failing I/O operation being retried by the caller. If
++** defined, the "winIoerrCanRetry2" macro must exhibit external semantics
++** identical to those of the "winIoerrCanRetry1" macro.
+ */
+-#ifndef SQLITE_LOCKFILEEX_FLAGS
+-# define SQLITE_LOCKFILEEX_FLAGS (LOCKFILE_FAIL_IMMEDIATELY)
++#if !defined(winIoerrCanRetry1)
++#define winIoerrCanRetry1(a) (((a)==ERROR_ACCESS_DENIED) || \
++ ((a)==ERROR_SHARING_VIOLATION) || \
++ ((a)==ERROR_LOCK_VIOLATION) || \
++ ((a)==ERROR_DEV_NOT_EXIST) || \
++ ((a)==ERROR_NETNAME_DELETED) || \
++ ((a)==ERROR_SEM_TIMEOUT) || \
++ ((a)==ERROR_NETWORK_UNREACHABLE))
+ #endif
+
+ /*
+-** Acquire a reader lock.
+-** Different API routines are called depending on whether or not this
+-** is Win9x or WinNT.
++** If a ReadFile() or WriteFile() error occurs, invoke this routine
++** to see if it should be retried. Return TRUE to retry. Return FALSE
++** to give up with an error.
+ */
+-static int winGetReadLock(winFile *pFile){
+- int res;
+- OSTRACE(("READ-LOCK file=%p, lock=%d\n", pFile->h, pFile->locktype));
+- if( osIsNT() ){
+-#if SQLITE_OS_WINCE
+- /*
+- ** NOTE: Windows CE is handled differently here due its lack of the Win32
+- ** API LockFileEx.
+- */
+- res = winceLockFile(&pFile->h, SHARED_FIRST, 0, 1, 0);
+-#else
+- res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS, SHARED_FIRST, 0,
+- SHARED_SIZE, 0);
+-#endif
++static int winRetryIoerr(int *pnRetry, DWORD *pError){
++ DWORD e = osGetLastError();
++ if( *pnRetry>=winIoerrRetry ){
++ if( pError ){
++ *pError = e;
++ }
++ return 0;
+ }
+-#ifdef SQLITE_WIN32_HAS_ANSI
+- else{
+- int lk;
+- sqlite3_randomness(sizeof(lk), &lk);
+- pFile->sharedLockByte = (short)((lk & 0x7fffffff)%(SHARED_SIZE - 1));
+- res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS,
+- SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0);
++ if( winIoerrCanRetry1(e) ){
++ sqlite3_win32_sleep(winIoerrRetryDelay*(1+*pnRetry));
++ ++*pnRetry;
++ return 1;
++ }
++#if defined(winIoerrCanRetry2)
++ else if( winIoerrCanRetry2(e) ){
++ sqlite3_win32_sleep(winIoerrRetryDelay*(1+*pnRetry));
++ ++*pnRetry;
++ return 1;
+ }
+ #endif
+- if( res == 0 ){
+- pFile->lastErrno = osGetLastError();
+- /* No need to log a failure to lock */
++ if( pError ){
++ *pError = e;
+ }
+- OSTRACE(("READ-LOCK file=%p, result=%d\n", pFile->h, res));
+- return res;
++ return 0;
+ }
+
+ /*
+-** Undo a readlock
++** Log a I/O error retry episode.
+ */
+-static int winUnlockReadLock(winFile *pFile){
+- int res;
+- DWORD lastErrno;
+- OSTRACE(("READ-UNLOCK file=%p, lock=%d\n", pFile->h, pFile->locktype));
+- if( osIsNT() ){
+- res = winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
+- }
+-#ifdef SQLITE_WIN32_HAS_ANSI
+- else{
+- res = winUnlockFile(&pFile->h, SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0);
+- }
+-#endif
+- if( res==0 && ((lastErrno = osGetLastError())!=ERROR_NOT_LOCKED) ){
+- pFile->lastErrno = lastErrno;
+- winLogError(SQLITE_IOERR_UNLOCK, pFile->lastErrno,
+- "winUnlockReadLock", pFile->zPath);
++static void winLogIoerr(int nRetry, int lineno){
++ if( nRetry ){
++ sqlite3_log(SQLITE_NOTICE,
++ "delayed %dms for lock/sharing conflict at line %d",
++ winIoerrRetryDelay*nRetry*(nRetry+1)/2, lineno
++ );
+ }
+- OSTRACE(("READ-UNLOCK file=%p, result=%d\n", pFile->h, res));
+- return res;
+ }
+
++#if SQLITE_OS_WINCE
++/*************************************************************************
++** This section contains code for WinCE only.
++*/
++#if !defined(SQLITE_MSVC_LOCALTIME_API) || !SQLITE_MSVC_LOCALTIME_API
+ /*
+-** Lock the file with the lock specified by parameter locktype - one
+-** of the following:
+-**
+-** (1) SHARED_LOCK
+-** (2) RESERVED_LOCK
+-** (3) PENDING_LOCK
+-** (4) EXCLUSIVE_LOCK
+-**
+-** Sometimes when requesting one lock state, additional lock states
+-** are inserted in between. The locking might fail on one of the later
+-** transitions leaving the lock state different from what it started but
+-** still short of its goal. The following chart shows the allowed
+-** transitions and the inserted intermediate states:
+-**
+-** UNLOCKED -> SHARED
+-** SHARED -> RESERVED
+-** SHARED -> (PENDING) -> EXCLUSIVE
+-** RESERVED -> (PENDING) -> EXCLUSIVE
+-** PENDING -> EXCLUSIVE
+-**
+-** This routine will only increase a lock. The winUnlock() routine
+-** erases all locks at once and returns us immediately to locking level 0.
+-** It is not possible to lower the locking level one step at a time. You
+-** must go straight to locking level 0.
++** The MSVC CRT on Windows CE may not have a localtime() function. So
++** create a substitute.
+ */
+-static int winLock(sqlite3_file *id, int locktype){
+- int rc = SQLITE_OK; /* Return code from subroutines */
+- int res = 1; /* Result of a Windows lock call */
+- int newLocktype; /* Set pFile->locktype to this value before exiting */
+- int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */
+- winFile *pFile = (winFile*)id;
+- DWORD lastErrno = NO_ERROR;
++/* #include <time.h> */
++struct tm *__cdecl localtime(const time_t *t)
++{
++ static struct tm y;
++ FILETIME uTm, lTm;
++ SYSTEMTIME pTm;
++ sqlite3_int64 t64;
++ t64 = *t;
++ t64 = (t64 + 11644473600)*10000000;
++ uTm.dwLowDateTime = (DWORD)(t64 & 0xFFFFFFFF);
++ uTm.dwHighDateTime= (DWORD)(t64 >> 32);
++ osFileTimeToLocalFileTime(&uTm,&lTm);
++ osFileTimeToSystemTime(&lTm,&pTm);
++ y.tm_year = pTm.wYear - 1900;
++ y.tm_mon = pTm.wMonth - 1;
++ y.tm_wday = pTm.wDayOfWeek;
++ y.tm_mday = pTm.wDay;
++ y.tm_hour = pTm.wHour;
++ y.tm_min = pTm.wMinute;
++ y.tm_sec = pTm.wSecond;
++ return &y;
++}
++#endif
+
+- assert( id!=0 );
+- OSTRACE(("LOCK file=%p, oldLock=%d(%d), newLock=%d\n",
+- pFile->h, pFile->locktype, pFile->sharedLockByte, locktype));
++#define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-(int)offsetof(winFile,h)]
+
+- /* If there is already a lock of this type or more restrictive on the
+- ** OsFile, do nothing. Don't use the end_lock: exit path, as
+- ** sqlite3OsEnterMutex() hasn't been called yet.
+- */
+- if( pFile->locktype>=locktype ){
+- OSTRACE(("LOCK-HELD file=%p, rc=SQLITE_OK\n", pFile->h));
+- return SQLITE_OK;
++/*
++** Acquire a lock on the handle h
++*/
++static void winceMutexAcquire(HANDLE h){
++ DWORD dwErr;
++ do {
++ dwErr = osWaitForSingleObject(h, INFINITE);
++ } while (dwErr != WAIT_OBJECT_0 && dwErr != WAIT_ABANDONED);
++}
++/*
++** Release a lock acquired by winceMutexAcquire()
++*/
++#define winceMutexRelease(h) ReleaseMutex(h)
++
++/*
++** Create the mutex and shared memory used for locking in the file
++** descriptor pFile
++*/
++static int winceCreateLock(const char *zFilename, winFile *pFile){
++ LPWSTR zTok;
++ LPWSTR zName;
++ DWORD lastErrno;
++ BOOL bLogged = FALSE;
++ BOOL bInit = TRUE;
++
++ zName = winUtf8ToUnicode(zFilename);
++ if( zName==0 ){
++ /* out of memory */
++ return SQLITE_IOERR_NOMEM;
+ }
+
+- /* Make sure the locking sequence is correct
+- */
+- assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK );
+- assert( locktype!=PENDING_LOCK );
+- assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK );
++ /* Initialize the local lockdata */
++ memset(&pFile->local, 0, sizeof(pFile->local));
+
+- /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or
+- ** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of
+- ** the PENDING_LOCK byte is temporary.
+- */
+- newLocktype = pFile->locktype;
+- if( (pFile->locktype==NO_LOCK)
+- || ( (locktype==EXCLUSIVE_LOCK)
+- && (pFile->locktype==RESERVED_LOCK))
+- ){
+- int cnt = 3;
+- while( cnt-->0 && (res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS,
+- PENDING_BYTE, 0, 1, 0))==0 ){
+- /* Try 3 times to get the pending lock. This is needed to work
+- ** around problems caused by indexing and/or anti-virus software on
+- ** Windows systems.
+- ** If you are using this code as a model for alternative VFSes, do not
+- ** copy this retry logic. It is a hack intended for Windows only.
+- */
+- lastErrno = osGetLastError();
+- OSTRACE(("LOCK-PENDING-FAIL file=%p, count=%d, result=%d\n",
+- pFile->h, cnt, res));
+- if( lastErrno==ERROR_INVALID_HANDLE ){
+- pFile->lastErrno = lastErrno;
+- rc = SQLITE_IOERR_LOCK;
+- OSTRACE(("LOCK-FAIL file=%p, count=%d, rc=%s\n",
+- pFile->h, cnt, sqlite3ErrName(rc)));
+- return rc;
+- }
+- if( cnt ) sqlite3_win32_sleep(1);
+- }
+- gotPendingLock = res;
+- if( !res ){
+- lastErrno = osGetLastError();
+- }
++ /* Replace the backslashes from the filename and lowercase it
++ ** to derive a mutex name. */
++ zTok = osCharLowerW(zName);
++ for (;*zTok;zTok++){
++ if (*zTok == '\\') *zTok = '_';
+ }
+
+- /* Acquire a shared lock
+- */
+- if( locktype==SHARED_LOCK && res ){
+- assert( pFile->locktype==NO_LOCK );
+- res = winGetReadLock(pFile);
+- if( res ){
+- newLocktype = SHARED_LOCK;
+- }else{
+- lastErrno = osGetLastError();
+- }
++ /* Create/open the named mutex */
++ pFile->hMutex = osCreateMutexW(NULL, FALSE, zName);
++ if (!pFile->hMutex){
++ pFile->lastErrno = osGetLastError();
++ sqlite3_free(zName);
++ return winLogError(SQLITE_IOERR, pFile->lastErrno,
++ "winceCreateLock1", zFilename);
+ }
+
+- /* Acquire a RESERVED lock
+- */
+- if( locktype==RESERVED_LOCK && res ){
+- assert( pFile->locktype==SHARED_LOCK );
+- res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, RESERVED_BYTE, 0, 1, 0);
+- if( res ){
+- newLocktype = RESERVED_LOCK;
+- }else{
+- lastErrno = osGetLastError();
+- }
+- }
++ /* Acquire the mutex before continuing */
++ winceMutexAcquire(pFile->hMutex);
+
+- /* Acquire a PENDING lock
++ /* Since the names of named mutexes, semaphores, file mappings etc are
++ ** case-sensitive, take advantage of that by uppercasing the mutex name
++ ** and using that as the shared filemapping name.
+ */
+- if( locktype==EXCLUSIVE_LOCK && res ){
+- newLocktype = PENDING_LOCK;
+- gotPendingLock = 0;
++ osCharUpperW(zName);
++ pFile->hShared = osCreateFileMappingW(INVALID_HANDLE_VALUE, NULL,
++ PAGE_READWRITE, 0, sizeof(winceLock),
++ zName);
++
++ /* Set a flag that indicates we're the first to create the memory so it
++ ** must be zero-initialized */
++ lastErrno = osGetLastError();
++ if (lastErrno == ERROR_ALREADY_EXISTS){
++ bInit = FALSE;
+ }
+
+- /* Acquire an EXCLUSIVE lock
+- */
+- if( locktype==EXCLUSIVE_LOCK && res ){
+- assert( pFile->locktype>=SHARED_LOCK );
+- res = winUnlockReadLock(pFile);
+- res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, SHARED_FIRST, 0,
+- SHARED_SIZE, 0);
+- if( res ){
+- newLocktype = EXCLUSIVE_LOCK;
+- }else{
+- lastErrno = osGetLastError();
+- winGetReadLock(pFile);
++ sqlite3_free(zName);
++
++ /* If we succeeded in making the shared memory handle, map it. */
++ if( pFile->hShared ){
++ pFile->shared = (winceLock*)osMapViewOfFile(pFile->hShared,
++ FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(winceLock));
++ /* If mapping failed, close the shared memory handle and erase it */
++ if( !pFile->shared ){
++ pFile->lastErrno = osGetLastError();
++ winLogError(SQLITE_IOERR, pFile->lastErrno,
++ "winceCreateLock2", zFilename);
++ bLogged = TRUE;
++ osCloseHandle(pFile->hShared);
++ pFile->hShared = NULL;
+ }
+ }
+
+- /* If we are holding a PENDING lock that ought to be released, then
+- ** release it now.
+- */
+- if( gotPendingLock && locktype==SHARED_LOCK ){
+- winUnlockFile(&pFile->h, PENDING_BYTE, 0, 1, 0);
++ /* If shared memory could not be created, then close the mutex and fail */
++ if( pFile->hShared==NULL ){
++ if( !bLogged ){
++ pFile->lastErrno = lastErrno;
++ winLogError(SQLITE_IOERR, pFile->lastErrno,
++ "winceCreateLock3", zFilename);
++ bLogged = TRUE;
++ }
++ winceMutexRelease(pFile->hMutex);
++ osCloseHandle(pFile->hMutex);
++ pFile->hMutex = NULL;
++ return SQLITE_IOERR;
+ }
+
+- /* Update the state of the lock has held in the file descriptor then
+- ** return the appropriate result code.
+- */
+- if( res ){
+- rc = SQLITE_OK;
+- }else{
+- pFile->lastErrno = lastErrno;
+- rc = SQLITE_BUSY;
+- OSTRACE(("LOCK-FAIL file=%p, wanted=%d, got=%d\n",
+- pFile->h, locktype, newLocktype));
++ /* Initialize the shared memory if we're supposed to */
++ if( bInit ){
++ memset(pFile->shared, 0, sizeof(winceLock));
+ }
+- pFile->locktype = (u8)newLocktype;
+- OSTRACE(("LOCK file=%p, lock=%d, rc=%s\n",
+- pFile->h, pFile->locktype, sqlite3ErrName(rc)));
+- return rc;
++
++ winceMutexRelease(pFile->hMutex);
++ return SQLITE_OK;
+ }
+
+ /*
+-** This routine checks if there is a RESERVED lock held on the specified
+-** file by this or any other process. If such a lock is held, return
+-** non-zero, otherwise zero.
++** Destroy the part of winFile that deals with wince locks
+ */
+-static int winCheckReservedLock(sqlite3_file *id, int *pResOut){
+- int res;
+- winFile *pFile = (winFile*)id;
+-
+- SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
+- OSTRACE(("TEST-WR-LOCK file=%p, pResOut=%p\n", pFile->h, pResOut));
++static void winceDestroyLock(winFile *pFile){
++ if (pFile->hMutex){
++ /* Acquire the mutex */
++ winceMutexAcquire(pFile->hMutex);
+
+- assert( id!=0 );
+- if( pFile->locktype>=RESERVED_LOCK ){
+- res = 1;
+- OSTRACE(("TEST-WR-LOCK file=%p, result=%d (local)\n", pFile->h, res));
+- }else{
+- res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS,RESERVED_BYTE, 0, 1, 0);
+- if( res ){
+- winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0);
++ /* The following blocks should probably assert in debug mode, but they
++ are to cleanup in case any locks remained open */
++ if (pFile->local.nReaders){
++ pFile->shared->nReaders --;
+ }
+- res = !res;
+- OSTRACE(("TEST-WR-LOCK file=%p, result=%d (remote)\n", pFile->h, res));
++ if (pFile->local.bReserved){
++ pFile->shared->bReserved = FALSE;
++ }
++ if (pFile->local.bPending){
++ pFile->shared->bPending = FALSE;
++ }
++ if (pFile->local.bExclusive){
++ pFile->shared->bExclusive = FALSE;
++ }
++
++ /* De-reference and close our copy of the shared memory handle */
++ osUnmapViewOfFile(pFile->shared);
++ osCloseHandle(pFile->hShared);
++
++ /* Done with the mutex */
++ winceMutexRelease(pFile->hMutex);
++ osCloseHandle(pFile->hMutex);
++ pFile->hMutex = NULL;
+ }
+- *pResOut = res;
+- OSTRACE(("TEST-WR-LOCK file=%p, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n",
+- pFile->h, pResOut, *pResOut));
+- return SQLITE_OK;
+ }
+
+ /*
+-** Lower the locking level on file descriptor id to locktype. locktype
+-** must be either NO_LOCK or SHARED_LOCK.
+-**
+-** If the locking level of the file descriptor is already at or below
+-** the requested locking level, this routine is a no-op.
+-**
+-** It is not possible for this routine to fail if the second argument
+-** is NO_LOCK. If the second argument is SHARED_LOCK then this routine
+-** might return SQLITE_IOERR;
++** An implementation of the LockFile() API of Windows for CE
+ */
+-static int winUnlock(sqlite3_file *id, int locktype){
+- int type;
+- winFile *pFile = (winFile*)id;
+- int rc = SQLITE_OK;
+- assert( pFile!=0 );
+- assert( locktype<=SHARED_LOCK );
+- OSTRACE(("UNLOCK file=%p, oldLock=%d(%d), newLock=%d\n",
+- pFile->h, pFile->locktype, pFile->sharedLockByte, locktype));
+- type = pFile->locktype;
+- if( type>=EXCLUSIVE_LOCK ){
+- winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
+- if( locktype==SHARED_LOCK && !winGetReadLock(pFile) ){
+- /* This should never happen. We should always be able to
+- ** reacquire the read lock */
+- rc = winLogError(SQLITE_IOERR_UNLOCK, osGetLastError(),
+- "winUnlock", pFile->zPath);
++static BOOL winceLockFile(
++ LPHANDLE phFile,
++ DWORD dwFileOffsetLow,
++ DWORD dwFileOffsetHigh,
++ DWORD nNumberOfBytesToLockLow,
++ DWORD nNumberOfBytesToLockHigh
++){
++ winFile *pFile = HANDLE_TO_WINFILE(phFile);
++ BOOL bReturn = FALSE;
++
++ UNUSED_PARAMETER(dwFileOffsetHigh);
++ UNUSED_PARAMETER(nNumberOfBytesToLockHigh);
++
++ if (!pFile->hMutex) return TRUE;
++ winceMutexAcquire(pFile->hMutex);
++
++ /* Wanting an exclusive lock? */
++ if (dwFileOffsetLow == (DWORD)SHARED_FIRST
++ && nNumberOfBytesToLockLow == (DWORD)SHARED_SIZE){
++ if (pFile->shared->nReaders == 0 && pFile->shared->bExclusive == 0){
++ pFile->shared->bExclusive = TRUE;
++ pFile->local.bExclusive = TRUE;
++ bReturn = TRUE;
+ }
+ }
+- if( type>=RESERVED_LOCK ){
+- winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0);
++
++ /* Want a read-only lock? */
++ else if (dwFileOffsetLow == (DWORD)SHARED_FIRST &&
++ nNumberOfBytesToLockLow == 1){
++ if (pFile->shared->bExclusive == 0){
++ pFile->local.nReaders ++;
++ if (pFile->local.nReaders == 1){
++ pFile->shared->nReaders ++;
++ }
++ bReturn = TRUE;
++ }
+ }
+- if( locktype==NO_LOCK && type>=SHARED_LOCK ){
+- winUnlockReadLock(pFile);
++
++ /* Want a pending lock? */
++ else if (dwFileOffsetLow == (DWORD)PENDING_BYTE
++ && nNumberOfBytesToLockLow == 1){
++ /* If no pending lock has been acquired, then acquire it */
++ if (pFile->shared->bPending == 0) {
++ pFile->shared->bPending = TRUE;
++ pFile->local.bPending = TRUE;
++ bReturn = TRUE;
++ }
+ }
+- if( type>=PENDING_LOCK ){
+- winUnlockFile(&pFile->h, PENDING_BYTE, 0, 1, 0);
++
++ /* Want a reserved lock? */
++ else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE
++ && nNumberOfBytesToLockLow == 1){
++ if (pFile->shared->bReserved == 0) {
++ pFile->shared->bReserved = TRUE;
++ pFile->local.bReserved = TRUE;
++ bReturn = TRUE;
++ }
+ }
+- pFile->locktype = (u8)locktype;
+- OSTRACE(("UNLOCK file=%p, lock=%d, rc=%s\n",
+- pFile->h, pFile->locktype, sqlite3ErrName(rc)));
+- return rc;
++
++ winceMutexRelease(pFile->hMutex);
++ return bReturn;
+ }
+
+ /*
+-** If *pArg is initially negative then this is a query. Set *pArg to
+-** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set.
+-**
+-** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags.
++** An implementation of the UnlockFile API of Windows for CE
+ */
+-static void winModeBit(winFile *pFile, unsigned char mask, int *pArg){
+- if( *pArg<0 ){
+- *pArg = (pFile->ctrlFlags & mask)!=0;
+- }else if( (*pArg)==0 ){
+- pFile->ctrlFlags &= ~mask;
+- }else{
+- pFile->ctrlFlags |= mask;
+- }
+-}
++static BOOL winceUnlockFile(
++ LPHANDLE phFile,
++ DWORD dwFileOffsetLow,
++ DWORD dwFileOffsetHigh,
++ DWORD nNumberOfBytesToUnlockLow,
++ DWORD nNumberOfBytesToUnlockHigh
++){
++ winFile *pFile = HANDLE_TO_WINFILE(phFile);
++ BOOL bReturn = FALSE;
+
+-/* Forward references to VFS helper methods used for temporary files */
+-static int winGetTempname(sqlite3_vfs *, char **);
+-static int winIsDir(const void *);
+-static BOOL winIsDriveLetterAndColon(const char *);
++ UNUSED_PARAMETER(dwFileOffsetHigh);
++ UNUSED_PARAMETER(nNumberOfBytesToUnlockHigh);
+
+-/*
+-** Control and query of the open file handle.
+-*/
+-static int winFileControl(sqlite3_file *id, int op, void *pArg){
+- winFile *pFile = (winFile*)id;
+- OSTRACE(("FCNTL file=%p, op=%d, pArg=%p\n", pFile->h, op, pArg));
+- switch( op ){
+- case SQLITE_FCNTL_LOCKSTATE: {
+- *(int*)pArg = pFile->locktype;
+- OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
+- return SQLITE_OK;
+- }
+- case SQLITE_LAST_ERRNO: {
+- *(int*)pArg = (int)pFile->lastErrno;
+- OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
+- return SQLITE_OK;
+- }
+- case SQLITE_FCNTL_CHUNK_SIZE: {
+- pFile->szChunk = *(int *)pArg;
+- OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
+- return SQLITE_OK;
+- }
+- case SQLITE_FCNTL_SIZE_HINT: {
+- if( pFile->szChunk>0 ){
+- sqlite3_int64 oldSz;
+- int rc = winFileSize(id, &oldSz);
+- if( rc==SQLITE_OK ){
+- sqlite3_int64 newSz = *(sqlite3_int64*)pArg;
+- if( newSz>oldSz ){
+- SimulateIOErrorBenign(1);
+- rc = winTruncate(id, newSz);
+- SimulateIOErrorBenign(0);
+- }
+- }
+- OSTRACE(("FCNTL file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc)));
+- return rc;
+- }
+- OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
+- return SQLITE_OK;
+- }
+- case SQLITE_FCNTL_PERSIST_WAL: {
+- winModeBit(pFile, WINFILE_PERSIST_WAL, (int*)pArg);
+- OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
+- return SQLITE_OK;
+- }
+- case SQLITE_FCNTL_POWERSAFE_OVERWRITE: {
+- winModeBit(pFile, WINFILE_PSOW, (int*)pArg);
+- OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
+- return SQLITE_OK;
+- }
+- case SQLITE_FCNTL_VFSNAME: {
+- *(char**)pArg = sqlite3_mprintf("%s", pFile->pVfs->zName);
+- OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
+- return SQLITE_OK;
++ if (!pFile->hMutex) return TRUE;
++ winceMutexAcquire(pFile->hMutex);
++
++ /* Releasing a reader lock or an exclusive lock */
++ if (dwFileOffsetLow == (DWORD)SHARED_FIRST){
++ /* Did we have an exclusive lock? */
++ if (pFile->local.bExclusive){
++ assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE);
++ pFile->local.bExclusive = FALSE;
++ pFile->shared->bExclusive = FALSE;
++ bReturn = TRUE;
+ }
+- case SQLITE_FCNTL_WIN32_AV_RETRY: {
+- int *a = (int*)pArg;
+- if( a[0]>0 ){
+- winIoerrRetry = a[0];
+- }else{
+- a[0] = winIoerrRetry;
+- }
+- if( a[1]>0 ){
+- winIoerrRetryDelay = a[1];
+- }else{
+- a[1] = winIoerrRetryDelay;
++
++ /* Did we just have a reader lock? */
++ else if (pFile->local.nReaders){
++ assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE
++ || nNumberOfBytesToUnlockLow == 1);
++ pFile->local.nReaders --;
++ if (pFile->local.nReaders == 0)
++ {
++ pFile->shared->nReaders --;
+ }
+- OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
+- return SQLITE_OK;
+- }
+-#ifdef SQLITE_TEST
+- case SQLITE_FCNTL_WIN32_SET_HANDLE: {
+- LPHANDLE phFile = (LPHANDLE)pArg;
+- HANDLE hOldFile = pFile->h;
+- pFile->h = *phFile;
+- *phFile = hOldFile;
+- OSTRACE(("FCNTL oldFile=%p, newFile=%p, rc=SQLITE_OK\n",
+- hOldFile, pFile->h));
+- return SQLITE_OK;
++ bReturn = TRUE;
+ }
+-#endif
+- case SQLITE_FCNTL_TEMPFILENAME: {
+- char *zTFile = 0;
+- int rc = winGetTempname(pFile->pVfs, &zTFile);
+- if( rc==SQLITE_OK ){
+- *(char**)pArg = zTFile;
+- }
+- OSTRACE(("FCNTL file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc)));
+- return rc;
++ }
++
++ /* Releasing a pending lock */
++ else if (dwFileOffsetLow == (DWORD)PENDING_BYTE
++ && nNumberOfBytesToUnlockLow == 1){
++ if (pFile->local.bPending){
++ pFile->local.bPending = FALSE;
++ pFile->shared->bPending = FALSE;
++ bReturn = TRUE;
+ }
+-#if SQLITE_MAX_MMAP_SIZE>0
+- case SQLITE_FCNTL_MMAP_SIZE: {
+- i64 newLimit = *(i64*)pArg;
+- int rc = SQLITE_OK;
+- if( newLimit>sqlite3GlobalConfig.mxMmap ){
+- newLimit = sqlite3GlobalConfig.mxMmap;
+- }
+- *(i64*)pArg = pFile->mmapSizeMax;
+- if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){
+- pFile->mmapSizeMax = newLimit;
+- if( pFile->mmapSize>0 ){
+- winUnmapfile(pFile);
+- rc = winMapfile(pFile, -1);
+- }
+- }
+- OSTRACE(("FCNTL file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc)));
+- return rc;
++ }
++ /* Releasing a reserved lock */
++ else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE
++ && nNumberOfBytesToUnlockLow == 1){
++ if (pFile->local.bReserved) {
++ pFile->local.bReserved = FALSE;
++ pFile->shared->bReserved = FALSE;
++ bReturn = TRUE;
+ }
+-#endif
+ }
+- OSTRACE(("FCNTL file=%p, rc=SQLITE_NOTFOUND\n", pFile->h));
+- return SQLITE_NOTFOUND;
++
++ winceMutexRelease(pFile->hMutex);
++ return bReturn;
++}
++/*
++** End of the special code for wince
++*****************************************************************************/
++#endif /* SQLITE_OS_WINCE */
++
++/*
++** Lock a file region.
++*/
++static BOOL winLockFile(
++ LPHANDLE phFile,
++ DWORD flags,
++ DWORD offsetLow,
++ DWORD offsetHigh,
++ DWORD numBytesLow,
++ DWORD numBytesHigh
++){
++#if SQLITE_OS_WINCE
++ /*
++ ** NOTE: Windows CE is handled differently here due its lack of the Win32
++ ** API LockFile.
++ */
++ return winceLockFile(phFile, offsetLow, offsetHigh,
++ numBytesLow, numBytesHigh);
++#else
++ if( osIsNT() ){
++ OVERLAPPED ovlp;
++ memset(&ovlp, 0, sizeof(OVERLAPPED));
++ ovlp.Offset = offsetLow;
++ ovlp.OffsetHigh = offsetHigh;
++ return osLockFileEx(*phFile, flags, 0, numBytesLow, numBytesHigh, &ovlp);
++ }else{
++ return osLockFile(*phFile, offsetLow, offsetHigh, numBytesLow,
++ numBytesHigh);
++ }
++#endif
+ }
+
+ /*
+-** Return the sector size in bytes of the underlying block device for
+-** the specified file. This is almost always 512 bytes, but may be
+-** larger for some devices.
+-**
+-** SQLite code assumes this function cannot fail. It also assumes that
+-** if two files are created in the same file-system directory (i.e.
+-** a database and its journal file) that the sector size will be the
+-** same for both.
+-*/
+-static int winSectorSize(sqlite3_file *id){
+- (void)id;
+- return SQLITE_DEFAULT_SECTOR_SIZE;
++** Unlock a file region.
++ */
++static BOOL winUnlockFile(
++ LPHANDLE phFile,
++ DWORD offsetLow,
++ DWORD offsetHigh,
++ DWORD numBytesLow,
++ DWORD numBytesHigh
++){
++#if SQLITE_OS_WINCE
++ /*
++ ** NOTE: Windows CE is handled differently here due its lack of the Win32
++ ** API UnlockFile.
++ */
++ return winceUnlockFile(phFile, offsetLow, offsetHigh,
++ numBytesLow, numBytesHigh);
++#else
++ if( osIsNT() ){
++ OVERLAPPED ovlp;
++ memset(&ovlp, 0, sizeof(OVERLAPPED));
++ ovlp.Offset = offsetLow;
++ ovlp.OffsetHigh = offsetHigh;
++ return osUnlockFileEx(*phFile, 0, numBytesLow, numBytesHigh, &ovlp);
++ }else{
++ return osUnlockFile(*phFile, offsetLow, offsetHigh, numBytesLow,
++ numBytesHigh);
++ }
++#endif
+ }
+
++/*****************************************************************************
++** The next group of routines implement the I/O methods specified
++** by the sqlite3_io_methods object.
++******************************************************************************/
++
+ /*
+-** Return a vector of device characteristics.
++** Some Microsoft compilers lack this definition.
+ */
+-static int winDeviceCharacteristics(sqlite3_file *id){
+- winFile *p = (winFile*)id;
+- return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN |
+- ((p->ctrlFlags & WINFILE_PSOW)?SQLITE_IOCAP_POWERSAFE_OVERWRITE:0);
+-}
++#ifndef INVALID_SET_FILE_POINTER
++# define INVALID_SET_FILE_POINTER ((DWORD)-1)
++#endif
+
+ /*
+-** Windows will only let you create file view mappings
+-** on allocation size granularity boundaries.
+-** During sqlite3_os_init() we do a GetSystemInfo()
+-** to get the granularity size.
++** Move the current position of the file handle passed as the first
++** argument to offset iOffset within the file. If successful, return 0.
++** Otherwise, set pFile->lastErrno and return non-zero.
+ */
+-static SYSTEM_INFO winSysInfo;
++static int winSeekFile(winFile *pFile, sqlite3_int64 iOffset){
++#if !SQLITE_OS_WINRT
++ LONG upperBits; /* Most sig. 32 bits of new offset */
++ LONG lowerBits; /* Least sig. 32 bits of new offset */
++ DWORD dwRet; /* Value returned by SetFilePointer() */
++ DWORD lastErrno; /* Value returned by GetLastError() */
+
+-#ifndef SQLITE_OMIT_WAL
++ OSTRACE(("SEEK file=%p, offset=%lld\n", pFile->h, iOffset));
+
+-/*
+-** Helper functions to obtain and relinquish the global mutex. The
+-** global mutex is used to protect the winLockInfo objects used by
+-** this file, all of which may be shared by multiple threads.
+-**
+-** Function winShmMutexHeld() is used to assert() that the global mutex
+-** is held when required. This function is only used as part of assert()
+-** statements. e.g.
+-**
+-** winShmEnterMutex()
+-** assert( winShmMutexHeld() );
+-** winShmLeaveMutex()
+-*/
+-static void winShmEnterMutex(void){
+- sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+-}
+-static void winShmLeaveMutex(void){
+- sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+-}
+-#ifndef NDEBUG
+-static int winShmMutexHeld(void) {
+- return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
++ upperBits = (LONG)((iOffset>>32) & 0x7fffffff);
++ lowerBits = (LONG)(iOffset & 0xffffffff);
++
++ /* API oddity: If successful, SetFilePointer() returns a dword
++ ** containing the lower 32-bits of the new file-offset. Or, if it fails,
++ ** it returns INVALID_SET_FILE_POINTER. However according to MSDN,
++ ** INVALID_SET_FILE_POINTER may also be a valid new offset. So to determine
++ ** whether an error has actually occurred, it is also necessary to call
++ ** GetLastError().
++ */
++ dwRet = osSetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
++
++ if( (dwRet==INVALID_SET_FILE_POINTER
++ && ((lastErrno = osGetLastError())!=NO_ERROR)) ){
++ pFile->lastErrno = lastErrno;
++ winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno,
++ "winSeekFile", pFile->zPath);
++ OSTRACE(("SEEK file=%p, rc=SQLITE_IOERR_SEEK\n", pFile->h));
++ return 1;
++ }
++
++ OSTRACE(("SEEK file=%p, rc=SQLITE_OK\n", pFile->h));
++ return 0;
++#else
++ /*
++ ** Same as above, except that this implementation works for WinRT.
++ */
++
++ LARGE_INTEGER x; /* The new offset */
++ BOOL bRet; /* Value returned by SetFilePointerEx() */
++
++ x.QuadPart = iOffset;
++ bRet = osSetFilePointerEx(pFile->h, x, 0, FILE_BEGIN);
++
++ if(!bRet){
++ pFile->lastErrno = osGetLastError();
++ winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno,
++ "winSeekFile", pFile->zPath);
++ OSTRACE(("SEEK file=%p, rc=SQLITE_IOERR_SEEK\n", pFile->h));
++ return 1;
++ }
++
++ OSTRACE(("SEEK file=%p, rc=SQLITE_OK\n", pFile->h));
++ return 0;
++#endif
+ }
++
++#if SQLITE_MAX_MMAP_SIZE>0
++/* Forward references to VFS helper methods used for memory mapped files */
++static int winMapfile(winFile*, sqlite3_int64);
++static int winUnmapfile(winFile*);
+ #endif
+
+ /*
+-** Object used to represent a single file opened and mmapped to provide
+-** shared memory. When multiple threads all reference the same
+-** log-summary, each thread has its own winFile object, but they all
+-** point to a single instance of this object. In other words, each
+-** log-summary is opened only once per process.
+-**
+-** winShmMutexHeld() must be true when creating or destroying
+-** this object or while reading or writing the following fields:
+-**
+-** nRef
+-** pNext
+-**
+-** The following fields are read-only after the object is created:
+-**
+-** fid
+-** zFilename
+-**
+-** Either winShmNode.mutex must be held or winShmNode.nRef==0 and
+-** winShmMutexHeld() is true when reading or writing any other field
+-** in this structure.
++** Close a file.
+ **
++** It is reported that an attempt to close a handle might sometimes
++** fail. This is a very unreasonable result, but Windows is notorious
++** for being unreasonable so I do not doubt that it might happen. If
++** the close fails, we pause for 100 milliseconds and try again. As
++** many as MX_CLOSE_ATTEMPT attempts to close the handle are made before
++** giving up and returning an error.
+ */
+-struct winShmNode {
+- sqlite3_mutex *mutex; /* Mutex to access this object */
+- char *zFilename; /* Name of the file */
+- winFile hFile; /* File handle from winOpen */
++#define MX_CLOSE_ATTEMPT 3
++static int winClose(sqlite3_file *id){
++ int rc, cnt = 0;
++ winFile *pFile = (winFile*)id;
+
+- int szRegion; /* Size of shared-memory regions */
+- int nRegion; /* Size of array apRegion */
+- struct ShmRegion {
+- HANDLE hMap; /* File handle from CreateFileMapping */
+- void *pMap;
+- } *aRegion;
+- DWORD lastErrno; /* The Windows errno from the last I/O error */
++ assert( id!=0 );
++#ifndef SQLITE_OMIT_WAL
++ assert( pFile->pShm==0 );
++#endif
++ assert( pFile->h!=NULL && pFile->h!=INVALID_HANDLE_VALUE );
++ OSTRACE(("CLOSE pid=%lu, pFile=%p, file=%p\n",
++ osGetCurrentProcessId(), pFile, pFile->h));
+
+- int nRef; /* Number of winShm objects pointing to this */
+- winShm *pFirst; /* All winShm objects pointing to this */
+- winShmNode *pNext; /* Next in list of all winShmNode objects */
+-#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
+- u8 nextShmId; /* Next available winShm.id value */
++#if SQLITE_MAX_MMAP_SIZE>0
++ winUnmapfile(pFile);
+ #endif
+-};
+
+-/*
+-** A global array of all winShmNode objects.
+-**
+-** The winShmMutexHeld() must be true while reading or writing this list.
+-*/
+-static winShmNode *winShmNodeList = 0;
++ do{
++ rc = osCloseHandle(pFile->h);
++ /* SimulateIOError( rc=0; cnt=MX_CLOSE_ATTEMPT; ); */
++ }while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (sqlite3_win32_sleep(100), 1) );
++#if SQLITE_OS_WINCE
++#define WINCE_DELETION_ATTEMPTS 3
++ winceDestroyLock(pFile);
++ if( pFile->zDeleteOnClose ){
++ int cnt = 0;
++ while(
++ osDeleteFileW(pFile->zDeleteOnClose)==0
++ && osGetFileAttributesW(pFile->zDeleteOnClose)!=0xffffffff
++ && cnt++ < WINCE_DELETION_ATTEMPTS
++ ){
++ sqlite3_win32_sleep(100); /* Wait a little before trying again */
++ }
++ sqlite3_free(pFile->zDeleteOnClose);
++ }
++#endif
++ if( rc ){
++ pFile->h = NULL;
++ }
++ OpenCounter(-1);
++ OSTRACE(("CLOSE pid=%lu, pFile=%p, file=%p, rc=%s\n",
++ osGetCurrentProcessId(), pFile, pFile->h, rc ? "ok" : "failed"));
++ return rc ? SQLITE_OK
++ : winLogError(SQLITE_IOERR_CLOSE, osGetLastError(),
++ "winClose", pFile->zPath);
++}
+
+ /*
+-** Structure used internally by this VFS to record the state of an
+-** open shared memory connection.
+-**
+-** The following fields are initialized when this object is created and
+-** are read-only thereafter:
+-**
+-** winShm.pShmNode
+-** winShm.id
+-**
+-** All other fields are read/write. The winShm.pShmNode->mutex must be held
+-** while accessing any read/write fields.
++** Read data from a file into a buffer. Return SQLITE_OK if all
++** bytes were read successfully and SQLITE_IOERR if anything goes
++** wrong.
+ */
+-struct winShm {
+- winShmNode *pShmNode; /* The underlying winShmNode object */
+- winShm *pNext; /* Next winShm with the same winShmNode */
+- u8 hasMutex; /* True if holding the winShmNode mutex */
+- u16 sharedMask; /* Mask of shared locks held */
+- u16 exclMask; /* Mask of exclusive locks held */
+-#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
+- u8 id; /* Id of this connection with its winShmNode */
++static int winRead(
++ sqlite3_file *id, /* File to read from */
++ void *pBuf, /* Write content into this buffer */
++ int amt, /* Number of bytes to read */
++ sqlite3_int64 offset /* Begin reading at this offset */
++){
++#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
++ OVERLAPPED overlapped; /* The offset for ReadFile. */
+ #endif
+-};
++ winFile *pFile = (winFile*)id; /* file handle */
++ DWORD nRead; /* Number of bytes actually read from file */
++ int nRetry = 0; /* Number of retrys */
+
+-/*
+-** Constants used for locking
+-*/
+-#define WIN_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */
+-#define WIN_SHM_DMS (WIN_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */
++ assert( id!=0 );
++ assert( amt>0 );
++ assert( offset>=0 );
++ SimulateIOError(return SQLITE_IOERR_READ);
++ OSTRACE(("READ pid=%lu, pFile=%p, file=%p, buffer=%p, amount=%d, "
++ "offset=%lld, lock=%d\n", osGetCurrentProcessId(), pFile,
++ pFile->h, pBuf, amt, offset, pFile->locktype));
++
++#if SQLITE_MAX_MMAP_SIZE>0
++ /* Deal with as much of this read request as possible by transfering
++ ** data from the memory mapping using memcpy(). */
++ if( offset<pFile->mmapSize ){
++ if( offset+amt <= pFile->mmapSize ){
++ memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], amt);
++ OSTRACE(("READ-MMAP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
++ osGetCurrentProcessId(), pFile, pFile->h));
++ return SQLITE_OK;
++ }else{
++ int nCopy = (int)(pFile->mmapSize - offset);
++ memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], nCopy);
++ pBuf = &((u8 *)pBuf)[nCopy];
++ amt -= nCopy;
++ offset += nCopy;
++ }
++ }
++#endif
++
++#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED)
++ if( winSeekFile(pFile, offset) ){
++ OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_FULL\n",
++ osGetCurrentProcessId(), pFile, pFile->h));
++ return SQLITE_FULL;
++ }
++ while( !osReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
++#else
++ memset(&overlapped, 0, sizeof(OVERLAPPED));
++ overlapped.Offset = (LONG)(offset & 0xffffffff);
++ overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
++ while( !osReadFile(pFile->h, pBuf, amt, &nRead, &overlapped) &&
++ osGetLastError()!=ERROR_HANDLE_EOF ){
++#endif
++ DWORD lastErrno;
++ if( winRetryIoerr(&nRetry, &lastErrno) ) continue;
++ pFile->lastErrno = lastErrno;
++ OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_READ\n",
++ osGetCurrentProcessId(), pFile, pFile->h));
++ return winLogError(SQLITE_IOERR_READ, pFile->lastErrno,
++ "winRead", pFile->zPath);
++ }
++ winLogIoerr(nRetry, __LINE__);
++ if( nRead<(DWORD)amt ){
++ /* Unread parts of the buffer must be zero-filled */
++ memset(&((char*)pBuf)[nRead], 0, amt-nRead);
++ OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_SHORT_READ\n",
++ osGetCurrentProcessId(), pFile, pFile->h));
++ return SQLITE_IOERR_SHORT_READ;
++ }
++
++ OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
++ osGetCurrentProcessId(), pFile, pFile->h));
++ return SQLITE_OK;
++}
+
+ /*
+-** Apply advisory locks for all n bytes beginning at ofst.
++** Write data from a buffer into a file. Return SQLITE_OK on success
++** or some other error code on failure.
+ */
+-#define _SHM_UNLCK 1
+-#define _SHM_RDLCK 2
+-#define _SHM_WRLCK 3
+-static int winShmSystemLock(
+- winShmNode *pFile, /* Apply locks to this open shared-memory segment */
+- int lockType, /* _SHM_UNLCK, _SHM_RDLCK, or _SHM_WRLCK */
+- int ofst, /* Offset to first byte to be locked/unlocked */
+- int nByte /* Number of bytes to lock or unlock */
++static int winWrite(
++ sqlite3_file *id, /* File to write into */
++ const void *pBuf, /* The bytes to be written */
++ int amt, /* Number of bytes to write */
++ sqlite3_int64 offset /* Offset into the file to begin writing at */
+ ){
+- int rc = 0; /* Result code form Lock/UnlockFileEx() */
+-
+- /* Access to the winShmNode object is serialized by the caller */
+- assert( sqlite3_mutex_held(pFile->mutex) || pFile->nRef==0 );
++ int rc = 0; /* True if error has occurred, else false */
++ winFile *pFile = (winFile*)id; /* File handle */
++ int nRetry = 0; /* Number of retries */
+
+- OSTRACE(("SHM-LOCK file=%p, lock=%d, offset=%d, size=%d\n",
+- pFile->hFile.h, lockType, ofst, nByte));
++ assert( amt>0 );
++ assert( pFile );
++ SimulateIOError(return SQLITE_IOERR_WRITE);
++ SimulateDiskfullError(return SQLITE_FULL);
+
+- /* Release/Acquire the system-level lock */
+- if( lockType==_SHM_UNLCK ){
+- rc = winUnlockFile(&pFile->hFile.h, ofst, 0, nByte, 0);
+- }else{
+- /* Initialize the locking parameters */
+- DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY;
+- if( lockType == _SHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
+- rc = winLockFile(&pFile->hFile.h, dwFlags, ofst, 0, nByte, 0);
+- }
++ OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, buffer=%p, amount=%d, "
++ "offset=%lld, lock=%d\n", osGetCurrentProcessId(), pFile,
++ pFile->h, pBuf, amt, offset, pFile->locktype));
+
+- if( rc!= 0 ){
+- rc = SQLITE_OK;
+- }else{
+- pFile->lastErrno = osGetLastError();
+- rc = SQLITE_BUSY;
++#if SQLITE_MAX_MMAP_SIZE>0
++ /* Deal with as much of this write request as possible by transfering
++ ** data from the memory mapping using memcpy(). */
++ if( offset<pFile->mmapSize ){
++ if( offset+amt <= pFile->mmapSize ){
++ memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, amt);
++ OSTRACE(("WRITE-MMAP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
++ osGetCurrentProcessId(), pFile, pFile->h));
++ return SQLITE_OK;
++ }else{
++ int nCopy = (int)(pFile->mmapSize - offset);
++ memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, nCopy);
++ pBuf = &((u8 *)pBuf)[nCopy];
++ amt -= nCopy;
++ offset += nCopy;
++ }
+ }
++#endif
+
+- OSTRACE(("SHM-LOCK file=%p, func=%s, errno=%lu, rc=%s\n",
+- pFile->hFile.h, (lockType == _SHM_UNLCK) ? "winUnlockFile" :
+- "winLockFile", pFile->lastErrno, sqlite3ErrName(rc)));
+-
+- return rc;
+-}
++#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED)
++ rc = winSeekFile(pFile, offset);
++ if( rc==0 ){
++#else
++ {
++#endif
++#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
++ OVERLAPPED overlapped; /* The offset for WriteFile. */
++#endif
++ u8 *aRem = (u8 *)pBuf; /* Data yet to be written */
++ int nRem = amt; /* Number of bytes yet to be written */
++ DWORD nWrite; /* Bytes written by each WriteFile() call */
++ DWORD lastErrno = NO_ERROR; /* Value returned by GetLastError() */
+
+-/* Forward references to VFS methods */
+-static int winOpen(sqlite3_vfs*,const char*,sqlite3_file*,int,int*);
+-static int winDelete(sqlite3_vfs *,const char*,int);
++#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
++ memset(&overlapped, 0, sizeof(OVERLAPPED));
++ overlapped.Offset = (LONG)(offset & 0xffffffff);
++ overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
++#endif
+
+-/*
+-** Purge the winShmNodeList list of all entries with winShmNode.nRef==0.
+-**
+-** This is not a VFS shared-memory method; it is a utility function called
+-** by VFS shared-memory methods.
+-*/
+-static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
+- winShmNode **pp;
+- winShmNode *p;
+- assert( winShmMutexHeld() );
+- OSTRACE(("SHM-PURGE pid=%lu, deleteFlag=%d\n",
+- osGetCurrentProcessId(), deleteFlag));
+- pp = &winShmNodeList;
+- while( (p = *pp)!=0 ){
+- if( p->nRef==0 ){
+- int i;
+- if( p->mutex ){ sqlite3_mutex_free(p->mutex); }
+- for(i=0; i<p->nRegion; i++){
+- BOOL bRc = osUnmapViewOfFile(p->aRegion[i].pMap);
+- OSTRACE(("SHM-PURGE-UNMAP pid=%lu, region=%d, rc=%s\n",
+- osGetCurrentProcessId(), i, bRc ? "ok" : "failed"));
+- UNUSED_VARIABLE_VALUE(bRc);
+- bRc = osCloseHandle(p->aRegion[i].hMap);
+- OSTRACE(("SHM-PURGE-CLOSE pid=%lu, region=%d, rc=%s\n",
+- osGetCurrentProcessId(), i, bRc ? "ok" : "failed"));
+- UNUSED_VARIABLE_VALUE(bRc);
+- }
+- if( p->hFile.h!=NULL && p->hFile.h!=INVALID_HANDLE_VALUE ){
+- SimulateIOErrorBenign(1);
+- winClose((sqlite3_file *)&p->hFile);
+- SimulateIOErrorBenign(0);
++ while( nRem>0 ){
++#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED)
++ if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, 0) ){
++#else
++ if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, &overlapped) ){
++#endif
++ if( winRetryIoerr(&nRetry, &lastErrno) ) continue;
++ break;
+ }
+- if( deleteFlag ){
+- SimulateIOErrorBenign(1);
+- sqlite3BeginBenignMalloc();
+- winDelete(pVfs, p->zFilename, 0);
+- sqlite3EndBenignMalloc();
+- SimulateIOErrorBenign(0);
++ assert( nWrite==0 || nWrite<=(DWORD)nRem );
++ if( nWrite==0 || nWrite>(DWORD)nRem ){
++ lastErrno = osGetLastError();
++ break;
+ }
+- *pp = p->pNext;
+- sqlite3_free(p->aRegion);
+- sqlite3_free(p);
+- }else{
+- pp = &p->pNext;
++#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
++ offset += nWrite;
++ overlapped.Offset = (LONG)(offset & 0xffffffff);
++ overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
++#endif
++ aRem += nWrite;
++ nRem -= nWrite;
++ }
++ if( nRem>0 ){
++ pFile->lastErrno = lastErrno;
++ rc = 1;
++ }
++ }
++
++ if( rc ){
++ if( ( pFile->lastErrno==ERROR_HANDLE_DISK_FULL )
++ || ( pFile->lastErrno==ERROR_DISK_FULL )){
++ OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_FULL\n",
++ osGetCurrentProcessId(), pFile, pFile->h));
++ return winLogError(SQLITE_FULL, pFile->lastErrno,
++ "winWrite1", pFile->zPath);
+ }
++ OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_WRITE\n",
++ osGetCurrentProcessId(), pFile, pFile->h));
++ return winLogError(SQLITE_IOERR_WRITE, pFile->lastErrno,
++ "winWrite2", pFile->zPath);
++ }else{
++ winLogIoerr(nRetry, __LINE__);
+ }
++ OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
++ osGetCurrentProcessId(), pFile, pFile->h));
++ return SQLITE_OK;
+ }
+
+ /*
+-** Open the shared-memory area associated with database file pDbFd.
+-**
+-** When opening a new shared-memory file, if no other instances of that
+-** file are currently open, in this process or in other processes, then
+-** the file must be truncated to zero length or have its header cleared.
++** Truncate an open file to a specified size
+ */
+-static int winOpenSharedMemory(winFile *pDbFd){
+- struct winShm *p; /* The connection to be opened */
+- struct winShmNode *pShmNode = 0; /* The underlying mmapped file */
+- int rc; /* Result code */
+- struct winShmNode *pNew; /* Newly allocated winShmNode */
+- int nName; /* Size of zName in bytes */
++static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
++ winFile *pFile = (winFile*)id; /* File handle object */
++ int rc = SQLITE_OK; /* Return code for this function */
++ DWORD lastErrno;
+
+- assert( pDbFd->pShm==0 ); /* Not previously opened */
++ assert( pFile );
++ SimulateIOError(return SQLITE_IOERR_TRUNCATE);
++ OSTRACE(("TRUNCATE pid=%lu, pFile=%p, file=%p, size=%lld, lock=%d\n",
++ osGetCurrentProcessId(), pFile, pFile->h, nByte, pFile->locktype));
+
+- /* Allocate space for the new sqlite3_shm object. Also speculatively
+- ** allocate space for a new winShmNode and filename.
++ /* If the user has configured a chunk-size for this file, truncate the
++ ** file so that it consists of an integer number of chunks (i.e. the
++ ** actual file size after the operation may be larger than the requested
++ ** size).
+ */
+- p = sqlite3MallocZero( sizeof(*p) );
+- if( p==0 ) return SQLITE_IOERR_NOMEM;
+- nName = sqlite3Strlen30(pDbFd->zPath);
+- pNew = sqlite3MallocZero( sizeof(*pShmNode) + nName + 17 );
+- if( pNew==0 ){
+- sqlite3_free(p);
+- return SQLITE_IOERR_NOMEM;
++ if( pFile->szChunk>0 ){
++ nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
+ }
+- pNew->zFilename = (char*)&pNew[1];
+- sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath);
+- sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename);
+
+- /* Look to see if there is an existing winShmNode that can be used.
+- ** If no matching winShmNode currently exists, create a new one.
+- */
+- winShmEnterMutex();
+- for(pShmNode = winShmNodeList; pShmNode; pShmNode=pShmNode->pNext){
+- /* TBD need to come up with better match here. Perhaps
+- ** use FILE_ID_BOTH_DIR_INFO Structure.
+- */
+- if( sqlite3StrICmp(pShmNode->zFilename, pNew->zFilename)==0 ) break;
++ /* SetEndOfFile() returns non-zero when successful, or zero when it fails. */
++ if( winSeekFile(pFile, nByte) ){
++ rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno,
++ "winTruncate1", pFile->zPath);
++ }else if( 0==osSetEndOfFile(pFile->h) &&
++ ((lastErrno = osGetLastError())!=ERROR_USER_MAPPED_FILE) ){
++ pFile->lastErrno = lastErrno;
++ rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno,
++ "winTruncate2", pFile->zPath);
+ }
+- if( pShmNode ){
+- sqlite3_free(pNew);
+- }else{
+- pShmNode = pNew;
+- pNew = 0;
+- ((winFile*)(&pShmNode->hFile))->h = INVALID_HANDLE_VALUE;
+- pShmNode->pNext = winShmNodeList;
+- winShmNodeList = pShmNode;
+-
+- pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
+- if( pShmNode->mutex==0 ){
+- rc = SQLITE_IOERR_NOMEM;
+- goto shm_open_err;
+- }
+-
+- rc = winOpen(pDbFd->pVfs,
+- pShmNode->zFilename, /* Name of the file (UTF-8) */
+- (sqlite3_file*)&pShmNode->hFile, /* File handle here */
+- SQLITE_OPEN_WAL | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
+- 0);
+- if( SQLITE_OK!=rc ){
+- goto shm_open_err;
+- }
+
+- /* Check to see if another process is holding the dead-man switch.
+- ** If not, truncate the file to zero length.
+- */
+- if( winShmSystemLock(pShmNode, _SHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){
+- rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0);
+- if( rc!=SQLITE_OK ){
+- rc = winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(),
+- "winOpenShm", pDbFd->zPath);
+- }
+- }
+- if( rc==SQLITE_OK ){
+- winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1);
+- rc = winShmSystemLock(pShmNode, _SHM_RDLCK, WIN_SHM_DMS, 1);
+- }
+- if( rc ) goto shm_open_err;
++#if SQLITE_MAX_MMAP_SIZE>0
++ /* If the file was truncated to a size smaller than the currently
++ ** mapped region, reduce the effective mapping size as well. SQLite will
++ ** use read() and write() to access data beyond this point from now on.
++ */
++ if( pFile->pMapRegion && nByte<pFile->mmapSize ){
++ pFile->mmapSize = nByte;
+ }
+-
+- /* Make the new connection a child of the winShmNode */
+- p->pShmNode = pShmNode;
+-#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
+- p->id = pShmNode->nextShmId++;
+ #endif
+- pShmNode->nRef++;
+- pDbFd->pShm = p;
+- winShmLeaveMutex();
+-
+- /* The reference count on pShmNode has already been incremented under
+- ** the cover of the winShmEnterMutex() mutex and the pointer from the
+- ** new (struct winShm) object to the pShmNode has been set. All that is
+- ** left to do is to link the new object into the linked list starting
+- ** at pShmNode->pFirst. This must be done while holding the pShmNode->mutex
+- ** mutex.
+- */
+- sqlite3_mutex_enter(pShmNode->mutex);
+- p->pNext = pShmNode->pFirst;
+- pShmNode->pFirst = p;
+- sqlite3_mutex_leave(pShmNode->mutex);
+- return SQLITE_OK;
+
+- /* Jump here on any error */
+-shm_open_err:
+- winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1);
+- winShmPurge(pDbFd->pVfs, 0); /* This call frees pShmNode if required */
+- sqlite3_free(p);
+- sqlite3_free(pNew);
+- winShmLeaveMutex();
++ OSTRACE(("TRUNCATE pid=%lu, pFile=%p, file=%p, rc=%s\n",
++ osGetCurrentProcessId(), pFile, pFile->h, sqlite3ErrName(rc)));
+ return rc;
+ }
+
++#ifdef SQLITE_TEST
+ /*
+-** Close a connection to shared-memory. Delete the underlying
+-** storage if deleteFlag is true.
++** Count the number of fullsyncs and normal syncs. This is used to test
++** that syncs and fullsyncs are occuring at the right times.
+ */
+-static int winShmUnmap(
+- sqlite3_file *fd, /* Database holding shared memory */
+- int deleteFlag /* Delete after closing if true */
+-){
+- winFile *pDbFd; /* Database holding shared-memory */
+- winShm *p; /* The connection to be closed */
+- winShmNode *pShmNode; /* The underlying shared-memory file */
+- winShm **pp; /* For looping over sibling connections */
++SQLITE_API int sqlite3_sync_count = 0;
++SQLITE_API int sqlite3_fullsync_count = 0;
++#endif
+
+- pDbFd = (winFile*)fd;
+- p = pDbFd->pShm;
+- if( p==0 ) return SQLITE_OK;
+- pShmNode = p->pShmNode;
++/*
++** Make sure all writes to a particular file are committed to disk.
++*/
++static int winSync(sqlite3_file *id, int flags){
++#ifndef SQLITE_NO_SYNC
++ /*
++ ** Used only when SQLITE_NO_SYNC is not defined.
++ */
++ BOOL rc;
++#endif
++#if !defined(NDEBUG) || !defined(SQLITE_NO_SYNC) || \
++ defined(SQLITE_HAVE_OS_TRACE)
++ /*
++ ** Used when SQLITE_NO_SYNC is not defined and by the assert() and/or
++ ** OSTRACE() macros.
++ */
++ winFile *pFile = (winFile*)id;
++#else
++ UNUSED_PARAMETER(id);
++#endif
+
+- /* Remove connection p from the set of connections associated
+- ** with pShmNode */
+- sqlite3_mutex_enter(pShmNode->mutex);
+- for(pp=&pShmNode->pFirst; (*pp)!=p; pp = &(*pp)->pNext){}
+- *pp = p->pNext;
++ assert( pFile );
++ /* Check that one of SQLITE_SYNC_NORMAL or FULL was passed */
++ assert((flags&0x0F)==SQLITE_SYNC_NORMAL
++ || (flags&0x0F)==SQLITE_SYNC_FULL
++ );
+
+- /* Free the connection p */
+- sqlite3_free(p);
+- pDbFd->pShm = 0;
+- sqlite3_mutex_leave(pShmNode->mutex);
++ /* Unix cannot, but some systems may return SQLITE_FULL from here. This
++ ** line is to test that doing so does not cause any problems.
++ */
++ SimulateDiskfullError( return SQLITE_FULL );
+
+- /* If pShmNode->nRef has reached 0, then close the underlying
+- ** shared-memory file, too */
+- winShmEnterMutex();
+- assert( pShmNode->nRef>0 );
+- pShmNode->nRef--;
+- if( pShmNode->nRef==0 ){
+- winShmPurge(pDbFd->pVfs, deleteFlag);
++ OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, flags=%x, lock=%d\n",
++ osGetCurrentProcessId(), pFile, pFile->h, flags,
++ pFile->locktype));
++
++#ifndef SQLITE_TEST
++ UNUSED_PARAMETER(flags);
++#else
++ if( (flags&0x0F)==SQLITE_SYNC_FULL ){
++ sqlite3_fullsync_count++;
+ }
+- winShmLeaveMutex();
++ sqlite3_sync_count++;
++#endif
+
++ /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a
++ ** no-op
++ */
++#ifdef SQLITE_NO_SYNC
++ OSTRACE(("SYNC-NOP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
++ osGetCurrentProcessId(), pFile, pFile->h));
+ return SQLITE_OK;
++#else
++#if SQLITE_MAX_MMAP_SIZE>0
++ if( pFile->pMapRegion ){
++ if( osFlushViewOfFile(pFile->pMapRegion, 0) ){
++ OSTRACE(("SYNC-MMAP pid=%lu, pFile=%p, pMapRegion=%p, "
++ "rc=SQLITE_OK\n", osGetCurrentProcessId(),
++ pFile, pFile->pMapRegion));
++ }else{
++ pFile->lastErrno = osGetLastError();
++ OSTRACE(("SYNC-MMAP pid=%lu, pFile=%p, pMapRegion=%p, "
++ "rc=SQLITE_IOERR_MMAP\n", osGetCurrentProcessId(),
++ pFile, pFile->pMapRegion));
++ return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno,
++ "winSync1", pFile->zPath);
++ }
++ }
++#endif
++ rc = osFlushFileBuffers(pFile->h);
++ SimulateIOError( rc=FALSE );
++ if( rc ){
++ OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
++ osGetCurrentProcessId(), pFile, pFile->h));
++ return SQLITE_OK;
++ }else{
++ pFile->lastErrno = osGetLastError();
++ OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_FSYNC\n",
++ osGetCurrentProcessId(), pFile, pFile->h));
++ return winLogError(SQLITE_IOERR_FSYNC, pFile->lastErrno,
++ "winSync2", pFile->zPath);
++ }
++#endif
+ }
+
+ /*
+-** Change the lock state for a shared-memory segment.
++** Determine the current size of a file in bytes
+ */
+-static int winShmLock(
+- sqlite3_file *fd, /* Database file holding the shared memory */
+- int ofst, /* First lock to acquire or release */
+- int n, /* Number of locks to acquire or release */
+- int flags /* What to do with the lock */
+-){
+- winFile *pDbFd = (winFile*)fd; /* Connection holding shared memory */
+- winShm *p = pDbFd->pShm; /* The shared memory being locked */
+- winShm *pX; /* For looping over all siblings */
+- winShmNode *pShmNode = p->pShmNode;
+- int rc = SQLITE_OK; /* Result code */
+- u16 mask; /* Mask of locks to take or release */
+-
+- assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK );
+- assert( n>=1 );
+- assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED)
+- || flags==(SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE)
+- || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED)
+- || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
+- assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
+-
+- mask = (u16)((1U<<(ofst+n)) - (1U<<ofst));
+- assert( n>1 || mask==(1<<ofst) );
+- sqlite3_mutex_enter(pShmNode->mutex);
+- if( flags & SQLITE_SHM_UNLOCK ){
+- u16 allMask = 0; /* Mask of locks held by siblings */
++static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){
++ winFile *pFile = (winFile*)id;
++ int rc = SQLITE_OK;
+
+- /* See if any siblings hold this same lock */
+- for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
+- if( pX==p ) continue;
+- assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 );
+- allMask |= pX->sharedMask;
+- }
++ assert( id!=0 );
++ assert( pSize!=0 );
++ SimulateIOError(return SQLITE_IOERR_FSTAT);
++ OSTRACE(("SIZE file=%p, pSize=%p\n", pFile->h, pSize));
+
+- /* Unlock the system-level locks */
+- if( (mask & allMask)==0 ){
+- rc = winShmSystemLock(pShmNode, _SHM_UNLCK, ofst+WIN_SHM_BASE, n);
++#if SQLITE_OS_WINRT
++ {
++ FILE_STANDARD_INFO info;
++ if( osGetFileInformationByHandleEx(pFile->h, FileStandardInfo,
++ &info, sizeof(info)) ){
++ *pSize = info.EndOfFile.QuadPart;
+ }else{
+- rc = SQLITE_OK;
++ pFile->lastErrno = osGetLastError();
++ rc = winLogError(SQLITE_IOERR_FSTAT, pFile->lastErrno,
++ "winFileSize", pFile->zPath);
+ }
++ }
++#else
++ {
++ DWORD upperBits;
++ DWORD lowerBits;
++ DWORD lastErrno;
+
+- /* Undo the local locks */
+- if( rc==SQLITE_OK ){
+- p->exclMask &= ~mask;
+- p->sharedMask &= ~mask;
++ lowerBits = osGetFileSize(pFile->h, &upperBits);
++ *pSize = (((sqlite3_int64)upperBits)<<32) + lowerBits;
++ if( (lowerBits == INVALID_FILE_SIZE)
++ && ((lastErrno = osGetLastError())!=NO_ERROR) ){
++ pFile->lastErrno = lastErrno;
++ rc = winLogError(SQLITE_IOERR_FSTAT, pFile->lastErrno,
++ "winFileSize", pFile->zPath);
+ }
+- }else if( flags & SQLITE_SHM_SHARED ){
+- u16 allShared = 0; /* Union of locks held by connections other than "p" */
++ }
++#endif
++ OSTRACE(("SIZE file=%p, pSize=%p, *pSize=%lld, rc=%s\n",
++ pFile->h, pSize, *pSize, sqlite3ErrName(rc)));
++ return rc;
++}
+
+- /* Find out which shared locks are already held by sibling connections.
+- ** If any sibling already holds an exclusive lock, go ahead and return
+- ** SQLITE_BUSY.
+- */
+- for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
+- if( (pX->exclMask & mask)!=0 ){
+- rc = SQLITE_BUSY;
+- break;
+- }
+- allShared |= pX->sharedMask;
+- }
++/*
++** LOCKFILE_FAIL_IMMEDIATELY is undefined on some Windows systems.
++*/
++#ifndef LOCKFILE_FAIL_IMMEDIATELY
++# define LOCKFILE_FAIL_IMMEDIATELY 1
++#endif
+
+- /* Get shared locks at the system level, if necessary */
+- if( rc==SQLITE_OK ){
+- if( (allShared & mask)==0 ){
+- rc = winShmSystemLock(pShmNode, _SHM_RDLCK, ofst+WIN_SHM_BASE, n);
+- }else{
+- rc = SQLITE_OK;
+- }
+- }
++#ifndef LOCKFILE_EXCLUSIVE_LOCK
++# define LOCKFILE_EXCLUSIVE_LOCK 2
++#endif
+
+- /* Get the local shared locks */
+- if( rc==SQLITE_OK ){
+- p->sharedMask |= mask;
+- }
+- }else{
+- /* Make sure no sibling connections hold locks that will block this
+- ** lock. If any do, return SQLITE_BUSY right away.
+- */
+- for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
+- if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){
+- rc = SQLITE_BUSY;
+- break;
+- }
+- }
++/*
++** Historically, SQLite has used both the LockFile and LockFileEx functions.
++** When the LockFile function was used, it was always expected to fail
++** immediately if the lock could not be obtained. Also, it always expected to
++** obtain an exclusive lock. These flags are used with the LockFileEx function
++** and reflect those expectations; therefore, they should not be changed.
++*/
++#ifndef SQLITE_LOCKFILE_FLAGS
++# define SQLITE_LOCKFILE_FLAGS (LOCKFILE_FAIL_IMMEDIATELY | \
++ LOCKFILE_EXCLUSIVE_LOCK)
++#endif
+
+- /* Get the exclusive locks at the system level. Then if successful
+- ** also mark the local connection as being locked.
++/*
++** Currently, SQLite never calls the LockFileEx function without wanting the
++** call to fail immediately if the lock cannot be obtained.
++*/
++#ifndef SQLITE_LOCKFILEEX_FLAGS
++# define SQLITE_LOCKFILEEX_FLAGS (LOCKFILE_FAIL_IMMEDIATELY)
++#endif
++
++/*
++** Acquire a reader lock.
++** Different API routines are called depending on whether or not this
++** is Win9x or WinNT.
++*/
++static int winGetReadLock(winFile *pFile){
++ int res;
++ OSTRACE(("READ-LOCK file=%p, lock=%d\n", pFile->h, pFile->locktype));
++ if( osIsNT() ){
++#if SQLITE_OS_WINCE
++ /*
++ ** NOTE: Windows CE is handled differently here due its lack of the Win32
++ ** API LockFileEx.
+ */
+- if( rc==SQLITE_OK ){
+- rc = winShmSystemLock(pShmNode, _SHM_WRLCK, ofst+WIN_SHM_BASE, n);
+- if( rc==SQLITE_OK ){
+- assert( (p->sharedMask & mask)==0 );
+- p->exclMask |= mask;
+- }
+- }
++ res = winceLockFile(&pFile->h, SHARED_FIRST, 0, 1, 0);
++#else
++ res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS, SHARED_FIRST, 0,
++ SHARED_SIZE, 0);
++#endif
+ }
+- sqlite3_mutex_leave(pShmNode->mutex);
+- OSTRACE(("SHM-LOCK pid=%lu, id=%d, sharedMask=%03x, exclMask=%03x, rc=%s\n",
+- osGetCurrentProcessId(), p->id, p->sharedMask, p->exclMask,
+- sqlite3ErrName(rc)));
+- return rc;
++#ifdef SQLITE_WIN32_HAS_ANSI
++ else{
++ int lk;
++ sqlite3_randomness(sizeof(lk), &lk);
++ pFile->sharedLockByte = (short)((lk & 0x7fffffff)%(SHARED_SIZE - 1));
++ res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS,
++ SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0);
++ }
++#endif
++ if( res == 0 ){
++ pFile->lastErrno = osGetLastError();
++ /* No need to log a failure to lock */
++ }
++ OSTRACE(("READ-LOCK file=%p, result=%d\n", pFile->h, res));
++ return res;
+ }
+
+ /*
+-** Implement a memory barrier or memory fence on shared memory.
+-**
+-** All loads and stores begun before the barrier must complete before
+-** any load or store begun after the barrier.
++** Undo a readlock
+ */
+-static void winShmBarrier(
+- sqlite3_file *fd /* Database holding the shared memory */
+-){
+- UNUSED_PARAMETER(fd);
+- /* MemoryBarrier(); // does not work -- do not know why not */
+- winShmEnterMutex();
+- winShmLeaveMutex();
++static int winUnlockReadLock(winFile *pFile){
++ int res;
++ DWORD lastErrno;
++ OSTRACE(("READ-UNLOCK file=%p, lock=%d\n", pFile->h, pFile->locktype));
++ if( osIsNT() ){
++ res = winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
++ }
++#ifdef SQLITE_WIN32_HAS_ANSI
++ else{
++ res = winUnlockFile(&pFile->h, SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0);
++ }
++#endif
++ if( res==0 && ((lastErrno = osGetLastError())!=ERROR_NOT_LOCKED) ){
++ pFile->lastErrno = lastErrno;
++ winLogError(SQLITE_IOERR_UNLOCK, pFile->lastErrno,
++ "winUnlockReadLock", pFile->zPath);
++ }
++ OSTRACE(("READ-UNLOCK file=%p, result=%d\n", pFile->h, res));
++ return res;
+ }
+
+ /*
+-** This function is called to obtain a pointer to region iRegion of the
+-** shared-memory associated with the database file fd. Shared-memory regions
+-** are numbered starting from zero. Each shared-memory region is szRegion
+-** bytes in size.
+-**
+-** If an error occurs, an error code is returned and *pp is set to NULL.
+-**
+-** Otherwise, if the isWrite parameter is 0 and the requested shared-memory
+-** region has not been allocated (by any client, including one running in a
+-** separate process), then *pp is set to NULL and SQLITE_OK returned. If
+-** isWrite is non-zero and the requested shared-memory region has not yet
+-** been allocated, it is allocated by this function.
++** Lock the file with the lock specified by parameter locktype - one
++** of the following:
+ **
+-** If the shared-memory region has already been allocated or is allocated by
+-** this call as described above, then it is mapped into this processes
+-** address space (if it is not already), *pp is set to point to the mapped
+-** memory and SQLITE_OK returned.
+-*/
+-static int winShmMap(
+- sqlite3_file *fd, /* Handle open on database file */
+- int iRegion, /* Region to retrieve */
+- int szRegion, /* Size of regions */
+- int isWrite, /* True to extend file if necessary */
+- void volatile **pp /* OUT: Mapped memory */
+-){
+- winFile *pDbFd = (winFile*)fd;
+- winShm *pShm = pDbFd->pShm;
+- winShmNode *pShmNode;
+- int rc = SQLITE_OK;
+-
+- if( !pShm ){
+- rc = winOpenSharedMemory(pDbFd);
+- if( rc!=SQLITE_OK ) return rc;
+- pShm = pDbFd->pShm;
+- }
+- pShmNode = pShm->pShmNode;
+-
+- sqlite3_mutex_enter(pShmNode->mutex);
+- assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
++** (1) SHARED_LOCK
++** (2) RESERVED_LOCK
++** (3) PENDING_LOCK
++** (4) EXCLUSIVE_LOCK
++**
++** Sometimes when requesting one lock state, additional lock states
++** are inserted in between. The locking might fail on one of the later
++** transitions leaving the lock state different from what it started but
++** still short of its goal. The following chart shows the allowed
++** transitions and the inserted intermediate states:
++**
++** UNLOCKED -> SHARED
++** SHARED -> RESERVED
++** SHARED -> (PENDING) -> EXCLUSIVE
++** RESERVED -> (PENDING) -> EXCLUSIVE
++** PENDING -> EXCLUSIVE
++**
++** This routine will only increase a lock. The winUnlock() routine
++** erases all locks at once and returns us immediately to locking level 0.
++** It is not possible to lower the locking level one step at a time. You
++** must go straight to locking level 0.
++*/
++static int winLock(sqlite3_file *id, int locktype){
++ int rc = SQLITE_OK; /* Return code from subroutines */
++ int res = 1; /* Result of a Windows lock call */
++ int newLocktype; /* Set pFile->locktype to this value before exiting */
++ int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */
++ winFile *pFile = (winFile*)id;
++ DWORD lastErrno = NO_ERROR;
+
+- if( pShmNode->nRegion<=iRegion ){
+- struct ShmRegion *apNew; /* New aRegion[] array */
+- int nByte = (iRegion+1)*szRegion; /* Minimum required file size */
+- sqlite3_int64 sz; /* Current size of wal-index file */
++ assert( id!=0 );
++ OSTRACE(("LOCK file=%p, oldLock=%d(%d), newLock=%d\n",
++ pFile->h, pFile->locktype, pFile->sharedLockByte, locktype));
+
+- pShmNode->szRegion = szRegion;
++ /* If there is already a lock of this type or more restrictive on the
++ ** OsFile, do nothing. Don't use the end_lock: exit path, as
++ ** sqlite3OsEnterMutex() hasn't been called yet.
++ */
++ if( pFile->locktype>=locktype ){
++ OSTRACE(("LOCK-HELD file=%p, rc=SQLITE_OK\n", pFile->h));
++ return SQLITE_OK;
++ }
+
+- /* The requested region is not mapped into this processes address space.
+- ** Check to see if it has been allocated (i.e. if the wal-index file is
+- ** large enough to contain the requested region).
+- */
+- rc = winFileSize((sqlite3_file *)&pShmNode->hFile, &sz);
+- if( rc!=SQLITE_OK ){
+- rc = winLogError(SQLITE_IOERR_SHMSIZE, osGetLastError(),
+- "winShmMap1", pDbFd->zPath);
+- goto shmpage_out;
+- }
++ /* Make sure the locking sequence is correct
++ */
++ assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK );
++ assert( locktype!=PENDING_LOCK );
++ assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK );
+
+- if( sz<nByte ){
+- /* The requested memory region does not exist. If isWrite is set to
+- ** zero, exit early. *pp will be set to NULL and SQLITE_OK returned.
+- **
+- ** Alternatively, if isWrite is non-zero, use ftruncate() to allocate
+- ** the requested memory region.
++ /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or
++ ** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of
++ ** the PENDING_LOCK byte is temporary.
++ */
++ newLocktype = pFile->locktype;
++ if( (pFile->locktype==NO_LOCK)
++ || ( (locktype==EXCLUSIVE_LOCK)
++ && (pFile->locktype==RESERVED_LOCK))
++ ){
++ int cnt = 3;
++ while( cnt-->0 && (res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS,
++ PENDING_BYTE, 0, 1, 0))==0 ){
++ /* Try 3 times to get the pending lock. This is needed to work
++ ** around problems caused by indexing and/or anti-virus software on
++ ** Windows systems.
++ ** If you are using this code as a model for alternative VFSes, do not
++ ** copy this retry logic. It is a hack intended for Windows only.
+ */
+- if( !isWrite ) goto shmpage_out;
+- rc = winTruncate((sqlite3_file *)&pShmNode->hFile, nByte);
+- if( rc!=SQLITE_OK ){
+- rc = winLogError(SQLITE_IOERR_SHMSIZE, osGetLastError(),
+- "winShmMap2", pDbFd->zPath);
+- goto shmpage_out;
++ lastErrno = osGetLastError();
++ OSTRACE(("LOCK-PENDING-FAIL file=%p, count=%d, result=%d\n",
++ pFile->h, cnt, res));
++ if( lastErrno==ERROR_INVALID_HANDLE ){
++ pFile->lastErrno = lastErrno;
++ rc = SQLITE_IOERR_LOCK;
++ OSTRACE(("LOCK-FAIL file=%p, count=%d, rc=%s\n",
++ pFile->h, cnt, sqlite3ErrName(rc)));
++ return rc;
+ }
++ if( cnt ) sqlite3_win32_sleep(1);
++ }
++ gotPendingLock = res;
++ if( !res ){
++ lastErrno = osGetLastError();
+ }
++ }
+
+- /* Map the requested memory region into this processes address space. */
+- apNew = (struct ShmRegion *)sqlite3_realloc64(
+- pShmNode->aRegion, (iRegion+1)*sizeof(apNew[0])
+- );
+- if( !apNew ){
+- rc = SQLITE_IOERR_NOMEM;
+- goto shmpage_out;
++ /* Acquire a shared lock
++ */
++ if( locktype==SHARED_LOCK && res ){
++ assert( pFile->locktype==NO_LOCK );
++ res = winGetReadLock(pFile);
++ if( res ){
++ newLocktype = SHARED_LOCK;
++ }else{
++ lastErrno = osGetLastError();
+ }
+- pShmNode->aRegion = apNew;
++ }
+
+- while( pShmNode->nRegion<=iRegion ){
+- HANDLE hMap = NULL; /* file-mapping handle */
+- void *pMap = 0; /* Mapped memory region */
++ /* Acquire a RESERVED lock
++ */
++ if( locktype==RESERVED_LOCK && res ){
++ assert( pFile->locktype==SHARED_LOCK );
++ res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, RESERVED_BYTE, 0, 1, 0);
++ if( res ){
++ newLocktype = RESERVED_LOCK;
++ }else{
++ lastErrno = osGetLastError();
++ }
++ }
+
+-#if SQLITE_OS_WINRT
+- hMap = osCreateFileMappingFromApp(pShmNode->hFile.h,
+- NULL, PAGE_READWRITE, nByte, NULL
+- );
+-#elif defined(SQLITE_WIN32_HAS_WIDE)
+- hMap = osCreateFileMappingW(pShmNode->hFile.h,
+- NULL, PAGE_READWRITE, 0, nByte, NULL
+- );
+-#elif defined(SQLITE_WIN32_HAS_ANSI)
+- hMap = osCreateFileMappingA(pShmNode->hFile.h,
+- NULL, PAGE_READWRITE, 0, nByte, NULL
+- );
+-#endif
+- OSTRACE(("SHM-MAP-CREATE pid=%lu, region=%d, size=%d, rc=%s\n",
+- osGetCurrentProcessId(), pShmNode->nRegion, nByte,
+- hMap ? "ok" : "failed"));
+- if( hMap ){
+- int iOffset = pShmNode->nRegion*szRegion;
+- int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity;
+-#if SQLITE_OS_WINRT
+- pMap = osMapViewOfFileFromApp(hMap, FILE_MAP_WRITE | FILE_MAP_READ,
+- iOffset - iOffsetShift, szRegion + iOffsetShift
+- );
+-#else
+- pMap = osMapViewOfFile(hMap, FILE_MAP_WRITE | FILE_MAP_READ,
+- 0, iOffset - iOffsetShift, szRegion + iOffsetShift
+- );
+-#endif
+- OSTRACE(("SHM-MAP-MAP pid=%lu, region=%d, offset=%d, size=%d, rc=%s\n",
+- osGetCurrentProcessId(), pShmNode->nRegion, iOffset,
+- szRegion, pMap ? "ok" : "failed"));
+- }
+- if( !pMap ){
+- pShmNode->lastErrno = osGetLastError();
+- rc = winLogError(SQLITE_IOERR_SHMMAP, pShmNode->lastErrno,
+- "winShmMap3", pDbFd->zPath);
+- if( hMap ) osCloseHandle(hMap);
+- goto shmpage_out;
+- }
++ /* Acquire a PENDING lock
++ */
++ if( locktype==EXCLUSIVE_LOCK && res ){
++ newLocktype = PENDING_LOCK;
++ gotPendingLock = 0;
++ }
+
+- pShmNode->aRegion[pShmNode->nRegion].pMap = pMap;
+- pShmNode->aRegion[pShmNode->nRegion].hMap = hMap;
+- pShmNode->nRegion++;
++ /* Acquire an EXCLUSIVE lock
++ */
++ if( locktype==EXCLUSIVE_LOCK && res ){
++ assert( pFile->locktype>=SHARED_LOCK );
++ res = winUnlockReadLock(pFile);
++ res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, SHARED_FIRST, 0,
++ SHARED_SIZE, 0);
++ if( res ){
++ newLocktype = EXCLUSIVE_LOCK;
++ }else{
++ lastErrno = osGetLastError();
++ winGetReadLock(pFile);
+ }
+ }
+
+-shmpage_out:
+- if( pShmNode->nRegion>iRegion ){
+- int iOffset = iRegion*szRegion;
+- int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity;
+- char *p = (char *)pShmNode->aRegion[iRegion].pMap;
+- *pp = (void *)&p[iOffsetShift];
++ /* If we are holding a PENDING lock that ought to be released, then
++ ** release it now.
++ */
++ if( gotPendingLock && locktype==SHARED_LOCK ){
++ winUnlockFile(&pFile->h, PENDING_BYTE, 0, 1, 0);
++ }
++
++ /* Update the state of the lock has held in the file descriptor then
++ ** return the appropriate result code.
++ */
++ if( res ){
++ rc = SQLITE_OK;
+ }else{
+- *pp = 0;
++ pFile->lastErrno = lastErrno;
++ rc = SQLITE_BUSY;
++ OSTRACE(("LOCK-FAIL file=%p, wanted=%d, got=%d\n",
++ pFile->h, locktype, newLocktype));
+ }
+- sqlite3_mutex_leave(pShmNode->mutex);
++ pFile->locktype = (u8)newLocktype;
++ OSTRACE(("LOCK file=%p, lock=%d, rc=%s\n",
++ pFile->h, pFile->locktype, sqlite3ErrName(rc)));
+ return rc;
+ }
+
+-#else
+-# define winShmMap 0
+-# define winShmLock 0
+-# define winShmBarrier 0
+-# define winShmUnmap 0
+-#endif /* #ifndef SQLITE_OMIT_WAL */
+-
+ /*
+-** Cleans up the mapped region of the specified file, if any.
++** This routine checks if there is a RESERVED lock held on the specified
++** file by this or any other process. If such a lock is held, return
++** non-zero, otherwise zero.
+ */
+-#if SQLITE_MAX_MMAP_SIZE>0
+-static int winUnmapfile(winFile *pFile){
+- assert( pFile!=0 );
+- OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, hMap=%p, pMapRegion=%p, "
+- "mmapSize=%lld, mmapSizeActual=%lld, mmapSizeMax=%lld\n",
+- osGetCurrentProcessId(), pFile, pFile->hMap, pFile->pMapRegion,
+- pFile->mmapSize, pFile->mmapSizeActual, pFile->mmapSizeMax));
+- if( pFile->pMapRegion ){
+- if( !osUnmapViewOfFile(pFile->pMapRegion) ){
+- pFile->lastErrno = osGetLastError();
+- OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, pMapRegion=%p, "
+- "rc=SQLITE_IOERR_MMAP\n", osGetCurrentProcessId(), pFile,
+- pFile->pMapRegion));
+- return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno,
+- "winUnmapfile1", pFile->zPath);
+- }
+- pFile->pMapRegion = 0;
+- pFile->mmapSize = 0;
+- pFile->mmapSizeActual = 0;
+- }
+- if( pFile->hMap!=NULL ){
+- if( !osCloseHandle(pFile->hMap) ){
+- pFile->lastErrno = osGetLastError();
+- OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, hMap=%p, rc=SQLITE_IOERR_MMAP\n",
+- osGetCurrentProcessId(), pFile, pFile->hMap));
+- return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno,
+- "winUnmapfile2", pFile->zPath);
++static int winCheckReservedLock(sqlite3_file *id, int *pResOut){
++ int res;
++ winFile *pFile = (winFile*)id;
++
++ SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
++ OSTRACE(("TEST-WR-LOCK file=%p, pResOut=%p\n", pFile->h, pResOut));
++
++ assert( id!=0 );
++ if( pFile->locktype>=RESERVED_LOCK ){
++ res = 1;
++ OSTRACE(("TEST-WR-LOCK file=%p, result=%d (local)\n", pFile->h, res));
++ }else{
++ res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS,RESERVED_BYTE, 0, 1, 0);
++ if( res ){
++ winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0);
+ }
+- pFile->hMap = NULL;
++ res = !res;
++ OSTRACE(("TEST-WR-LOCK file=%p, result=%d (remote)\n", pFile->h, res));
+ }
+- OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, rc=SQLITE_OK\n",
+- osGetCurrentProcessId(), pFile));
++ *pResOut = res;
++ OSTRACE(("TEST-WR-LOCK file=%p, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n",
++ pFile->h, pResOut, *pResOut));
+ return SQLITE_OK;
+ }
+
+ /*
+-** Memory map or remap the file opened by file-descriptor pFd (if the file
+-** is already mapped, the existing mapping is replaced by the new). Or, if
+-** there already exists a mapping for this file, and there are still
+-** outstanding xFetch() references to it, this function is a no-op.
++** Lower the locking level on file descriptor id to locktype. locktype
++** must be either NO_LOCK or SHARED_LOCK.
+ **
+-** If parameter nByte is non-negative, then it is the requested size of
+-** the mapping to create. Otherwise, if nByte is less than zero, then the
+-** requested size is the size of the file on disk. The actual size of the
+-** created mapping is either the requested size or the value configured
+-** using SQLITE_FCNTL_MMAP_SIZE, whichever is smaller.
++** If the locking level of the file descriptor is already at or below
++** the requested locking level, this routine is a no-op.
+ **
+-** SQLITE_OK is returned if no error occurs (even if the mapping is not
+-** recreated as a result of outstanding references) or an SQLite error
+-** code otherwise.
++** It is not possible for this routine to fail if the second argument
++** is NO_LOCK. If the second argument is SHARED_LOCK then this routine
++** might return SQLITE_IOERR;
+ */
+-static int winMapfile(winFile *pFd, sqlite3_int64 nByte){
+- sqlite3_int64 nMap = nByte;
+- int rc;
+-
+- assert( nMap>=0 || pFd->nFetchOut==0 );
+- OSTRACE(("MAP-FILE pid=%lu, pFile=%p, size=%lld\n",
+- osGetCurrentProcessId(), pFd, nByte));
+-
+- if( pFd->nFetchOut>0 ) return SQLITE_OK;
+-
+- if( nMap<0 ){
+- rc = winFileSize((sqlite3_file*)pFd, &nMap);
+- if( rc ){
+- OSTRACE(("MAP-FILE pid=%lu, pFile=%p, rc=SQLITE_IOERR_FSTAT\n",
+- osGetCurrentProcessId(), pFd));
+- return SQLITE_IOERR_FSTAT;
++static int winUnlock(sqlite3_file *id, int locktype){
++ int type;
++ winFile *pFile = (winFile*)id;
++ int rc = SQLITE_OK;
++ assert( pFile!=0 );
++ assert( locktype<=SHARED_LOCK );
++ OSTRACE(("UNLOCK file=%p, oldLock=%d(%d), newLock=%d\n",
++ pFile->h, pFile->locktype, pFile->sharedLockByte, locktype));
++ type = pFile->locktype;
++ if( type>=EXCLUSIVE_LOCK ){
++ winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
++ if( locktype==SHARED_LOCK && !winGetReadLock(pFile) ){
++ /* This should never happen. We should always be able to
++ ** reacquire the read lock */
++ rc = winLogError(SQLITE_IOERR_UNLOCK, osGetLastError(),
++ "winUnlock", pFile->zPath);
+ }
+ }
+- if( nMap>pFd->mmapSizeMax ){
+- nMap = pFd->mmapSizeMax;
++ if( type>=RESERVED_LOCK ){
++ winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0);
+ }
+- nMap &= ~(sqlite3_int64)(winSysInfo.dwPageSize - 1);
+-
+- if( nMap==0 && pFd->mmapSize>0 ){
+- winUnmapfile(pFd);
++ if( locktype==NO_LOCK && type>=SHARED_LOCK ){
++ winUnlockReadLock(pFile);
+ }
+- if( nMap!=pFd->mmapSize ){
+- void *pNew = 0;
+- DWORD protect = PAGE_READONLY;
+- DWORD flags = FILE_MAP_READ;
+-
+- winUnmapfile(pFd);
+- if( (pFd->ctrlFlags & WINFILE_RDONLY)==0 ){
+- protect = PAGE_READWRITE;
+- flags |= FILE_MAP_WRITE;
+- }
+-#if SQLITE_OS_WINRT
+- pFd->hMap = osCreateFileMappingFromApp(pFd->h, NULL, protect, nMap, NULL);
+-#elif defined(SQLITE_WIN32_HAS_WIDE)
+- pFd->hMap = osCreateFileMappingW(pFd->h, NULL, protect,
+- (DWORD)((nMap>>32) & 0xffffffff),
+- (DWORD)(nMap & 0xffffffff), NULL);
+-#elif defined(SQLITE_WIN32_HAS_ANSI)
+- pFd->hMap = osCreateFileMappingA(pFd->h, NULL, protect,
+- (DWORD)((nMap>>32) & 0xffffffff),
+- (DWORD)(nMap & 0xffffffff), NULL);
+-#endif
+- if( pFd->hMap==NULL ){
+- pFd->lastErrno = osGetLastError();
+- rc = winLogError(SQLITE_IOERR_MMAP, pFd->lastErrno,
+- "winMapfile1", pFd->zPath);
+- /* Log the error, but continue normal operation using xRead/xWrite */
+- OSTRACE(("MAP-FILE-CREATE pid=%lu, pFile=%p, rc=%s\n",
+- osGetCurrentProcessId(), pFd, sqlite3ErrName(rc)));
+- return SQLITE_OK;
+- }
+- assert( (nMap % winSysInfo.dwPageSize)==0 );
+- assert( sizeof(SIZE_T)==sizeof(sqlite3_int64) || nMap<=0xffffffff );
+-#if SQLITE_OS_WINRT
+- pNew = osMapViewOfFileFromApp(pFd->hMap, flags, 0, (SIZE_T)nMap);
+-#else
+- pNew = osMapViewOfFile(pFd->hMap, flags, 0, 0, (SIZE_T)nMap);
+-#endif
+- if( pNew==NULL ){
+- osCloseHandle(pFd->hMap);
+- pFd->hMap = NULL;
+- pFd->lastErrno = osGetLastError();
+- rc = winLogError(SQLITE_IOERR_MMAP, pFd->lastErrno,
+- "winMapfile2", pFd->zPath);
+- /* Log the error, but continue normal operation using xRead/xWrite */
+- OSTRACE(("MAP-FILE-MAP pid=%lu, pFile=%p, rc=%s\n",
+- osGetCurrentProcessId(), pFd, sqlite3ErrName(rc)));
+- return SQLITE_OK;
+- }
+- pFd->pMapRegion = pNew;
+- pFd->mmapSize = nMap;
+- pFd->mmapSizeActual = nMap;
++ if( type>=PENDING_LOCK ){
++ winUnlockFile(&pFile->h, PENDING_BYTE, 0, 1, 0);
+ }
+-
+- OSTRACE(("MAP-FILE pid=%lu, pFile=%p, rc=SQLITE_OK\n",
+- osGetCurrentProcessId(), pFd));
+- return SQLITE_OK;
++ pFile->locktype = (u8)locktype;
++ OSTRACE(("UNLOCK file=%p, lock=%d, rc=%s\n",
++ pFile->h, pFile->locktype, sqlite3ErrName(rc)));
++ return rc;
+ }
+-#endif /* SQLITE_MAX_MMAP_SIZE>0 */
+
+ /*
+-** If possible, return a pointer to a mapping of file fd starting at offset
+-** iOff. The mapping must be valid for at least nAmt bytes.
+-**
+-** If such a pointer can be obtained, store it in *pp and return SQLITE_OK.
+-** Or, if one cannot but no error occurs, set *pp to 0 and return SQLITE_OK.
+-** Finally, if an error does occur, return an SQLite error code. The final
+-** value of *pp is undefined in this case.
++** If *pArg is initially negative then this is a query. Set *pArg to
++** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set.
+ **
+-** If this function does return a pointer, the caller must eventually
+-** release the reference by calling winUnfetch().
++** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags.
+ */
+-static int winFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
+-#if SQLITE_MAX_MMAP_SIZE>0
+- winFile *pFd = (winFile*)fd; /* The underlying database file */
+-#endif
+- *pp = 0;
++static void winModeBit(winFile *pFile, unsigned char mask, int *pArg){
++ if( *pArg<0 ){
++ *pArg = (pFile->ctrlFlags & mask)!=0;
++ }else if( (*pArg)==0 ){
++ pFile->ctrlFlags &= ~mask;
++ }else{
++ pFile->ctrlFlags |= mask;
++ }
++}
+
+- OSTRACE(("FETCH pid=%lu, pFile=%p, offset=%lld, amount=%d, pp=%p\n",
+- osGetCurrentProcessId(), fd, iOff, nAmt, pp));
++/* Forward references to VFS helper methods used for temporary files */
++static int winGetTempname(sqlite3_vfs *, char **);
++static int winIsDir(const void *);
++static BOOL winIsDriveLetterAndColon(const char *);
+
+-#if SQLITE_MAX_MMAP_SIZE>0
+- if( pFd->mmapSizeMax>0 ){
+- if( pFd->pMapRegion==0 ){
+- int rc = winMapfile(pFd, -1);
+- if( rc!=SQLITE_OK ){
+- OSTRACE(("FETCH pid=%lu, pFile=%p, rc=%s\n",
+- osGetCurrentProcessId(), pFd, sqlite3ErrName(rc)));
++/*
++** Control and query of the open file handle.
++*/
++static int winFileControl(sqlite3_file *id, int op, void *pArg){
++ winFile *pFile = (winFile*)id;
++ OSTRACE(("FCNTL file=%p, op=%d, pArg=%p\n", pFile->h, op, pArg));
++ switch( op ){
++ case SQLITE_FCNTL_LOCKSTATE: {
++ *(int*)pArg = pFile->locktype;
++ OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
++ return SQLITE_OK;
++ }
++ case SQLITE_LAST_ERRNO: {
++ *(int*)pArg = (int)pFile->lastErrno;
++ OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
++ return SQLITE_OK;
++ }
++ case SQLITE_FCNTL_CHUNK_SIZE: {
++ pFile->szChunk = *(int *)pArg;
++ OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
++ return SQLITE_OK;
++ }
++ case SQLITE_FCNTL_SIZE_HINT: {
++ if( pFile->szChunk>0 ){
++ sqlite3_int64 oldSz;
++ int rc = winFileSize(id, &oldSz);
++ if( rc==SQLITE_OK ){
++ sqlite3_int64 newSz = *(sqlite3_int64*)pArg;
++ if( newSz>oldSz ){
++ SimulateIOErrorBenign(1);
++ rc = winTruncate(id, newSz);
++ SimulateIOErrorBenign(0);
++ }
++ }
++ OSTRACE(("FCNTL file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc)));
+ return rc;
+ }
++ OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
++ return SQLITE_OK;
++ }
++ case SQLITE_FCNTL_PERSIST_WAL: {
++ winModeBit(pFile, WINFILE_PERSIST_WAL, (int*)pArg);
++ OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
++ return SQLITE_OK;
++ }
++ case SQLITE_FCNTL_POWERSAFE_OVERWRITE: {
++ winModeBit(pFile, WINFILE_PSOW, (int*)pArg);
++ OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
++ return SQLITE_OK;
++ }
++ case SQLITE_FCNTL_VFSNAME: {
++ *(char**)pArg = sqlite3_mprintf("%s", pFile->pVfs->zName);
++ OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
++ return SQLITE_OK;
++ }
++ case SQLITE_FCNTL_WIN32_AV_RETRY: {
++ int *a = (int*)pArg;
++ if( a[0]>0 ){
++ winIoerrRetry = a[0];
++ }else{
++ a[0] = winIoerrRetry;
++ }
++ if( a[1]>0 ){
++ winIoerrRetryDelay = a[1];
++ }else{
++ a[1] = winIoerrRetryDelay;
++ }
++ OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
++ return SQLITE_OK;
++ }
++#ifdef SQLITE_TEST
++ case SQLITE_FCNTL_WIN32_SET_HANDLE: {
++ LPHANDLE phFile = (LPHANDLE)pArg;
++ HANDLE hOldFile = pFile->h;
++ pFile->h = *phFile;
++ *phFile = hOldFile;
++ OSTRACE(("FCNTL oldFile=%p, newFile=%p, rc=SQLITE_OK\n",
++ hOldFile, pFile->h));
++ return SQLITE_OK;
++ }
++#endif
++ case SQLITE_FCNTL_TEMPFILENAME: {
++ char *zTFile = 0;
++ int rc = winGetTempname(pFile->pVfs, &zTFile);
++ if( rc==SQLITE_OK ){
++ *(char**)pArg = zTFile;
++ }
++ OSTRACE(("FCNTL file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc)));
++ return rc;
+ }
+- if( pFd->mmapSize >= iOff+nAmt ){
+- *pp = &((u8 *)pFd->pMapRegion)[iOff];
+- pFd->nFetchOut++;
++#if SQLITE_MAX_MMAP_SIZE>0
++ case SQLITE_FCNTL_MMAP_SIZE: {
++ i64 newLimit = *(i64*)pArg;
++ int rc = SQLITE_OK;
++ if( newLimit>sqlite3GlobalConfig.mxMmap ){
++ newLimit = sqlite3GlobalConfig.mxMmap;
++ }
++ *(i64*)pArg = pFile->mmapSizeMax;
++ if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){
++ pFile->mmapSizeMax = newLimit;
++ if( pFile->mmapSize>0 ){
++ winUnmapfile(pFile);
++ rc = winMapfile(pFile, -1);
++ }
++ }
++ OSTRACE(("FCNTL file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc)));
++ return rc;
+ }
+- }
+ #endif
+-
+- OSTRACE(("FETCH pid=%lu, pFile=%p, pp=%p, *pp=%p, rc=SQLITE_OK\n",
+- osGetCurrentProcessId(), fd, pp, *pp));
+- return SQLITE_OK;
++ }
++ OSTRACE(("FCNTL file=%p, rc=SQLITE_NOTFOUND\n", pFile->h));
++ return SQLITE_NOTFOUND;
+ }
+
+ /*
+-** If the third argument is non-NULL, then this function releases a
+-** reference obtained by an earlier call to winFetch(). The second
+-** argument passed to this function must be the same as the corresponding
+-** argument that was passed to the winFetch() invocation.
++** Return the sector size in bytes of the underlying block device for
++** the specified file. This is almost always 512 bytes, but may be
++** larger for some devices.
+ **
+-** Or, if the third argument is NULL, then this function is being called
+-** to inform the VFS layer that, according to POSIX, any existing mapping
+-** may now be invalid and should be unmapped.
++** SQLite code assumes this function cannot fail. It also assumes that
++** if two files are created in the same file-system directory (i.e.
++** a database and its journal file) that the sector size will be the
++** same for both.
+ */
+-static int winUnfetch(sqlite3_file *fd, i64 iOff, void *p){
+-#if SQLITE_MAX_MMAP_SIZE>0
+- winFile *pFd = (winFile*)fd; /* The underlying database file */
+-
+- /* If p==0 (unmap the entire file) then there must be no outstanding
+- ** xFetch references. Or, if p!=0 (meaning it is an xFetch reference),
+- ** then there must be at least one outstanding. */
+- assert( (p==0)==(pFd->nFetchOut==0) );
+-
+- /* If p!=0, it must match the iOff value. */
+- assert( p==0 || p==&((u8 *)pFd->pMapRegion)[iOff] );
+-
+- OSTRACE(("UNFETCH pid=%lu, pFile=%p, offset=%lld, p=%p\n",
+- osGetCurrentProcessId(), pFd, iOff, p));
+-
+- if( p ){
+- pFd->nFetchOut--;
+- }else{
+- /* FIXME: If Windows truly always prevents truncating or deleting a
+- ** file while a mapping is held, then the following winUnmapfile() call
+- ** is unnecessary can be omitted - potentially improving
+- ** performance. */
+- winUnmapfile(pFd);
+- }
+-
+- assert( pFd->nFetchOut>=0 );
+-#endif
+-
+- OSTRACE(("UNFETCH pid=%lu, pFile=%p, rc=SQLITE_OK\n",
+- osGetCurrentProcessId(), fd));
+- return SQLITE_OK;
++static int winSectorSize(sqlite3_file *id){
++ (void)id;
++ return SQLITE_DEFAULT_SECTOR_SIZE;
+ }
+
+ /*
+-** Here ends the implementation of all sqlite3_file methods.
+-**
+-********************** End sqlite3_file Methods *******************************
+-******************************************************************************/
++** Return a vector of device characteristics.
++*/
++static int winDeviceCharacteristics(sqlite3_file *id){
++ winFile *p = (winFile*)id;
++ return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN |
++ ((p->ctrlFlags & WINFILE_PSOW)?SQLITE_IOCAP_POWERSAFE_OVERWRITE:0);
++}
+
+ /*
+-** This vector defines all the methods that can operate on an
+-** sqlite3_file for win32.
++** Windows will only let you create file view mappings
++** on allocation size granularity boundaries.
++** During sqlite3_os_init() we do a GetSystemInfo()
++** to get the granularity size.
+ */
+-static const sqlite3_io_methods winIoMethod = {
+- 3, /* iVersion */
+- winClose, /* xClose */
+- winRead, /* xRead */
+- winWrite, /* xWrite */
+- winTruncate, /* xTruncate */
+- winSync, /* xSync */
+- winFileSize, /* xFileSize */
+- winLock, /* xLock */
+- winUnlock, /* xUnlock */
+- winCheckReservedLock, /* xCheckReservedLock */
+- winFileControl, /* xFileControl */
+- winSectorSize, /* xSectorSize */
+- winDeviceCharacteristics, /* xDeviceCharacteristics */
+- winShmMap, /* xShmMap */
+- winShmLock, /* xShmLock */
+- winShmBarrier, /* xShmBarrier */
+- winShmUnmap, /* xShmUnmap */
+- winFetch, /* xFetch */
+- winUnfetch /* xUnfetch */
+-};
++static SYSTEM_INFO winSysInfo;
+
+-/****************************************************************************
+-**************************** sqlite3_vfs methods ****************************
+-**
+-** This division contains the implementation of methods on the
+-** sqlite3_vfs object.
+-*/
++#ifndef SQLITE_OMIT_WAL
+
+-#if defined(__CYGWIN__)
+ /*
+-** Convert a filename from whatever the underlying operating system
+-** supports for filenames into UTF-8. Space to hold the result is
+-** obtained from malloc and must be freed by the calling function.
++** Helper functions to obtain and relinquish the global mutex. The
++** global mutex is used to protect the winLockInfo objects used by
++** this file, all of which may be shared by multiple threads.
++**
++** Function winShmMutexHeld() is used to assert() that the global mutex
++** is held when required. This function is only used as part of assert()
++** statements. e.g.
++**
++** winShmEnterMutex()
++** assert( winShmMutexHeld() );
++** winShmLeaveMutex()
+ */
+-static char *winConvertToUtf8Filename(const void *zFilename){
+- char *zConverted = 0;
+- if( osIsNT() ){
+- zConverted = winUnicodeToUtf8(zFilename);
+- }
+-#ifdef SQLITE_WIN32_HAS_ANSI
+- else{
+- zConverted = sqlite3_win32_mbcs_to_utf8(zFilename);
+- }
+-#endif
+- /* caller will handle out of memory */
+- return zConverted;
++static void winShmEnterMutex(void){
++ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
++}
++static void winShmLeaveMutex(void){
++ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
++}
++#ifndef NDEBUG
++static int winShmMutexHeld(void) {
++ return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+ }
+ #endif
+
+ /*
+-** Convert a UTF-8 filename into whatever form the underlying
+-** operating system wants filenames in. Space to hold the result
+-** is obtained from malloc and must be freed by the calling
+-** function.
++** Object used to represent a single file opened and mmapped to provide
++** shared memory. When multiple threads all reference the same
++** log-summary, each thread has its own winFile object, but they all
++** point to a single instance of this object. In other words, each
++** log-summary is opened only once per process.
++**
++** winShmMutexHeld() must be true when creating or destroying
++** this object or while reading or writing the following fields:
++**
++** nRef
++** pNext
++**
++** The following fields are read-only after the object is created:
++**
++** fid
++** zFilename
++**
++** Either winShmNode.mutex must be held or winShmNode.nRef==0 and
++** winShmMutexHeld() is true when reading or writing any other field
++** in this structure.
++**
+ */
+-static void *winConvertFromUtf8Filename(const char *zFilename){
+- void *zConverted = 0;
+- if( osIsNT() ){
+- zConverted = winUtf8ToUnicode(zFilename);
+- }
+-#ifdef SQLITE_WIN32_HAS_ANSI
+- else{
+- zConverted = sqlite3_win32_utf8_to_mbcs(zFilename);
+- }
++struct winShmNode {
++ sqlite3_mutex *mutex; /* Mutex to access this object */
++ char *zFilename; /* Name of the file */
++ winFile hFile; /* File handle from winOpen */
++
++ int szRegion; /* Size of shared-memory regions */
++ int nRegion; /* Size of array apRegion */
++ struct ShmRegion {
++ HANDLE hMap; /* File handle from CreateFileMapping */
++ void *pMap;
++ } *aRegion;
++ DWORD lastErrno; /* The Windows errno from the last I/O error */
++
++ int nRef; /* Number of winShm objects pointing to this */
++ winShm *pFirst; /* All winShm objects pointing to this */
++ winShmNode *pNext; /* Next in list of all winShmNode objects */
++#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
++ u8 nextShmId; /* Next available winShm.id value */
+ #endif
+- /* caller will handle out of memory */
+- return zConverted;
+-}
++};
+
+ /*
+-** This function returns non-zero if the specified UTF-8 string buffer
+-** ends with a directory separator character or one was successfully
+-** added to it.
++** A global array of all winShmNode objects.
++**
++** The winShmMutexHeld() must be true while reading or writing this list.
+ */
+-static int winMakeEndInDirSep(int nBuf, char *zBuf){
+- if( zBuf ){
+- int nLen = sqlite3Strlen30(zBuf);
+- if( nLen>0 ){
+- if( winIsDirSep(zBuf[nLen-1]) ){
+- return 1;
+- }else if( nLen+1<nBuf ){
+- zBuf[nLen] = winGetDirSep();
+- zBuf[nLen+1] = '\0';
+- return 1;
+- }
+- }
+- }
+- return 0;
+-}
++static winShmNode *winShmNodeList = 0;
+
+ /*
+-** Create a temporary file name and store the resulting pointer into pzBuf.
+-** The pointer returned in pzBuf must be freed via sqlite3_free().
++** Structure used internally by this VFS to record the state of an
++** open shared memory connection.
++**
++** The following fields are initialized when this object is created and
++** are read-only thereafter:
++**
++** winShm.pShmNode
++** winShm.id
++**
++** All other fields are read/write. The winShm.pShmNode->mutex must be held
++** while accessing any read/write fields.
+ */
+-static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
+- static char zChars[] =
+- "abcdefghijklmnopqrstuvwxyz"
+- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+- "0123456789";
+- size_t i, j;
+- int nPre = sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX);
+- int nMax, nBuf, nDir, nLen;
+- char *zBuf;
+-
+- /* It's odd to simulate an io-error here, but really this is just
+- ** using the io-error infrastructure to test that SQLite handles this
+- ** function failing.
+- */
+- SimulateIOError( return SQLITE_IOERR );
++struct winShm {
++ winShmNode *pShmNode; /* The underlying winShmNode object */
++ winShm *pNext; /* Next winShm with the same winShmNode */
++ u8 hasMutex; /* True if holding the winShmNode mutex */
++ u16 sharedMask; /* Mask of shared locks held */
++ u16 exclMask; /* Mask of exclusive locks held */
++#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
++ u8 id; /* Id of this connection with its winShmNode */
++#endif
++};
+
+- /* Allocate a temporary buffer to store the fully qualified file
+- ** name for the temporary file. If this fails, we cannot continue.
+- */
+- nMax = pVfs->mxPathname; nBuf = nMax + 2;
+- zBuf = sqlite3MallocZero( nBuf );
+- if( !zBuf ){
+- OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
+- return SQLITE_IOERR_NOMEM;
+- }
++/*
++** Constants used for locking
++*/
++#define WIN_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */
++#define WIN_SHM_DMS (WIN_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */
+
+- /* Figure out the effective temporary directory. First, check if one
+- ** has been explicitly set by the application; otherwise, use the one
+- ** configured by the operating system.
+- */
+- nDir = nMax - (nPre + 15);
+- assert( nDir>0 );
+- if( sqlite3_temp_directory ){
+- int nDirLen = sqlite3Strlen30(sqlite3_temp_directory);
+- if( nDirLen>0 ){
+- if( !winIsDirSep(sqlite3_temp_directory[nDirLen-1]) ){
+- nDirLen++;
+- }
+- if( nDirLen>nDir ){
+- sqlite3_free(zBuf);
+- OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n"));
+- return winLogError(SQLITE_ERROR, 0, "winGetTempname1", 0);
+- }
+- sqlite3_snprintf(nMax, zBuf, "%s", sqlite3_temp_directory);
+- }
+- }
+-#if defined(__CYGWIN__)
+- else{
+- static const char *azDirs[] = {
+- 0, /* getenv("SQLITE_TMPDIR") */
+- 0, /* getenv("TMPDIR") */
+- 0, /* getenv("TMP") */
+- 0, /* getenv("TEMP") */
+- 0, /* getenv("USERPROFILE") */
+- "/var/tmp",
+- "/usr/tmp",
+- "/tmp",
+- ".",
+- 0 /* List terminator */
+- };
+- unsigned int i;
+- const char *zDir = 0;
++/*
++** Apply advisory locks for all n bytes beginning at ofst.
++*/
++#define _SHM_UNLCK 1
++#define _SHM_RDLCK 2
++#define _SHM_WRLCK 3
++static int winShmSystemLock(
++ winShmNode *pFile, /* Apply locks to this open shared-memory segment */
++ int lockType, /* _SHM_UNLCK, _SHM_RDLCK, or _SHM_WRLCK */
++ int ofst, /* Offset to first byte to be locked/unlocked */
++ int nByte /* Number of bytes to lock or unlock */
++){
++ int rc = 0; /* Result code form Lock/UnlockFileEx() */
+
+- if( !azDirs[0] ) azDirs[0] = getenv("SQLITE_TMPDIR");
+- if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR");
+- if( !azDirs[2] ) azDirs[2] = getenv("TMP");
+- if( !azDirs[3] ) azDirs[3] = getenv("TEMP");
+- if( !azDirs[4] ) azDirs[4] = getenv("USERPROFILE");
+- for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); zDir=azDirs[i++]){
+- void *zConverted;
+- if( zDir==0 ) continue;
+- /* If the path starts with a drive letter followed by the colon
+- ** character, assume it is already a native Win32 path; otherwise,
+- ** it must be converted to a native Win32 path via the Cygwin API
+- ** prior to using it.
+- */
+- if( winIsDriveLetterAndColon(zDir) ){
+- zConverted = winConvertFromUtf8Filename(zDir);
+- if( !zConverted ){
+- sqlite3_free(zBuf);
+- OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
+- return SQLITE_IOERR_NOMEM;
+- }
+- if( winIsDir(zConverted) ){
+- sqlite3_snprintf(nMax, zBuf, "%s", zDir);
+- sqlite3_free(zConverted);
+- break;
+- }
+- sqlite3_free(zConverted);
+- }else{
+- zConverted = sqlite3MallocZero( nMax+1 );
+- if( !zConverted ){
+- sqlite3_free(zBuf);
+- OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
+- return SQLITE_IOERR_NOMEM;
+- }
+- if( cygwin_conv_path(
+- osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A, zDir,
+- zConverted, nMax+1)<0 ){
+- sqlite3_free(zConverted);
+- sqlite3_free(zBuf);
+- OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_CONVPATH\n"));
+- return winLogError(SQLITE_IOERR_CONVPATH, (DWORD)errno,
+- "winGetTempname2", zDir);
+- }
+- if( winIsDir(zConverted) ){
+- /* At this point, we know the candidate directory exists and should
+- ** be used. However, we may need to convert the string containing
+- ** its name into UTF-8 (i.e. if it is UTF-16 right now).
+- */
+- char *zUtf8 = winConvertToUtf8Filename(zConverted);
+- if( !zUtf8 ){
+- sqlite3_free(zConverted);
+- sqlite3_free(zBuf);
+- OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
+- return SQLITE_IOERR_NOMEM;
+- }
+- sqlite3_snprintf(nMax, zBuf, "%s", zUtf8);
+- sqlite3_free(zUtf8);
+- sqlite3_free(zConverted);
+- break;
+- }
+- sqlite3_free(zConverted);
+- }
+- }
+- }
+-#elif !SQLITE_OS_WINRT && !defined(__CYGWIN__)
+- else if( osIsNT() ){
+- char *zMulti;
+- LPWSTR zWidePath = sqlite3MallocZero( nMax*sizeof(WCHAR) );
+- if( !zWidePath ){
+- sqlite3_free(zBuf);
+- OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
+- return SQLITE_IOERR_NOMEM;
+- }
+- if( osGetTempPathW(nMax, zWidePath)==0 ){
+- sqlite3_free(zWidePath);
+- sqlite3_free(zBuf);
+- OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_GETTEMPPATH\n"));
+- return winLogError(SQLITE_IOERR_GETTEMPPATH, osGetLastError(),
+- "winGetTempname2", 0);
+- }
+- zMulti = winUnicodeToUtf8(zWidePath);
+- if( zMulti ){
+- sqlite3_snprintf(nMax, zBuf, "%s", zMulti);
+- sqlite3_free(zMulti);
+- sqlite3_free(zWidePath);
+- }else{
+- sqlite3_free(zWidePath);
+- sqlite3_free(zBuf);
+- OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
+- return SQLITE_IOERR_NOMEM;
+- }
+- }
+-#ifdef SQLITE_WIN32_HAS_ANSI
+- else{
+- char *zUtf8;
+- char *zMbcsPath = sqlite3MallocZero( nMax );
+- if( !zMbcsPath ){
+- sqlite3_free(zBuf);
+- OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
+- return SQLITE_IOERR_NOMEM;
+- }
+- if( osGetTempPathA(nMax, zMbcsPath)==0 ){
+- sqlite3_free(zBuf);
+- OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_GETTEMPPATH\n"));
+- return winLogError(SQLITE_IOERR_GETTEMPPATH, osGetLastError(),
+- "winGetTempname3", 0);
+- }
+- zUtf8 = sqlite3_win32_mbcs_to_utf8(zMbcsPath);
+- if( zUtf8 ){
+- sqlite3_snprintf(nMax, zBuf, "%s", zUtf8);
+- sqlite3_free(zUtf8);
+- }else{
+- sqlite3_free(zBuf);
+- OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
+- return SQLITE_IOERR_NOMEM;
+- }
+- }
+-#endif /* SQLITE_WIN32_HAS_ANSI */
+-#endif /* !SQLITE_OS_WINRT */
++ /* Access to the winShmNode object is serialized by the caller */
++ assert( sqlite3_mutex_held(pFile->mutex) || pFile->nRef==0 );
+
+- /*
+- ** Check to make sure the temporary directory ends with an appropriate
+- ** separator. If it does not and there is not enough space left to add
+- ** one, fail.
+- */
+- if( !winMakeEndInDirSep(nDir+1, zBuf) ){
+- sqlite3_free(zBuf);
+- OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n"));
+- return winLogError(SQLITE_ERROR, 0, "winGetTempname4", 0);
+- }
++ OSTRACE(("SHM-LOCK file=%p, lock=%d, offset=%d, size=%d\n",
++ pFile->hFile.h, lockType, ofst, nByte));
+
+- /*
+- ** Check that the output buffer is large enough for the temporary file
+- ** name in the following format:
+- **
+- ** "<temporary_directory>/etilqs_XXXXXXXXXXXXXXX\0\0"
+- **
+- ** If not, return SQLITE_ERROR. The number 17 is used here in order to
+- ** account for the space used by the 15 character random suffix and the
+- ** two trailing NUL characters. The final directory separator character
+- ** has already added if it was not already present.
+- */
+- nLen = sqlite3Strlen30(zBuf);
+- if( (nLen + nPre + 17) > nBuf ){
+- sqlite3_free(zBuf);
+- OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n"));
+- return winLogError(SQLITE_ERROR, 0, "winGetTempname5", 0);
++ /* Release/Acquire the system-level lock */
++ if( lockType==_SHM_UNLCK ){
++ rc = winUnlockFile(&pFile->hFile.h, ofst, 0, nByte, 0);
++ }else{
++ /* Initialize the locking parameters */
++ DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY;
++ if( lockType == _SHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
++ rc = winLockFile(&pFile->hFile.h, dwFlags, ofst, 0, nByte, 0);
+ }
+
+- sqlite3_snprintf(nBuf-16-nLen, zBuf+nLen, SQLITE_TEMP_FILE_PREFIX);
+-
+- j = sqlite3Strlen30(zBuf);
+- sqlite3_randomness(15, &zBuf[j]);
+- for(i=0; i<15; i++, j++){
+- zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
++ if( rc!= 0 ){
++ rc = SQLITE_OK;
++ }else{
++ pFile->lastErrno = osGetLastError();
++ rc = SQLITE_BUSY;
+ }
+- zBuf[j] = 0;
+- zBuf[j+1] = 0;
+- *pzBuf = zBuf;
+
+- OSTRACE(("TEMP-FILENAME name=%s, rc=SQLITE_OK\n", zBuf));
+- return SQLITE_OK;
++ OSTRACE(("SHM-LOCK file=%p, func=%s, errno=%lu, rc=%s\n",
++ pFile->hFile.h, (lockType == _SHM_UNLCK) ? "winUnlockFile" :
++ "winLockFile", pFile->lastErrno, sqlite3ErrName(rc)));
++
++ return rc;
+ }
+
++/* Forward references to VFS methods */
++static int winOpen(sqlite3_vfs*,const char*,sqlite3_file*,int,int*);
++static int winDelete(sqlite3_vfs *,const char*,int);
++
+ /*
+-** Return TRUE if the named file is really a directory. Return false if
+-** it is something other than a directory, or if there is any kind of memory
+-** allocation failure.
++** Purge the winShmNodeList list of all entries with winShmNode.nRef==0.
++**
++** This is not a VFS shared-memory method; it is a utility function called
++** by VFS shared-memory methods.
+ */
+-static int winIsDir(const void *zConverted){
+- DWORD attr;
+- int rc = 0;
+- DWORD lastErrno;
+-
+- if( osIsNT() ){
+- int cnt = 0;
+- WIN32_FILE_ATTRIBUTE_DATA sAttrData;
+- memset(&sAttrData, 0, sizeof(sAttrData));
+- while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted,
+- GetFileExInfoStandard,
+- &sAttrData)) && winRetryIoerr(&cnt, &lastErrno) ){}
+- if( !rc ){
+- return 0; /* Invalid name? */
++static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
++ winShmNode **pp;
++ winShmNode *p;
++ assert( winShmMutexHeld() );
++ OSTRACE(("SHM-PURGE pid=%lu, deleteFlag=%d\n",
++ osGetCurrentProcessId(), deleteFlag));
++ pp = &winShmNodeList;
++ while( (p = *pp)!=0 ){
++ if( p->nRef==0 ){
++ int i;
++ if( p->mutex ){ sqlite3_mutex_free(p->mutex); }
++ for(i=0; i<p->nRegion; i++){
++ BOOL bRc = osUnmapViewOfFile(p->aRegion[i].pMap);
++ OSTRACE(("SHM-PURGE-UNMAP pid=%lu, region=%d, rc=%s\n",
++ osGetCurrentProcessId(), i, bRc ? "ok" : "failed"));
++ UNUSED_VARIABLE_VALUE(bRc);
++ bRc = osCloseHandle(p->aRegion[i].hMap);
++ OSTRACE(("SHM-PURGE-CLOSE pid=%lu, region=%d, rc=%s\n",
++ osGetCurrentProcessId(), i, bRc ? "ok" : "failed"));
++ UNUSED_VARIABLE_VALUE(bRc);
++ }
++ if( p->hFile.h!=NULL && p->hFile.h!=INVALID_HANDLE_VALUE ){
++ SimulateIOErrorBenign(1);
++ winClose((sqlite3_file *)&p->hFile);
++ SimulateIOErrorBenign(0);
++ }
++ if( deleteFlag ){
++ SimulateIOErrorBenign(1);
++ sqlite3BeginBenignMalloc();
++ winDelete(pVfs, p->zFilename, 0);
++ sqlite3EndBenignMalloc();
++ SimulateIOErrorBenign(0);
++ }
++ *pp = p->pNext;
++ sqlite3_free(p->aRegion);
++ sqlite3_free(p);
++ }else{
++ pp = &p->pNext;
+ }
+- attr = sAttrData.dwFileAttributes;
+-#if SQLITE_OS_WINCE==0
+- }else{
+- attr = osGetFileAttributesA((char*)zConverted);
+-#endif
+ }
+- return (attr!=INVALID_FILE_ATTRIBUTES) && (attr&FILE_ATTRIBUTE_DIRECTORY);
+ }
+
+ /*
+-** Open a file.
++** Open the shared-memory area associated with database file pDbFd.
++**
++** When opening a new shared-memory file, if no other instances of that
++** file are currently open, in this process or in other processes, then
++** the file must be truncated to zero length or have its header cleared.
+ */
+-static int winOpen(
+- sqlite3_vfs *pVfs, /* Used to get maximum path name length */
+- const char *zName, /* Name of the file (UTF-8) */
+- sqlite3_file *id, /* Write the SQLite file handle here */
+- int flags, /* Open mode flags */
+- int *pOutFlags /* Status return flags */
+-){
+- HANDLE h;
+- DWORD lastErrno = 0;
+- DWORD dwDesiredAccess;
+- DWORD dwShareMode;
+- DWORD dwCreationDisposition;
+- DWORD dwFlagsAndAttributes = 0;
+-#if SQLITE_OS_WINCE
+- int isTemp = 0;
+-#endif
+- winFile *pFile = (winFile*)id;
+- void *zConverted; /* Filename in OS encoding */
+- const char *zUtf8Name = zName; /* Filename in UTF-8 encoding */
+- int cnt = 0;
+-
+- /* If argument zPath is a NULL pointer, this function is required to open
+- ** a temporary file. Use this buffer to store the file name in.
+- */
+- char *zTmpname = 0; /* For temporary filename, if necessary. */
+-
+- int rc = SQLITE_OK; /* Function Return Code */
+-#if !defined(NDEBUG) || SQLITE_OS_WINCE
+- int eType = flags&0xFFFFFF00; /* Type of file to open */
+-#endif
+-
+- int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE);
+- int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE);
+- int isCreate = (flags & SQLITE_OPEN_CREATE);
+- int isReadonly = (flags & SQLITE_OPEN_READONLY);
+- int isReadWrite = (flags & SQLITE_OPEN_READWRITE);
+-
+-#ifndef NDEBUG
+- int isOpenJournal = (isCreate && (
+- eType==SQLITE_OPEN_MASTER_JOURNAL
+- || eType==SQLITE_OPEN_MAIN_JOURNAL
+- || eType==SQLITE_OPEN_WAL
+- ));
+-#endif
++static int winOpenSharedMemory(winFile *pDbFd){
++ struct winShm *p; /* The connection to be opened */
++ struct winShmNode *pShmNode = 0; /* The underlying mmapped file */
++ int rc; /* Result code */
++ struct winShmNode *pNew; /* Newly allocated winShmNode */
++ int nName; /* Size of zName in bytes */
+
+- OSTRACE(("OPEN name=%s, pFile=%p, flags=%x, pOutFlags=%p\n",
+- zUtf8Name, id, flags, pOutFlags));
++ assert( pDbFd->pShm==0 ); /* Not previously opened */
+
+- /* Check the following statements are true:
+- **
+- ** (a) Exactly one of the READWRITE and READONLY flags must be set, and
+- ** (b) if CREATE is set, then READWRITE must also be set, and
+- ** (c) if EXCLUSIVE is set, then CREATE must also be set.
+- ** (d) if DELETEONCLOSE is set, then CREATE must also be set.
++ /* Allocate space for the new sqlite3_shm object. Also speculatively
++ ** allocate space for a new winShmNode and filename.
+ */
+- assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly));
+- assert(isCreate==0 || isReadWrite);
+- assert(isExclusive==0 || isCreate);
+- assert(isDelete==0 || isCreate);
++ p = sqlite3MallocZero( sizeof(*p) );
++ if( p==0 ) return SQLITE_IOERR_NOMEM;
++ nName = sqlite3Strlen30(pDbFd->zPath);
++ pNew = sqlite3MallocZero( sizeof(*pShmNode) + nName + 17 );
++ if( pNew==0 ){
++ sqlite3_free(p);
++ return SQLITE_IOERR_NOMEM;
++ }
++ pNew->zFilename = (char*)&pNew[1];
++ sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath);
++ sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename);
+
+- /* The main DB, main journal, WAL file and master journal are never
+- ** automatically deleted. Nor are they ever temporary files. */
+- assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB );
+- assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL );
+- assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL );
+- assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL );
++ /* Look to see if there is an existing winShmNode that can be used.
++ ** If no matching winShmNode currently exists, create a new one.
++ */
++ winShmEnterMutex();
++ for(pShmNode = winShmNodeList; pShmNode; pShmNode=pShmNode->pNext){
++ /* TBD need to come up with better match here. Perhaps
++ ** use FILE_ID_BOTH_DIR_INFO Structure.
++ */
++ if( sqlite3StrICmp(pShmNode->zFilename, pNew->zFilename)==0 ) break;
++ }
++ if( pShmNode ){
++ sqlite3_free(pNew);
++ }else{
++ pShmNode = pNew;
++ pNew = 0;
++ ((winFile*)(&pShmNode->hFile))->h = INVALID_HANDLE_VALUE;
++ pShmNode->pNext = winShmNodeList;
++ winShmNodeList = pShmNode;
+
+- /* Assert that the upper layer has set one of the "file-type" flags. */
+- assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB
+- || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
+- || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL
+- || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
+- );
++ pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
++ if( pShmNode->mutex==0 ){
++ rc = SQLITE_IOERR_NOMEM;
++ goto shm_open_err;
++ }
+
+- assert( pFile!=0 );
+- memset(pFile, 0, sizeof(winFile));
+- pFile->h = INVALID_HANDLE_VALUE;
++ rc = winOpen(pDbFd->pVfs,
++ pShmNode->zFilename, /* Name of the file (UTF-8) */
++ (sqlite3_file*)&pShmNode->hFile, /* File handle here */
++ SQLITE_OPEN_WAL | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
++ 0);
++ if( SQLITE_OK!=rc ){
++ goto shm_open_err;
++ }
+
+-#if SQLITE_OS_WINRT
+- if( !zUtf8Name && !sqlite3_temp_directory ){
+- sqlite3_log(SQLITE_ERROR,
+- "sqlite3_temp_directory variable should be set for WinRT");
++ /* Check to see if another process is holding the dead-man switch.
++ ** If not, truncate the file to zero length.
++ */
++ if( winShmSystemLock(pShmNode, _SHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){
++ rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0);
++ if( rc!=SQLITE_OK ){
++ rc = winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(),
++ "winOpenShm", pDbFd->zPath);
++ }
++ }
++ if( rc==SQLITE_OK ){
++ winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1);
++ rc = winShmSystemLock(pShmNode, _SHM_RDLCK, WIN_SHM_DMS, 1);
++ }
++ if( rc ) goto shm_open_err;
+ }
++
++ /* Make the new connection a child of the winShmNode */
++ p->pShmNode = pShmNode;
++#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
++ p->id = pShmNode->nextShmId++;
+ #endif
++ pShmNode->nRef++;
++ pDbFd->pShm = p;
++ winShmLeaveMutex();
+
+- /* If the second argument to this function is NULL, generate a
+- ** temporary file name to use
++ /* The reference count on pShmNode has already been incremented under
++ ** the cover of the winShmEnterMutex() mutex and the pointer from the
++ ** new (struct winShm) object to the pShmNode has been set. All that is
++ ** left to do is to link the new object into the linked list starting
++ ** at pShmNode->pFirst. This must be done while holding the pShmNode->mutex
++ ** mutex.
+ */
+- if( !zUtf8Name ){
+- assert( isDelete && !isOpenJournal );
+- rc = winGetTempname(pVfs, &zTmpname);
+- if( rc!=SQLITE_OK ){
+- OSTRACE(("OPEN name=%s, rc=%s", zUtf8Name, sqlite3ErrName(rc)));
+- return rc;
+- }
+- zUtf8Name = zTmpname;
+- }
++ sqlite3_mutex_enter(pShmNode->mutex);
++ p->pNext = pShmNode->pFirst;
++ pShmNode->pFirst = p;
++ sqlite3_mutex_leave(pShmNode->mutex);
++ return SQLITE_OK;
+
+- /* Database filenames are double-zero terminated if they are not
+- ** URIs with parameters. Hence, they can always be passed into
+- ** sqlite3_uri_parameter().
+- */
+- assert( (eType!=SQLITE_OPEN_MAIN_DB) || (flags & SQLITE_OPEN_URI) ||
+- zUtf8Name[sqlite3Strlen30(zUtf8Name)+1]==0 );
++ /* Jump here on any error */
++shm_open_err:
++ winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1);
++ winShmPurge(pDbFd->pVfs, 0); /* This call frees pShmNode if required */
++ sqlite3_free(p);
++ sqlite3_free(pNew);
++ winShmLeaveMutex();
++ return rc;
++}
+
+- /* Convert the filename to the system encoding. */
+- zConverted = winConvertFromUtf8Filename(zUtf8Name);
+- if( zConverted==0 ){
+- sqlite3_free(zTmpname);
+- OSTRACE(("OPEN name=%s, rc=SQLITE_IOERR_NOMEM", zUtf8Name));
+- return SQLITE_IOERR_NOMEM;
+- }
++/*
++** Close a connection to shared-memory. Delete the underlying
++** storage if deleteFlag is true.
++*/
++static int winShmUnmap(
++ sqlite3_file *fd, /* Database holding shared memory */
++ int deleteFlag /* Delete after closing if true */
++){
++ winFile *pDbFd; /* Database holding shared-memory */
++ winShm *p; /* The connection to be closed */
++ winShmNode *pShmNode; /* The underlying shared-memory file */
++ winShm **pp; /* For looping over sibling connections */
+
+- if( winIsDir(zConverted) ){
+- sqlite3_free(zConverted);
+- sqlite3_free(zTmpname);
+- OSTRACE(("OPEN name=%s, rc=SQLITE_CANTOPEN_ISDIR", zUtf8Name));
+- return SQLITE_CANTOPEN_ISDIR;
+- }
++ pDbFd = (winFile*)fd;
++ p = pDbFd->pShm;
++ if( p==0 ) return SQLITE_OK;
++ pShmNode = p->pShmNode;
+
+- if( isReadWrite ){
+- dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
+- }else{
+- dwDesiredAccess = GENERIC_READ;
+- }
++ /* Remove connection p from the set of connections associated
++ ** with pShmNode */
++ sqlite3_mutex_enter(pShmNode->mutex);
++ for(pp=&pShmNode->pFirst; (*pp)!=p; pp = &(*pp)->pNext){}
++ *pp = p->pNext;
+
+- /* SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is
+- ** created. SQLite doesn't use it to indicate "exclusive access"
+- ** as it is usually understood.
+- */
+- if( isExclusive ){
+- /* Creates a new file, only if it does not already exist. */
+- /* If the file exists, it fails. */
+- dwCreationDisposition = CREATE_NEW;
+- }else if( isCreate ){
+- /* Open existing file, or create if it doesn't exist */
+- dwCreationDisposition = OPEN_ALWAYS;
+- }else{
+- /* Opens a file, only if it exists. */
+- dwCreationDisposition = OPEN_EXISTING;
++ /* Free the connection p */
++ sqlite3_free(p);
++ pDbFd->pShm = 0;
++ sqlite3_mutex_leave(pShmNode->mutex);
++
++ /* If pShmNode->nRef has reached 0, then close the underlying
++ ** shared-memory file, too */
++ winShmEnterMutex();
++ assert( pShmNode->nRef>0 );
++ pShmNode->nRef--;
++ if( pShmNode->nRef==0 ){
++ winShmPurge(pDbFd->pVfs, deleteFlag);
+ }
++ winShmLeaveMutex();
+
+- dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
++ return SQLITE_OK;
++}
+
+- if( isDelete ){
+-#if SQLITE_OS_WINCE
+- dwFlagsAndAttributes = FILE_ATTRIBUTE_HIDDEN;
+- isTemp = 1;
+-#else
+- dwFlagsAndAttributes = FILE_ATTRIBUTE_TEMPORARY
+- | FILE_ATTRIBUTE_HIDDEN
+- | FILE_FLAG_DELETE_ON_CLOSE;
+-#endif
+- }else{
+- dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
+- }
+- /* Reports from the internet are that performance is always
+- ** better if FILE_FLAG_RANDOM_ACCESS is used. Ticket #2699. */
+-#if SQLITE_OS_WINCE
+- dwFlagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS;
+-#endif
++/*
++** Change the lock state for a shared-memory segment.
++*/
++static int winShmLock(
++ sqlite3_file *fd, /* Database file holding the shared memory */
++ int ofst, /* First lock to acquire or release */
++ int n, /* Number of locks to acquire or release */
++ int flags /* What to do with the lock */
++){
++ winFile *pDbFd = (winFile*)fd; /* Connection holding shared memory */
++ winShm *p = pDbFd->pShm; /* The shared memory being locked */
++ winShm *pX; /* For looping over all siblings */
++ winShmNode *pShmNode = p->pShmNode;
++ int rc = SQLITE_OK; /* Result code */
++ u16 mask; /* Mask of locks to take or release */
+
+- if( osIsNT() ){
+-#if SQLITE_OS_WINRT
+- CREATEFILE2_EXTENDED_PARAMETERS extendedParameters;
+- extendedParameters.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
+- extendedParameters.dwFileAttributes =
+- dwFlagsAndAttributes & FILE_ATTRIBUTE_MASK;
+- extendedParameters.dwFileFlags = dwFlagsAndAttributes & FILE_FLAG_MASK;
+- extendedParameters.dwSecurityQosFlags = SECURITY_ANONYMOUS;
+- extendedParameters.lpSecurityAttributes = NULL;
+- extendedParameters.hTemplateFile = NULL;
+- while( (h = osCreateFile2((LPCWSTR)zConverted,
+- dwDesiredAccess,
+- dwShareMode,
+- dwCreationDisposition,
+- &extendedParameters))==INVALID_HANDLE_VALUE &&
+- winRetryIoerr(&cnt, &lastErrno) ){
+- /* Noop */
+- }
+-#else
+- while( (h = osCreateFileW((LPCWSTR)zConverted,
+- dwDesiredAccess,
+- dwShareMode, NULL,
+- dwCreationDisposition,
+- dwFlagsAndAttributes,
+- NULL))==INVALID_HANDLE_VALUE &&
+- winRetryIoerr(&cnt, &lastErrno) ){
+- /* Noop */
+- }
+-#endif
+- }
+-#ifdef SQLITE_WIN32_HAS_ANSI
+- else{
+- while( (h = osCreateFileA((LPCSTR)zConverted,
+- dwDesiredAccess,
+- dwShareMode, NULL,
+- dwCreationDisposition,
+- dwFlagsAndAttributes,
+- NULL))==INVALID_HANDLE_VALUE &&
+- winRetryIoerr(&cnt, &lastErrno) ){
+- /* Noop */
+- }
+- }
+-#endif
+- winLogIoerr(cnt, __LINE__);
++ assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK );
++ assert( n>=1 );
++ assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED)
++ || flags==(SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE)
++ || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED)
++ || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
++ assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
+
+- OSTRACE(("OPEN file=%p, name=%s, access=%lx, rc=%s\n", h, zUtf8Name,
+- dwDesiredAccess, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok"));
++ mask = (u16)((1U<<(ofst+n)) - (1U<<ofst));
++ assert( n>1 || mask==(1<<ofst) );
++ sqlite3_mutex_enter(pShmNode->mutex);
++ if( flags & SQLITE_SHM_UNLOCK ){
++ u16 allMask = 0; /* Mask of locks held by siblings */
+
+- if( h==INVALID_HANDLE_VALUE ){
+- pFile->lastErrno = lastErrno;
+- winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name);
+- sqlite3_free(zConverted);
+- sqlite3_free(zTmpname);
+- if( isReadWrite && !isExclusive ){
+- return winOpen(pVfs, zName, id,
+- ((flags|SQLITE_OPEN_READONLY) &
+- ~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)),
+- pOutFlags);
+- }else{
+- return SQLITE_CANTOPEN_BKPT;
++ /* See if any siblings hold this same lock */
++ for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
++ if( pX==p ) continue;
++ assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 );
++ allMask |= pX->sharedMask;
+ }
+- }
+
+- if( pOutFlags ){
+- if( isReadWrite ){
+- *pOutFlags = SQLITE_OPEN_READWRITE;
++ /* Unlock the system-level locks */
++ if( (mask & allMask)==0 ){
++ rc = winShmSystemLock(pShmNode, _SHM_UNLCK, ofst+WIN_SHM_BASE, n);
+ }else{
+- *pOutFlags = SQLITE_OPEN_READONLY;
++ rc = SQLITE_OK;
+ }
+- }
+
+- OSTRACE(("OPEN file=%p, name=%s, access=%lx, pOutFlags=%p, *pOutFlags=%d, "
+- "rc=%s\n", h, zUtf8Name, dwDesiredAccess, pOutFlags, pOutFlags ?
+- *pOutFlags : 0, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok"));
++ /* Undo the local locks */
++ if( rc==SQLITE_OK ){
++ p->exclMask &= ~mask;
++ p->sharedMask &= ~mask;
++ }
++ }else if( flags & SQLITE_SHM_SHARED ){
++ u16 allShared = 0; /* Union of locks held by connections other than "p" */
+
+-#if SQLITE_OS_WINCE
+- if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB
+- && (rc = winceCreateLock(zName, pFile))!=SQLITE_OK
+- ){
+- osCloseHandle(h);
+- sqlite3_free(zConverted);
+- sqlite3_free(zTmpname);
+- OSTRACE(("OPEN-CE-LOCK name=%s, rc=%s\n", zName, sqlite3ErrName(rc)));
+- return rc;
+- }
+- if( isTemp ){
+- pFile->zDeleteOnClose = zConverted;
+- }else
+-#endif
+- {
+- sqlite3_free(zConverted);
+- }
++ /* Find out which shared locks are already held by sibling connections.
++ ** If any sibling already holds an exclusive lock, go ahead and return
++ ** SQLITE_BUSY.
++ */
++ for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
++ if( (pX->exclMask & mask)!=0 ){
++ rc = SQLITE_BUSY;
++ break;
++ }
++ allShared |= pX->sharedMask;
++ }
++
++ /* Get shared locks at the system level, if necessary */
++ if( rc==SQLITE_OK ){
++ if( (allShared & mask)==0 ){
++ rc = winShmSystemLock(pShmNode, _SHM_RDLCK, ofst+WIN_SHM_BASE, n);
++ }else{
++ rc = SQLITE_OK;
++ }
++ }
+
+- sqlite3_free(zTmpname);
+- pFile->pMethod = &winIoMethod;
+- pFile->pVfs = pVfs;
+- pFile->h = h;
+- if( isReadonly ){
+- pFile->ctrlFlags |= WINFILE_RDONLY;
+- }
+- if( sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE) ){
+- pFile->ctrlFlags |= WINFILE_PSOW;
+- }
+- pFile->lastErrno = NO_ERROR;
+- pFile->zPath = zName;
+-#if SQLITE_MAX_MMAP_SIZE>0
+- pFile->hMap = NULL;
+- pFile->pMapRegion = 0;
+- pFile->mmapSize = 0;
+- pFile->mmapSizeActual = 0;
+- pFile->mmapSizeMax = sqlite3GlobalConfig.szMmap;
+-#endif
++ /* Get the local shared locks */
++ if( rc==SQLITE_OK ){
++ p->sharedMask |= mask;
++ }
++ }else{
++ /* Make sure no sibling connections hold locks that will block this
++ ** lock. If any do, return SQLITE_BUSY right away.
++ */
++ for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
++ if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){
++ rc = SQLITE_BUSY;
++ break;
++ }
++ }
+
+- OpenCounter(+1);
++ /* Get the exclusive locks at the system level. Then if successful
++ ** also mark the local connection as being locked.
++ */
++ if( rc==SQLITE_OK ){
++ rc = winShmSystemLock(pShmNode, _SHM_WRLCK, ofst+WIN_SHM_BASE, n);
++ if( rc==SQLITE_OK ){
++ assert( (p->sharedMask & mask)==0 );
++ p->exclMask |= mask;
++ }
++ }
++ }
++ sqlite3_mutex_leave(pShmNode->mutex);
++ OSTRACE(("SHM-LOCK pid=%lu, id=%d, sharedMask=%03x, exclMask=%03x, rc=%s\n",
++ osGetCurrentProcessId(), p->id, p->sharedMask, p->exclMask,
++ sqlite3ErrName(rc)));
+ return rc;
+ }
+
+ /*
+-** Delete the named file.
++** Implement a memory barrier or memory fence on shared memory.
+ **
+-** Note that Windows does not allow a file to be deleted if some other
+-** process has it open. Sometimes a virus scanner or indexing program
+-** will open a journal file shortly after it is created in order to do
+-** whatever it does. While this other process is holding the
+-** file open, we will be unable to delete it. To work around this
+-** problem, we delay 100 milliseconds and try to delete again. Up
+-** to MX_DELETION_ATTEMPTs deletion attempts are run before giving
+-** up and returning an error.
++** All loads and stores begun before the barrier must complete before
++** any load or store begun after the barrier.
+ */
+-static int winDelete(
+- sqlite3_vfs *pVfs, /* Not used on win32 */
+- const char *zFilename, /* Name of file to delete */
+- int syncDir /* Not used on win32 */
++static void winShmBarrier(
++ sqlite3_file *fd /* Database holding the shared memory */
+ ){
+- int cnt = 0;
+- int rc;
+- DWORD attr;
+- DWORD lastErrno = 0;
+- void *zConverted;
+- UNUSED_PARAMETER(pVfs);
+- UNUSED_PARAMETER(syncDir);
++ UNUSED_PARAMETER(fd);
++ /* MemoryBarrier(); // does not work -- do not know why not */
++ winShmEnterMutex();
++ winShmLeaveMutex();
++}
+
+- SimulateIOError(return SQLITE_IOERR_DELETE);
+- OSTRACE(("DELETE name=%s, syncDir=%d\n", zFilename, syncDir));
++/*
++** This function is called to obtain a pointer to region iRegion of the
++** shared-memory associated with the database file fd. Shared-memory regions
++** are numbered starting from zero. Each shared-memory region is szRegion
++** bytes in size.
++**
++** If an error occurs, an error code is returned and *pp is set to NULL.
++**
++** Otherwise, if the isWrite parameter is 0 and the requested shared-memory
++** region has not been allocated (by any client, including one running in a
++** separate process), then *pp is set to NULL and SQLITE_OK returned. If
++** isWrite is non-zero and the requested shared-memory region has not yet
++** been allocated, it is allocated by this function.
++**
++** If the shared-memory region has already been allocated or is allocated by
++** this call as described above, then it is mapped into this processes
++** address space (if it is not already), *pp is set to point to the mapped
++** memory and SQLITE_OK returned.
++*/
++static int winShmMap(
++ sqlite3_file *fd, /* Handle open on database file */
++ int iRegion, /* Region to retrieve */
++ int szRegion, /* Size of regions */
++ int isWrite, /* True to extend file if necessary */
++ void volatile **pp /* OUT: Mapped memory */
++){
++ winFile *pDbFd = (winFile*)fd;
++ winShm *pShm = pDbFd->pShm;
++ winShmNode *pShmNode;
++ int rc = SQLITE_OK;
+
+- zConverted = winConvertFromUtf8Filename(zFilename);
+- if( zConverted==0 ){
+- OSTRACE(("DELETE name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename));
+- return SQLITE_IOERR_NOMEM;
++ if( !pShm ){
++ rc = winOpenSharedMemory(pDbFd);
++ if( rc!=SQLITE_OK ) return rc;
++ pShm = pDbFd->pShm;
+ }
+- if( osIsNT() ){
+- do {
+-#if SQLITE_OS_WINRT
+- WIN32_FILE_ATTRIBUTE_DATA sAttrData;
+- memset(&sAttrData, 0, sizeof(sAttrData));
+- if ( osGetFileAttributesExW(zConverted, GetFileExInfoStandard,
+- &sAttrData) ){
+- attr = sAttrData.dwFileAttributes;
+- }else{
+- lastErrno = osGetLastError();
+- if( lastErrno==ERROR_FILE_NOT_FOUND
+- || lastErrno==ERROR_PATH_NOT_FOUND ){
+- rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */
+- }else{
+- rc = SQLITE_ERROR;
+- }
+- break;
++ pShmNode = pShm->pShmNode;
++
++ sqlite3_mutex_enter(pShmNode->mutex);
++ assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
++
++ if( pShmNode->nRegion<=iRegion ){
++ struct ShmRegion *apNew; /* New aRegion[] array */
++ int nByte = (iRegion+1)*szRegion; /* Minimum required file size */
++ sqlite3_int64 sz; /* Current size of wal-index file */
++
++ pShmNode->szRegion = szRegion;
++
++ /* The requested region is not mapped into this processes address space.
++ ** Check to see if it has been allocated (i.e. if the wal-index file is
++ ** large enough to contain the requested region).
++ */
++ rc = winFileSize((sqlite3_file *)&pShmNode->hFile, &sz);
++ if( rc!=SQLITE_OK ){
++ rc = winLogError(SQLITE_IOERR_SHMSIZE, osGetLastError(),
++ "winShmMap1", pDbFd->zPath);
++ goto shmpage_out;
++ }
++
++ if( sz<nByte ){
++ /* The requested memory region does not exist. If isWrite is set to
++ ** zero, exit early. *pp will be set to NULL and SQLITE_OK returned.
++ **
++ ** Alternatively, if isWrite is non-zero, use ftruncate() to allocate
++ ** the requested memory region.
++ */
++ if( !isWrite ) goto shmpage_out;
++ rc = winTruncate((sqlite3_file *)&pShmNode->hFile, nByte);
++ if( rc!=SQLITE_OK ){
++ rc = winLogError(SQLITE_IOERR_SHMSIZE, osGetLastError(),
++ "winShmMap2", pDbFd->zPath);
++ goto shmpage_out;
+ }
++ }
++
++ /* Map the requested memory region into this processes address space. */
++ apNew = (struct ShmRegion *)sqlite3_realloc64(
++ pShmNode->aRegion, (iRegion+1)*sizeof(apNew[0])
++ );
++ if( !apNew ){
++ rc = SQLITE_IOERR_NOMEM;
++ goto shmpage_out;
++ }
++ pShmNode->aRegion = apNew;
++
++ while( pShmNode->nRegion<=iRegion ){
++ HANDLE hMap = NULL; /* file-mapping handle */
++ void *pMap = 0; /* Mapped memory region */
++
++#if SQLITE_OS_WINRT
++ hMap = osCreateFileMappingFromApp(pShmNode->hFile.h,
++ NULL, PAGE_READWRITE, nByte, NULL
++ );
++#elif defined(SQLITE_WIN32_HAS_WIDE)
++ hMap = osCreateFileMappingW(pShmNode->hFile.h,
++ NULL, PAGE_READWRITE, 0, nByte, NULL
++ );
++#elif defined(SQLITE_WIN32_HAS_ANSI)
++ hMap = osCreateFileMappingA(pShmNode->hFile.h,
++ NULL, PAGE_READWRITE, 0, nByte, NULL
++ );
++#endif
++ OSTRACE(("SHM-MAP-CREATE pid=%lu, region=%d, size=%d, rc=%s\n",
++ osGetCurrentProcessId(), pShmNode->nRegion, nByte,
++ hMap ? "ok" : "failed"));
++ if( hMap ){
++ int iOffset = pShmNode->nRegion*szRegion;
++ int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity;
++#if SQLITE_OS_WINRT
++ pMap = osMapViewOfFileFromApp(hMap, FILE_MAP_WRITE | FILE_MAP_READ,
++ iOffset - iOffsetShift, szRegion + iOffsetShift
++ );
+ #else
+- attr = osGetFileAttributesW(zConverted);
++ pMap = osMapViewOfFile(hMap, FILE_MAP_WRITE | FILE_MAP_READ,
++ 0, iOffset - iOffsetShift, szRegion + iOffsetShift
++ );
+ #endif
+- if ( attr==INVALID_FILE_ATTRIBUTES ){
+- lastErrno = osGetLastError();
+- if( lastErrno==ERROR_FILE_NOT_FOUND
+- || lastErrno==ERROR_PATH_NOT_FOUND ){
+- rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */
+- }else{
+- rc = SQLITE_ERROR;
+- }
+- break;
+- }
+- if ( attr&FILE_ATTRIBUTE_DIRECTORY ){
+- rc = SQLITE_ERROR; /* Files only. */
+- break;
+- }
+- if ( osDeleteFileW(zConverted) ){
+- rc = SQLITE_OK; /* Deleted OK. */
+- break;
+- }
+- if ( !winRetryIoerr(&cnt, &lastErrno) ){
+- rc = SQLITE_ERROR; /* No more retries. */
+- break;
+- }
+- } while(1);
+- }
+-#ifdef SQLITE_WIN32_HAS_ANSI
+- else{
+- do {
+- attr = osGetFileAttributesA(zConverted);
+- if ( attr==INVALID_FILE_ATTRIBUTES ){
+- lastErrno = osGetLastError();
+- if( lastErrno==ERROR_FILE_NOT_FOUND
+- || lastErrno==ERROR_PATH_NOT_FOUND ){
+- rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */
+- }else{
+- rc = SQLITE_ERROR;
+- }
+- break;
+- }
+- if ( attr&FILE_ATTRIBUTE_DIRECTORY ){
+- rc = SQLITE_ERROR; /* Files only. */
+- break;
+- }
+- if ( osDeleteFileA(zConverted) ){
+- rc = SQLITE_OK; /* Deleted OK. */
+- break;
++ OSTRACE(("SHM-MAP-MAP pid=%lu, region=%d, offset=%d, size=%d, rc=%s\n",
++ osGetCurrentProcessId(), pShmNode->nRegion, iOffset,
++ szRegion, pMap ? "ok" : "failed"));
+ }
+- if ( !winRetryIoerr(&cnt, &lastErrno) ){
+- rc = SQLITE_ERROR; /* No more retries. */
+- break;
++ if( !pMap ){
++ pShmNode->lastErrno = osGetLastError();
++ rc = winLogError(SQLITE_IOERR_SHMMAP, pShmNode->lastErrno,
++ "winShmMap3", pDbFd->zPath);
++ if( hMap ) osCloseHandle(hMap);
++ goto shmpage_out;
+ }
+- } while(1);
++
++ pShmNode->aRegion[pShmNode->nRegion].pMap = pMap;
++ pShmNode->aRegion[pShmNode->nRegion].hMap = hMap;
++ pShmNode->nRegion++;
++ }
+ }
+-#endif
+- if( rc && rc!=SQLITE_IOERR_DELETE_NOENT ){
+- rc = winLogError(SQLITE_IOERR_DELETE, lastErrno, "winDelete", zFilename);
++
++shmpage_out:
++ if( pShmNode->nRegion>iRegion ){
++ int iOffset = iRegion*szRegion;
++ int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity;
++ char *p = (char *)pShmNode->aRegion[iRegion].pMap;
++ *pp = (void *)&p[iOffsetShift];
+ }else{
+- winLogIoerr(cnt, __LINE__);
++ *pp = 0;
+ }
+- sqlite3_free(zConverted);
+- OSTRACE(("DELETE name=%s, rc=%s\n", zFilename, sqlite3ErrName(rc)));
++ sqlite3_mutex_leave(pShmNode->mutex);
+ return rc;
+ }
+
++#else
++# define winShmMap 0
++# define winShmLock 0
++# define winShmBarrier 0
++# define winShmUnmap 0
++#endif /* #ifndef SQLITE_OMIT_WAL */
++
+ /*
+-** Check the existence and status of a file.
++** Cleans up the mapped region of the specified file, if any.
+ */
+-static int winAccess(
+- sqlite3_vfs *pVfs, /* Not used on win32 */
+- const char *zFilename, /* Name of file to check */
+- int flags, /* Type of test to make on this file */
+- int *pResOut /* OUT: Result */
+-){
+- DWORD attr;
+- int rc = 0;
+- DWORD lastErrno = 0;
+- void *zConverted;
+- UNUSED_PARAMETER(pVfs);
+-
+- SimulateIOError( return SQLITE_IOERR_ACCESS; );
+- OSTRACE(("ACCESS name=%s, flags=%x, pResOut=%p\n",
+- zFilename, flags, pResOut));
+-
+- zConverted = winConvertFromUtf8Filename(zFilename);
+- if( zConverted==0 ){
+- OSTRACE(("ACCESS name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename));
+- return SQLITE_IOERR_NOMEM;
+- }
+- if( osIsNT() ){
+- int cnt = 0;
+- WIN32_FILE_ATTRIBUTE_DATA sAttrData;
+- memset(&sAttrData, 0, sizeof(sAttrData));
+- while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted,
+- GetFileExInfoStandard,
+- &sAttrData)) && winRetryIoerr(&cnt, &lastErrno) ){}
+- if( rc ){
+- /* For an SQLITE_ACCESS_EXISTS query, treat a zero-length file
+- ** as if it does not exist.
+- */
+- if( flags==SQLITE_ACCESS_EXISTS
+- && sAttrData.nFileSizeHigh==0
+- && sAttrData.nFileSizeLow==0 ){
+- attr = INVALID_FILE_ATTRIBUTES;
+- }else{
+- attr = sAttrData.dwFileAttributes;
+- }
+- }else{
+- winLogIoerr(cnt, __LINE__);
+- if( lastErrno!=ERROR_FILE_NOT_FOUND && lastErrno!=ERROR_PATH_NOT_FOUND ){
+- sqlite3_free(zConverted);
+- return winLogError(SQLITE_IOERR_ACCESS, lastErrno, "winAccess",
+- zFilename);
+- }else{
+- attr = INVALID_FILE_ATTRIBUTES;
+- }
++#if SQLITE_MAX_MMAP_SIZE>0
++static int winUnmapfile(winFile *pFile){
++ assert( pFile!=0 );
++ OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, hMap=%p, pMapRegion=%p, "
++ "mmapSize=%lld, mmapSizeActual=%lld, mmapSizeMax=%lld\n",
++ osGetCurrentProcessId(), pFile, pFile->hMap, pFile->pMapRegion,
++ pFile->mmapSize, pFile->mmapSizeActual, pFile->mmapSizeMax));
++ if( pFile->pMapRegion ){
++ if( !osUnmapViewOfFile(pFile->pMapRegion) ){
++ pFile->lastErrno = osGetLastError();
++ OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, pMapRegion=%p, "
++ "rc=SQLITE_IOERR_MMAP\n", osGetCurrentProcessId(), pFile,
++ pFile->pMapRegion));
++ return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno,
++ "winUnmapfile1", pFile->zPath);
+ }
++ pFile->pMapRegion = 0;
++ pFile->mmapSize = 0;
++ pFile->mmapSizeActual = 0;
+ }
+-#ifdef SQLITE_WIN32_HAS_ANSI
+- else{
+- attr = osGetFileAttributesA((char*)zConverted);
+- }
+-#endif
+- sqlite3_free(zConverted);
+- switch( flags ){
+- case SQLITE_ACCESS_READ:
+- case SQLITE_ACCESS_EXISTS:
+- rc = attr!=INVALID_FILE_ATTRIBUTES;
+- break;
+- case SQLITE_ACCESS_READWRITE:
+- rc = attr!=INVALID_FILE_ATTRIBUTES &&
+- (attr & FILE_ATTRIBUTE_READONLY)==0;
+- break;
+- default:
+- assert(!"Invalid flags argument");
++ if( pFile->hMap!=NULL ){
++ if( !osCloseHandle(pFile->hMap) ){
++ pFile->lastErrno = osGetLastError();
++ OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, hMap=%p, rc=SQLITE_IOERR_MMAP\n",
++ osGetCurrentProcessId(), pFile, pFile->hMap));
++ return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno,
++ "winUnmapfile2", pFile->zPath);
++ }
++ pFile->hMap = NULL;
+ }
+- *pResOut = rc;
+- OSTRACE(("ACCESS name=%s, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n",
+- zFilename, pResOut, *pResOut));
++ OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, rc=SQLITE_OK\n",
++ osGetCurrentProcessId(), pFile));
+ return SQLITE_OK;
+ }
+
+ /*
+-** Returns non-zero if the specified path name starts with a drive letter
+-** followed by a colon character.
++** Memory map or remap the file opened by file-descriptor pFd (if the file
++** is already mapped, the existing mapping is replaced by the new). Or, if
++** there already exists a mapping for this file, and there are still
++** outstanding xFetch() references to it, this function is a no-op.
++**
++** If parameter nByte is non-negative, then it is the requested size of
++** the mapping to create. Otherwise, if nByte is less than zero, then the
++** requested size is the size of the file on disk. The actual size of the
++** created mapping is either the requested size or the value configured
++** using SQLITE_FCNTL_MMAP_SIZE, whichever is smaller.
++**
++** SQLITE_OK is returned if no error occurs (even if the mapping is not
++** recreated as a result of outstanding references) or an SQLite error
++** code otherwise.
+ */
+-static BOOL winIsDriveLetterAndColon(
+- const char *zPathname
+-){
+- return ( sqlite3Isalpha(zPathname[0]) && zPathname[1]==':' );
+-}
++static int winMapfile(winFile *pFd, sqlite3_int64 nByte){
++ sqlite3_int64 nMap = nByte;
++ int rc;
+
+-/*
+-** Returns non-zero if the specified path name should be used verbatim. If
+-** non-zero is returned from this function, the calling function must simply
+-** use the provided path name verbatim -OR- resolve it into a full path name
+-** using the GetFullPathName Win32 API function (if available).
+-*/
+-static BOOL winIsVerbatimPathname(
+- const char *zPathname
+-){
+- /*
+- ** If the path name starts with a forward slash or a backslash, it is either
+- ** a legal UNC name, a volume relative path, or an absolute path name in the
+- ** "Unix" format on Windows. There is no easy way to differentiate between
+- ** the final two cases; therefore, we return the safer return value of TRUE
+- ** so that callers of this function will simply use it verbatim.
+- */
+- if ( winIsDirSep(zPathname[0]) ){
+- return TRUE;
++ assert( nMap>=0 || pFd->nFetchOut==0 );
++ OSTRACE(("MAP-FILE pid=%lu, pFile=%p, size=%lld\n",
++ osGetCurrentProcessId(), pFd, nByte));
++
++ if( pFd->nFetchOut>0 ) return SQLITE_OK;
++
++ if( nMap<0 ){
++ rc = winFileSize((sqlite3_file*)pFd, &nMap);
++ if( rc ){
++ OSTRACE(("MAP-FILE pid=%lu, pFile=%p, rc=SQLITE_IOERR_FSTAT\n",
++ osGetCurrentProcessId(), pFd));
++ return SQLITE_IOERR_FSTAT;
++ }
++ }
++ if( nMap>pFd->mmapSizeMax ){
++ nMap = pFd->mmapSizeMax;
+ }
++ nMap &= ~(sqlite3_int64)(winSysInfo.dwPageSize - 1);
+
+- /*
+- ** If the path name starts with a letter and a colon it is either a volume
+- ** relative path or an absolute path. Callers of this function must not
+- ** attempt to treat it as a relative path name (i.e. they should simply use
+- ** it verbatim).
+- */
+- if ( winIsDriveLetterAndColon(zPathname) ){
+- return TRUE;
++ if( nMap==0 && pFd->mmapSize>0 ){
++ winUnmapfile(pFd);
++ }
++ if( nMap!=pFd->mmapSize ){
++ void *pNew = 0;
++ DWORD protect = PAGE_READONLY;
++ DWORD flags = FILE_MAP_READ;
++
++ winUnmapfile(pFd);
++ if( (pFd->ctrlFlags & WINFILE_RDONLY)==0 ){
++ protect = PAGE_READWRITE;
++ flags |= FILE_MAP_WRITE;
++ }
++#if SQLITE_OS_WINRT
++ pFd->hMap = osCreateFileMappingFromApp(pFd->h, NULL, protect, nMap, NULL);
++#elif defined(SQLITE_WIN32_HAS_WIDE)
++ pFd->hMap = osCreateFileMappingW(pFd->h, NULL, protect,
++ (DWORD)((nMap>>32) & 0xffffffff),
++ (DWORD)(nMap & 0xffffffff), NULL);
++#elif defined(SQLITE_WIN32_HAS_ANSI)
++ pFd->hMap = osCreateFileMappingA(pFd->h, NULL, protect,
++ (DWORD)((nMap>>32) & 0xffffffff),
++ (DWORD)(nMap & 0xffffffff), NULL);
++#endif
++ if( pFd->hMap==NULL ){
++ pFd->lastErrno = osGetLastError();
++ rc = winLogError(SQLITE_IOERR_MMAP, pFd->lastErrno,
++ "winMapfile1", pFd->zPath);
++ /* Log the error, but continue normal operation using xRead/xWrite */
++ OSTRACE(("MAP-FILE-CREATE pid=%lu, pFile=%p, rc=%s\n",
++ osGetCurrentProcessId(), pFd, sqlite3ErrName(rc)));
++ return SQLITE_OK;
++ }
++ assert( (nMap % winSysInfo.dwPageSize)==0 );
++ assert( sizeof(SIZE_T)==sizeof(sqlite3_int64) || nMap<=0xffffffff );
++#if SQLITE_OS_WINRT
++ pNew = osMapViewOfFileFromApp(pFd->hMap, flags, 0, (SIZE_T)nMap);
++#else
++ pNew = osMapViewOfFile(pFd->hMap, flags, 0, 0, (SIZE_T)nMap);
++#endif
++ if( pNew==NULL ){
++ osCloseHandle(pFd->hMap);
++ pFd->hMap = NULL;
++ pFd->lastErrno = osGetLastError();
++ rc = winLogError(SQLITE_IOERR_MMAP, pFd->lastErrno,
++ "winMapfile2", pFd->zPath);
++ /* Log the error, but continue normal operation using xRead/xWrite */
++ OSTRACE(("MAP-FILE-MAP pid=%lu, pFile=%p, rc=%s\n",
++ osGetCurrentProcessId(), pFd, sqlite3ErrName(rc)));
++ return SQLITE_OK;
++ }
++ pFd->pMapRegion = pNew;
++ pFd->mmapSize = nMap;
++ pFd->mmapSizeActual = nMap;
+ }
+
+- /*
+- ** If we get to this point, the path name should almost certainly be a purely
+- ** relative one (i.e. not a UNC name, not absolute, and not volume relative).
+- */
+- return FALSE;
++ OSTRACE(("MAP-FILE pid=%lu, pFile=%p, rc=SQLITE_OK\n",
++ osGetCurrentProcessId(), pFd));
++ return SQLITE_OK;
+ }
++#endif /* SQLITE_MAX_MMAP_SIZE>0 */
+
+ /*
+-** Turn a relative pathname into a full pathname. Write the full
+-** pathname into zOut[]. zOut[] will be at least pVfs->mxPathname
+-** bytes in size.
++** If possible, return a pointer to a mapping of file fd starting at offset
++** iOff. The mapping must be valid for at least nAmt bytes.
++**
++** If such a pointer can be obtained, store it in *pp and return SQLITE_OK.
++** Or, if one cannot but no error occurs, set *pp to 0 and return SQLITE_OK.
++** Finally, if an error does occur, return an SQLite error code. The final
++** value of *pp is undefined in this case.
++**
++** If this function does return a pointer, the caller must eventually
++** release the reference by calling winUnfetch().
+ */
+-static int winFullPathname(
+- sqlite3_vfs *pVfs, /* Pointer to vfs object */
+- const char *zRelative, /* Possibly relative input path */
+- int nFull, /* Size of output buffer in bytes */
+- char *zFull /* Output buffer */
+-){
++static int winFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
++#if SQLITE_MAX_MMAP_SIZE>0
++ winFile *pFd = (winFile*)fd; /* The underlying database file */
++#endif
++ *pp = 0;
+
+-#if defined(__CYGWIN__)
+- SimulateIOError( return SQLITE_ERROR );
+- UNUSED_PARAMETER(nFull);
+- assert( nFull>=pVfs->mxPathname );
+- if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){
+- /*
+- ** NOTE: We are dealing with a relative path name and the data
+- ** directory has been set. Therefore, use it as the basis
+- ** for converting the relative path name to an absolute
+- ** one by prepending the data directory and a slash.
+- */
+- char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 );
+- if( !zOut ){
+- return SQLITE_IOERR_NOMEM;
+- }
+- if( cygwin_conv_path(
+- (osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A) |
+- CCP_RELATIVE, zRelative, zOut, pVfs->mxPathname+1)<0 ){
+- sqlite3_free(zOut);
+- return winLogError(SQLITE_CANTOPEN_CONVPATH, (DWORD)errno,
+- "winFullPathname1", zRelative);
+- }else{
+- char *zUtf8 = winConvertToUtf8Filename(zOut);
+- if( !zUtf8 ){
+- sqlite3_free(zOut);
+- return SQLITE_IOERR_NOMEM;
++ OSTRACE(("FETCH pid=%lu, pFile=%p, offset=%lld, amount=%d, pp=%p\n",
++ osGetCurrentProcessId(), fd, iOff, nAmt, pp));
++
++#if SQLITE_MAX_MMAP_SIZE>0
++ if( pFd->mmapSizeMax>0 ){
++ if( pFd->pMapRegion==0 ){
++ int rc = winMapfile(pFd, -1);
++ if( rc!=SQLITE_OK ){
++ OSTRACE(("FETCH pid=%lu, pFile=%p, rc=%s\n",
++ osGetCurrentProcessId(), pFd, sqlite3ErrName(rc)));
++ return rc;
+ }
+- sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s",
+- sqlite3_data_directory, winGetDirSep(), zUtf8);
+- sqlite3_free(zUtf8);
+- sqlite3_free(zOut);
+- }
+- }else{
+- char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 );
+- if( !zOut ){
+- return SQLITE_IOERR_NOMEM;
+ }
+- if( cygwin_conv_path(
+- (osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A),
+- zRelative, zOut, pVfs->mxPathname+1)<0 ){
+- sqlite3_free(zOut);
+- return winLogError(SQLITE_CANTOPEN_CONVPATH, (DWORD)errno,
+- "winFullPathname2", zRelative);
+- }else{
+- char *zUtf8 = winConvertToUtf8Filename(zOut);
+- if( !zUtf8 ){
+- sqlite3_free(zOut);
+- return SQLITE_IOERR_NOMEM;
+- }
+- sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zUtf8);
+- sqlite3_free(zUtf8);
+- sqlite3_free(zOut);
++ if( pFd->mmapSize >= iOff+nAmt ){
++ *pp = &((u8 *)pFd->pMapRegion)[iOff];
++ pFd->nFetchOut++;
+ }
+ }
+- return SQLITE_OK;
+ #endif
+
+-#if (SQLITE_OS_WINCE || SQLITE_OS_WINRT) && !defined(__CYGWIN__)
+- SimulateIOError( return SQLITE_ERROR );
+- /* WinCE has no concept of a relative pathname, or so I am told. */
+- /* WinRT has no way to convert a relative path to an absolute one. */
+- if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){
+- /*
+- ** NOTE: We are dealing with a relative path name and the data
+- ** directory has been set. Therefore, use it as the basis
+- ** for converting the relative path name to an absolute
+- ** one by prepending the data directory and a backslash.
+- */
+- sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s",
+- sqlite3_data_directory, winGetDirSep(), zRelative);
++ OSTRACE(("FETCH pid=%lu, pFile=%p, pp=%p, *pp=%p, rc=SQLITE_OK\n",
++ osGetCurrentProcessId(), fd, pp, *pp));
++ return SQLITE_OK;
++}
++
++/*
++** If the third argument is non-NULL, then this function releases a
++** reference obtained by an earlier call to winFetch(). The second
++** argument passed to this function must be the same as the corresponding
++** argument that was passed to the winFetch() invocation.
++**
++** Or, if the third argument is NULL, then this function is being called
++** to inform the VFS layer that, according to POSIX, any existing mapping
++** may now be invalid and should be unmapped.
++*/
++static int winUnfetch(sqlite3_file *fd, i64 iOff, void *p){
++#if SQLITE_MAX_MMAP_SIZE>0
++ winFile *pFd = (winFile*)fd; /* The underlying database file */
++
++ /* If p==0 (unmap the entire file) then there must be no outstanding
++ ** xFetch references. Or, if p!=0 (meaning it is an xFetch reference),
++ ** then there must be at least one outstanding. */
++ assert( (p==0)==(pFd->nFetchOut==0) );
++
++ /* If p!=0, it must match the iOff value. */
++ assert( p==0 || p==&((u8 *)pFd->pMapRegion)[iOff] );
++
++ OSTRACE(("UNFETCH pid=%lu, pFile=%p, offset=%lld, p=%p\n",
++ osGetCurrentProcessId(), pFd, iOff, p));
++
++ if( p ){
++ pFd->nFetchOut--;
+ }else{
+- sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zRelative);
++ /* FIXME: If Windows truly always prevents truncating or deleting a
++ ** file while a mapping is held, then the following winUnmapfile() call
++ ** is unnecessary can be omitted - potentially improving
++ ** performance. */
++ winUnmapfile(pFd);
+ }
+- return SQLITE_OK;
++
++ assert( pFd->nFetchOut>=0 );
+ #endif
+
+-#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__)
+- DWORD nByte;
+- void *zConverted;
+- char *zOut;
++ OSTRACE(("UNFETCH pid=%lu, pFile=%p, rc=SQLITE_OK\n",
++ osGetCurrentProcessId(), fd));
++ return SQLITE_OK;
++}
+
+- /* If this path name begins with "/X:", where "X" is any alphabetic
+- ** character, discard the initial "/" from the pathname.
+- */
+- if( zRelative[0]=='/' && winIsDriveLetterAndColon(zRelative+1) ){
+- zRelative++;
+- }
++/*
++** Here ends the implementation of all sqlite3_file methods.
++**
++********************** End sqlite3_file Methods *******************************
++******************************************************************************/
+
+- /* It's odd to simulate an io-error here, but really this is just
+- ** using the io-error infrastructure to test that SQLite handles this
+- ** function failing. This function could fail if, for example, the
+- ** current working directory has been unlinked.
+- */
+- SimulateIOError( return SQLITE_ERROR );
+- if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){
+- /*
+- ** NOTE: We are dealing with a relative path name and the data
+- ** directory has been set. Therefore, use it as the basis
+- ** for converting the relative path name to an absolute
+- ** one by prepending the data directory and a backslash.
+- */
+- sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s",
+- sqlite3_data_directory, winGetDirSep(), zRelative);
+- return SQLITE_OK;
+- }
+- zConverted = winConvertFromUtf8Filename(zRelative);
+- if( zConverted==0 ){
+- return SQLITE_IOERR_NOMEM;
+- }
++/*
++** This vector defines all the methods that can operate on an
++** sqlite3_file for win32.
++*/
++static const sqlite3_io_methods winIoMethod = {
++ 3, /* iVersion */
++ winClose, /* xClose */
++ winRead, /* xRead */
++ winWrite, /* xWrite */
++ winTruncate, /* xTruncate */
++ winSync, /* xSync */
++ winFileSize, /* xFileSize */
++ winLock, /* xLock */
++ winUnlock, /* xUnlock */
++ winCheckReservedLock, /* xCheckReservedLock */
++ winFileControl, /* xFileControl */
++ winSectorSize, /* xSectorSize */
++ winDeviceCharacteristics, /* xDeviceCharacteristics */
++ winShmMap, /* xShmMap */
++ winShmLock, /* xShmLock */
++ winShmBarrier, /* xShmBarrier */
++ winShmUnmap, /* xShmUnmap */
++ winFetch, /* xFetch */
++ winUnfetch /* xUnfetch */
++};
++
++/****************************************************************************
++**************************** sqlite3_vfs methods ****************************
++**
++** This division contains the implementation of methods on the
++** sqlite3_vfs object.
++*/
++
++#if defined(__CYGWIN__)
++/*
++** Convert a filename from whatever the underlying operating system
++** supports for filenames into UTF-8. Space to hold the result is
++** obtained from malloc and must be freed by the calling function.
++*/
++static char *winConvertToUtf8Filename(const void *zFilename){
++ char *zConverted = 0;
+ if( osIsNT() ){
+- LPWSTR zTemp;
+- nByte = osGetFullPathNameW((LPCWSTR)zConverted, 0, 0, 0);
+- if( nByte==0 ){
+- sqlite3_free(zConverted);
+- return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(),
+- "winFullPathname1", zRelative);
+- }
+- nByte += 3;
+- zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) );
+- if( zTemp==0 ){
+- sqlite3_free(zConverted);
+- return SQLITE_IOERR_NOMEM;
+- }
+- nByte = osGetFullPathNameW((LPCWSTR)zConverted, nByte, zTemp, 0);
+- if( nByte==0 ){
+- sqlite3_free(zConverted);
+- sqlite3_free(zTemp);
+- return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(),
+- "winFullPathname2", zRelative);
+- }
+- sqlite3_free(zConverted);
+- zOut = winUnicodeToUtf8(zTemp);
+- sqlite3_free(zTemp);
++ zConverted = winUnicodeToUtf8(zFilename);
+ }
+ #ifdef SQLITE_WIN32_HAS_ANSI
+ else{
+- char *zTemp;
+- nByte = osGetFullPathNameA((char*)zConverted, 0, 0, 0);
+- if( nByte==0 ){
+- sqlite3_free(zConverted);
+- return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(),
+- "winFullPathname3", zRelative);
+- }
+- nByte += 3;
+- zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) );
+- if( zTemp==0 ){
+- sqlite3_free(zConverted);
+- return SQLITE_IOERR_NOMEM;
+- }
+- nByte = osGetFullPathNameA((char*)zConverted, nByte, zTemp, 0);
+- if( nByte==0 ){
+- sqlite3_free(zConverted);
+- sqlite3_free(zTemp);
+- return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(),
+- "winFullPathname4", zRelative);
+- }
+- sqlite3_free(zConverted);
+- zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
+- sqlite3_free(zTemp);
+- }
+-#endif
+- if( zOut ){
+- sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut);
+- sqlite3_free(zOut);
+- return SQLITE_OK;
+- }else{
+- return SQLITE_IOERR_NOMEM;
++ zConverted = sqlite3_win32_mbcs_to_utf8(zFilename);
+ }
+ #endif
++ /* caller will handle out of memory */
++ return zConverted;
+ }
++#endif
+
+-#ifndef SQLITE_OMIT_LOAD_EXTENSION
+ /*
+-** Interfaces for opening a shared library, finding entry points
+-** within the shared library, and closing the shared library.
++** Convert a UTF-8 filename into whatever form the underlying
++** operating system wants filenames in. Space to hold the result
++** is obtained from malloc and must be freed by the calling
++** function.
+ */
+-static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){
+- HANDLE h;
+-#if defined(__CYGWIN__)
+- int nFull = pVfs->mxPathname+1;
+- char *zFull = sqlite3MallocZero( nFull );
++static void *winConvertFromUtf8Filename(const char *zFilename){
+ void *zConverted = 0;
+- if( zFull==0 ){
+- OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0));
+- return 0;
+- }
+- if( winFullPathname(pVfs, zFilename, nFull, zFull)!=SQLITE_OK ){
+- sqlite3_free(zFull);
+- OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0));
+- return 0;
+- }
+- zConverted = winConvertFromUtf8Filename(zFull);
+- sqlite3_free(zFull);
+-#else
+- void *zConverted = winConvertFromUtf8Filename(zFilename);
+- UNUSED_PARAMETER(pVfs);
+-#endif
+- if( zConverted==0 ){
+- OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0));
+- return 0;
+- }
+ if( osIsNT() ){
+-#if SQLITE_OS_WINRT
+- h = osLoadPackagedLibrary((LPCWSTR)zConverted, 0);
+-#else
+- h = osLoadLibraryW((LPCWSTR)zConverted);
+-#endif
++ zConverted = winUtf8ToUnicode(zFilename);
+ }
+ #ifdef SQLITE_WIN32_HAS_ANSI
+ else{
+- h = osLoadLibraryA((char*)zConverted);
++ zConverted = sqlite3_win32_utf8_to_mbcs(zFilename);
+ }
+ #endif
+- OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)h));
+- sqlite3_free(zConverted);
+- return (void*)h;
+-}
+-static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
+- UNUSED_PARAMETER(pVfs);
+- winGetLastErrorMsg(osGetLastError(), nBuf, zBufOut);
+-}
+-static void (*winDlSym(sqlite3_vfs *pVfs,void *pH,const char *zSym))(void){
+- FARPROC proc;
+- UNUSED_PARAMETER(pVfs);
+- proc = osGetProcAddressA((HANDLE)pH, zSym);
+- OSTRACE(("DLSYM handle=%p, symbol=%s, address=%p\n",
+- (void*)pH, zSym, (void*)proc));
+- return (void(*)(void))proc;
+-}
+-static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){
+- UNUSED_PARAMETER(pVfs);
+- osFreeLibrary((HANDLE)pHandle);
+- OSTRACE(("DLCLOSE handle=%p\n", (void*)pHandle));
++ /* caller will handle out of memory */
++ return zConverted;
+ }
+-#else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */
+- #define winDlOpen 0
+- #define winDlError 0
+- #define winDlSym 0
+- #define winDlClose 0
+-#endif
+-
+
+ /*
+-** Write up to nBuf bytes of randomness into zBuf.
++** This function returns non-zero if the specified UTF-8 string buffer
++** ends with a directory separator character or one was successfully
++** added to it.
+ */
+-static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
+- int n = 0;
+- UNUSED_PARAMETER(pVfs);
+-#if defined(SQLITE_TEST) || defined(SQLITE_OMIT_RANDOMNESS)
+- n = nBuf;
+- memset(zBuf, 0, nBuf);
+-#else
+- if( sizeof(SYSTEMTIME)<=nBuf-n ){
+- SYSTEMTIME x;
+- osGetSystemTime(&x);
+- memcpy(&zBuf[n], &x, sizeof(x));
+- n += sizeof(x);
+- }
+- if( sizeof(DWORD)<=nBuf-n ){
+- DWORD pid = osGetCurrentProcessId();
+- memcpy(&zBuf[n], &pid, sizeof(pid));
+- n += sizeof(pid);
++static int winMakeEndInDirSep(int nBuf, char *zBuf){
++ if( zBuf ){
++ int nLen = sqlite3Strlen30(zBuf);
++ if( nLen>0 ){
++ if( winIsDirSep(zBuf[nLen-1]) ){
++ return 1;
++ }else if( nLen+1<nBuf ){
++ zBuf[nLen] = winGetDirSep();
++ zBuf[nLen+1] = '\0';
++ return 1;
++ }
++ }
+ }
+-#if SQLITE_OS_WINRT
+- if( sizeof(ULONGLONG)<=nBuf-n ){
+- ULONGLONG cnt = osGetTickCount64();
+- memcpy(&zBuf[n], &cnt, sizeof(cnt));
+- n += sizeof(cnt);
++ return 0;
++}
++
++/*
++** Create a temporary file name and store the resulting pointer into pzBuf.
++** The pointer returned in pzBuf must be freed via sqlite3_free().
++*/
++static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
++ static char zChars[] =
++ "abcdefghijklmnopqrstuvwxyz"
++ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
++ "0123456789";
++ size_t i, j;
++ int nPre = sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX);
++ int nMax, nBuf, nDir, nLen;
++ char *zBuf;
++
++ /* It's odd to simulate an io-error here, but really this is just
++ ** using the io-error infrastructure to test that SQLite handles this
++ ** function failing.
++ */
++ SimulateIOError( return SQLITE_IOERR );
++
++ /* Allocate a temporary buffer to store the fully qualified file
++ ** name for the temporary file. If this fails, we cannot continue.
++ */
++ nMax = pVfs->mxPathname; nBuf = nMax + 2;
++ zBuf = sqlite3MallocZero( nBuf );
++ if( !zBuf ){
++ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
++ return SQLITE_IOERR_NOMEM;
+ }
+-#else
+- if( sizeof(DWORD)<=nBuf-n ){
+- DWORD cnt = osGetTickCount();
+- memcpy(&zBuf[n], &cnt, sizeof(cnt));
+- n += sizeof(cnt);
++
++ /* Figure out the effective temporary directory. First, check if one
++ ** has been explicitly set by the application; otherwise, use the one
++ ** configured by the operating system.
++ */
++ nDir = nMax - (nPre + 15);
++ assert( nDir>0 );
++ if( sqlite3_temp_directory ){
++ int nDirLen = sqlite3Strlen30(sqlite3_temp_directory);
++ if( nDirLen>0 ){
++ if( !winIsDirSep(sqlite3_temp_directory[nDirLen-1]) ){
++ nDirLen++;
++ }
++ if( nDirLen>nDir ){
++ sqlite3_free(zBuf);
++ OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n"));
++ return winLogError(SQLITE_ERROR, 0, "winGetTempname1", 0);
++ }
++ sqlite3_snprintf(nMax, zBuf, "%s", sqlite3_temp_directory);
++ }
+ }
+-#endif
+- if( sizeof(LARGE_INTEGER)<=nBuf-n ){
+- LARGE_INTEGER i;
+- osQueryPerformanceCounter(&i);
+- memcpy(&zBuf[n], &i, sizeof(i));
+- n += sizeof(i);
++#if defined(__CYGWIN__)
++ else{
++ static const char *azDirs[] = {
++ 0, /* getenv("SQLITE_TMPDIR") */
++ 0, /* getenv("TMPDIR") */
++ 0, /* getenv("TMP") */
++ 0, /* getenv("TEMP") */
++ 0, /* getenv("USERPROFILE") */
++ "/var/tmp",
++ "/usr/tmp",
++ "/tmp",
++ ".",
++ 0 /* List terminator */
++ };
++ unsigned int i;
++ const char *zDir = 0;
++
++ if( !azDirs[0] ) azDirs[0] = getenv("SQLITE_TMPDIR");
++ if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR");
++ if( !azDirs[2] ) azDirs[2] = getenv("TMP");
++ if( !azDirs[3] ) azDirs[3] = getenv("TEMP");
++ if( !azDirs[4] ) azDirs[4] = getenv("USERPROFILE");
++ for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); zDir=azDirs[i++]){
++ void *zConverted;
++ if( zDir==0 ) continue;
++ /* If the path starts with a drive letter followed by the colon
++ ** character, assume it is already a native Win32 path; otherwise,
++ ** it must be converted to a native Win32 path via the Cygwin API
++ ** prior to using it.
++ */
++ if( winIsDriveLetterAndColon(zDir) ){
++ zConverted = winConvertFromUtf8Filename(zDir);
++ if( !zConverted ){
++ sqlite3_free(zBuf);
++ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
++ return SQLITE_IOERR_NOMEM;
++ }
++ if( winIsDir(zConverted) ){
++ sqlite3_snprintf(nMax, zBuf, "%s", zDir);
++ sqlite3_free(zConverted);
++ break;
++ }
++ sqlite3_free(zConverted);
++ }else{
++ zConverted = sqlite3MallocZero( nMax+1 );
++ if( !zConverted ){
++ sqlite3_free(zBuf);
++ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
++ return SQLITE_IOERR_NOMEM;
++ }
++ if( cygwin_conv_path(
++ osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A, zDir,
++ zConverted, nMax+1)<0 ){
++ sqlite3_free(zConverted);
++ sqlite3_free(zBuf);
++ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_CONVPATH\n"));
++ return winLogError(SQLITE_IOERR_CONVPATH, (DWORD)errno,
++ "winGetTempname2", zDir);
++ }
++ if( winIsDir(zConverted) ){
++ /* At this point, we know the candidate directory exists and should
++ ** be used. However, we may need to convert the string containing
++ ** its name into UTF-8 (i.e. if it is UTF-16 right now).
++ */
++ char *zUtf8 = winConvertToUtf8Filename(zConverted);
++ if( !zUtf8 ){
++ sqlite3_free(zConverted);
++ sqlite3_free(zBuf);
++ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
++ return SQLITE_IOERR_NOMEM;
++ }
++ sqlite3_snprintf(nMax, zBuf, "%s", zUtf8);
++ sqlite3_free(zUtf8);
++ sqlite3_free(zConverted);
++ break;
++ }
++ sqlite3_free(zConverted);
++ }
++ }
+ }
+-#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID
+- if( sizeof(UUID)<=nBuf-n ){
+- UUID id;
+- memset(&id, 0, sizeof(UUID));
+- osUuidCreate(&id);
+- memcpy(zBuf, &id, sizeof(UUID));
+- n += sizeof(UUID);
++#elif !SQLITE_OS_WINRT && !defined(__CYGWIN__)
++ else if( osIsNT() ){
++ char *zMulti;
++ LPWSTR zWidePath = sqlite3MallocZero( nMax*sizeof(WCHAR) );
++ if( !zWidePath ){
++ sqlite3_free(zBuf);
++ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
++ return SQLITE_IOERR_NOMEM;
++ }
++ if( osGetTempPathW(nMax, zWidePath)==0 ){
++ sqlite3_free(zWidePath);
++ sqlite3_free(zBuf);
++ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_GETTEMPPATH\n"));
++ return winLogError(SQLITE_IOERR_GETTEMPPATH, osGetLastError(),
++ "winGetTempname2", 0);
++ }
++ zMulti = winUnicodeToUtf8(zWidePath);
++ if( zMulti ){
++ sqlite3_snprintf(nMax, zBuf, "%s", zMulti);
++ sqlite3_free(zMulti);
++ sqlite3_free(zWidePath);
++ }else{
++ sqlite3_free(zWidePath);
++ sqlite3_free(zBuf);
++ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
++ return SQLITE_IOERR_NOMEM;
++ }
+ }
+- if( sizeof(UUID)<=nBuf-n ){
+- UUID id;
+- memset(&id, 0, sizeof(UUID));
+- osUuidCreateSequential(&id);
+- memcpy(zBuf, &id, sizeof(UUID));
+- n += sizeof(UUID);
++#ifdef SQLITE_WIN32_HAS_ANSI
++ else{
++ char *zUtf8;
++ char *zMbcsPath = sqlite3MallocZero( nMax );
++ if( !zMbcsPath ){
++ sqlite3_free(zBuf);
++ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
++ return SQLITE_IOERR_NOMEM;
++ }
++ if( osGetTempPathA(nMax, zMbcsPath)==0 ){
++ sqlite3_free(zBuf);
++ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_GETTEMPPATH\n"));
++ return winLogError(SQLITE_IOERR_GETTEMPPATH, osGetLastError(),
++ "winGetTempname3", 0);
++ }
++ zUtf8 = sqlite3_win32_mbcs_to_utf8(zMbcsPath);
++ if( zUtf8 ){
++ sqlite3_snprintf(nMax, zBuf, "%s", zUtf8);
++ sqlite3_free(zUtf8);
++ }else{
++ sqlite3_free(zBuf);
++ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
++ return SQLITE_IOERR_NOMEM;
++ }
+ }
+-#endif
+-#endif /* defined(SQLITE_TEST) || defined(SQLITE_ZERO_PRNG_SEED) */
+- return n;
+-}
+-
+-
+-/*
+-** Sleep for a little while. Return the amount of time slept.
+-*/
+-static int winSleep(sqlite3_vfs *pVfs, int microsec){
+- sqlite3_win32_sleep((microsec+999)/1000);
+- UNUSED_PARAMETER(pVfs);
+- return ((microsec+999)/1000)*1000;
+-}
+-
+-/*
+-** The following variable, if set to a non-zero value, is interpreted as
+-** the number of seconds since 1970 and is used to set the result of
+-** sqlite3OsCurrentTime() during testing.
+-*/
+-#ifdef SQLITE_TEST
+-SQLITE_API int sqlite3_current_time = 0; /* Fake system time in seconds since 1970. */
+-#endif
++#endif /* SQLITE_WIN32_HAS_ANSI */
++#endif /* !SQLITE_OS_WINRT */
+
+-/*
+-** Find the current time (in Universal Coordinated Time). Write into *piNow
+-** the current time and date as a Julian Day number times 86_400_000. In
+-** other words, write into *piNow the number of milliseconds since the Julian
+-** epoch of noon in Greenwich on November 24, 4714 B.C according to the
+-** proleptic Gregorian calendar.
+-**
+-** On success, return SQLITE_OK. Return SQLITE_ERROR if the time and date
+-** cannot be found.
+-*/
+-static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){
+- /* FILETIME structure is a 64-bit value representing the number of
+- 100-nanosecond intervals since January 1, 1601 (= JD 2305813.5).
++ /*
++ ** Check to make sure the temporary directory ends with an appropriate
++ ** separator. If it does not and there is not enough space left to add
++ ** one, fail.
+ */
+- FILETIME ft;
+- static const sqlite3_int64 winFiletimeEpoch = 23058135*(sqlite3_int64)8640000;
+-#ifdef SQLITE_TEST
+- static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
+-#endif
+- /* 2^32 - to avoid use of LL and warnings in gcc */
+- static const sqlite3_int64 max32BitValue =
+- (sqlite3_int64)2000000000 + (sqlite3_int64)2000000000 +
+- (sqlite3_int64)294967296;
++ if( !winMakeEndInDirSep(nDir+1, zBuf) ){
++ sqlite3_free(zBuf);
++ OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n"));
++ return winLogError(SQLITE_ERROR, 0, "winGetTempname4", 0);
++ }
+
+-#if SQLITE_OS_WINCE
+- SYSTEMTIME time;
+- osGetSystemTime(&time);
+- /* if SystemTimeToFileTime() fails, it returns zero. */
+- if (!osSystemTimeToFileTime(&time,&ft)){
+- return SQLITE_ERROR;
++ /*
++ ** Check that the output buffer is large enough for the temporary file
++ ** name in the following format:
++ **
++ ** "<temporary_directory>/etilqs_XXXXXXXXXXXXXXX\0\0"
++ **
++ ** If not, return SQLITE_ERROR. The number 17 is used here in order to
++ ** account for the space used by the 15 character random suffix and the
++ ** two trailing NUL characters. The final directory separator character
++ ** has already added if it was not already present.
++ */
++ nLen = sqlite3Strlen30(zBuf);
++ if( (nLen + nPre + 17) > nBuf ){
++ sqlite3_free(zBuf);
++ OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n"));
++ return winLogError(SQLITE_ERROR, 0, "winGetTempname5", 0);
+ }
+-#else
+- osGetSystemTimeAsFileTime( &ft );
+-#endif
+
+- *piNow = winFiletimeEpoch +
+- ((((sqlite3_int64)ft.dwHighDateTime)*max32BitValue) +
+- (sqlite3_int64)ft.dwLowDateTime)/(sqlite3_int64)10000;
++ sqlite3_snprintf(nBuf-16-nLen, zBuf+nLen, SQLITE_TEMP_FILE_PREFIX);
+
+-#ifdef SQLITE_TEST
+- if( sqlite3_current_time ){
+- *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch;
++ j = sqlite3Strlen30(zBuf);
++ sqlite3_randomness(15, &zBuf[j]);
++ for(i=0; i<15; i++, j++){
++ zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
+ }
+-#endif
+- UNUSED_PARAMETER(pVfs);
++ zBuf[j] = 0;
++ zBuf[j+1] = 0;
++ *pzBuf = zBuf;
++
++ OSTRACE(("TEMP-FILENAME name=%s, rc=SQLITE_OK\n", zBuf));
+ return SQLITE_OK;
+ }
+
+ /*
+-** Find the current time (in Universal Coordinated Time). Write the
+-** current time and date as a Julian Day number into *prNow and
+-** return 0. Return 1 if the time and date cannot be found.
++** Return TRUE if the named file is really a directory. Return false if
++** it is something other than a directory, or if there is any kind of memory
++** allocation failure.
+ */
+-static int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
+- int rc;
+- sqlite3_int64 i;
+- rc = winCurrentTimeInt64(pVfs, &i);
+- if( !rc ){
+- *prNow = i/86400000.0;
+- }
+- return rc;
+-}
++static int winIsDir(const void *zConverted){
++ DWORD attr;
++ int rc = 0;
++ DWORD lastErrno;
+
+-/*
+-** The idea is that this function works like a combination of
+-** GetLastError() and FormatMessage() on Windows (or errno and
+-** strerror_r() on Unix). After an error is returned by an OS
+-** function, SQLite calls this function with zBuf pointing to
+-** a buffer of nBuf bytes. The OS layer should populate the
+-** buffer with a nul-terminated UTF-8 encoded error message
+-** describing the last IO error to have occurred within the calling
+-** thread.
+-**
+-** If the error message is too large for the supplied buffer,
+-** it should be truncated. The return value of xGetLastError
+-** is zero if the error message fits in the buffer, or non-zero
+-** otherwise (if the message was truncated). If non-zero is returned,
+-** then it is not necessary to include the nul-terminator character
+-** in the output buffer.
+-**
+-** Not supplying an error message will have no adverse effect
+-** on SQLite. It is fine to have an implementation that never
+-** returns an error message:
+-**
+-** int xGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
+-** assert(zBuf[0]=='\0');
+-** return 0;
+-** }
+-**
+-** However if an error message is supplied, it will be incorporated
+-** by sqlite into the error message available to the user using
+-** sqlite3_errmsg(), possibly making IO errors easier to debug.
+-*/
+-static int winGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
+- UNUSED_PARAMETER(pVfs);
+- return winGetLastErrorMsg(osGetLastError(), nBuf, zBuf);
++ if( osIsNT() ){
++ int cnt = 0;
++ WIN32_FILE_ATTRIBUTE_DATA sAttrData;
++ memset(&sAttrData, 0, sizeof(sAttrData));
++ while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted,
++ GetFileExInfoStandard,
++ &sAttrData)) && winRetryIoerr(&cnt, &lastErrno) ){}
++ if( !rc ){
++ return 0; /* Invalid name? */
++ }
++ attr = sAttrData.dwFileAttributes;
++#if SQLITE_OS_WINCE==0
++ }else{
++ attr = osGetFileAttributesA((char*)zConverted);
++#endif
++ }
++ return (attr!=INVALID_FILE_ATTRIBUTES) && (attr&FILE_ATTRIBUTE_DIRECTORY);
+ }
+
+ /*
+-** Initialize and deinitialize the operating system interface.
++** Open a file.
+ */
+-SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void){
+- static sqlite3_vfs winVfs = {
+- 3, /* iVersion */
+- sizeof(winFile), /* szOsFile */
+- SQLITE_WIN32_MAX_PATH_BYTES, /* mxPathname */
+- 0, /* pNext */
+- "win32", /* zName */
+- 0, /* pAppData */
+- winOpen, /* xOpen */
+- winDelete, /* xDelete */
+- winAccess, /* xAccess */
+- winFullPathname, /* xFullPathname */
+- winDlOpen, /* xDlOpen */
+- winDlError, /* xDlError */
+- winDlSym, /* xDlSym */
+- winDlClose, /* xDlClose */
+- winRandomness, /* xRandomness */
+- winSleep, /* xSleep */
+- winCurrentTime, /* xCurrentTime */
+- winGetLastError, /* xGetLastError */
+- winCurrentTimeInt64, /* xCurrentTimeInt64 */
+- winSetSystemCall, /* xSetSystemCall */
+- winGetSystemCall, /* xGetSystemCall */
+- winNextSystemCall, /* xNextSystemCall */
+- };
+-#if defined(SQLITE_WIN32_HAS_WIDE)
+- static sqlite3_vfs winLongPathVfs = {
+- 3, /* iVersion */
+- sizeof(winFile), /* szOsFile */
+- SQLITE_WINNT_MAX_PATH_BYTES, /* mxPathname */
+- 0, /* pNext */
+- "win32-longpath", /* zName */
+- 0, /* pAppData */
+- winOpen, /* xOpen */
+- winDelete, /* xDelete */
+- winAccess, /* xAccess */
+- winFullPathname, /* xFullPathname */
+- winDlOpen, /* xDlOpen */
+- winDlError, /* xDlError */
+- winDlSym, /* xDlSym */
+- winDlClose, /* xDlClose */
+- winRandomness, /* xRandomness */
+- winSleep, /* xSleep */
+- winCurrentTime, /* xCurrentTime */
+- winGetLastError, /* xGetLastError */
+- winCurrentTimeInt64, /* xCurrentTimeInt64 */
+- winSetSystemCall, /* xSetSystemCall */
+- winGetSystemCall, /* xGetSystemCall */
+- winNextSystemCall, /* xNextSystemCall */
+- };
++static int winOpen(
++ sqlite3_vfs *pVfs, /* Used to get maximum path name length */
++ const char *zName, /* Name of the file (UTF-8) */
++ sqlite3_file *id, /* Write the SQLite file handle here */
++ int flags, /* Open mode flags */
++ int *pOutFlags /* Status return flags */
++){
++ HANDLE h;
++ DWORD lastErrno = 0;
++ DWORD dwDesiredAccess;
++ DWORD dwShareMode;
++ DWORD dwCreationDisposition;
++ DWORD dwFlagsAndAttributes = 0;
++#if SQLITE_OS_WINCE
++ int isTemp = 0;
+ #endif
++ winFile *pFile = (winFile*)id;
++ void *zConverted; /* Filename in OS encoding */
++ const char *zUtf8Name = zName; /* Filename in UTF-8 encoding */
++ int cnt = 0;
+
+- /* Double-check that the aSyscall[] array has been constructed
+- ** correctly. See ticket [bb3a86e890c8e96ab] */
+- assert( ArraySize(aSyscall)==80 );
++ /* If argument zPath is a NULL pointer, this function is required to open
++ ** a temporary file. Use this buffer to store the file name in.
++ */
++ char *zTmpname = 0; /* For temporary filename, if necessary. */
+
+- /* get memory map allocation granularity */
+- memset(&winSysInfo, 0, sizeof(SYSTEM_INFO));
+-#if SQLITE_OS_WINRT
+- osGetNativeSystemInfo(&winSysInfo);
+-#else
+- osGetSystemInfo(&winSysInfo);
++ int rc = SQLITE_OK; /* Function Return Code */
++#if !defined(NDEBUG) || SQLITE_OS_WINCE
++ int eType = flags&0xFFFFFF00; /* Type of file to open */
+ #endif
+- assert( winSysInfo.dwAllocationGranularity>0 );
+- assert( winSysInfo.dwPageSize>0 );
+
+- sqlite3_vfs_register(&winVfs, 1);
++ int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE);
++ int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE);
++ int isCreate = (flags & SQLITE_OPEN_CREATE);
++ int isReadonly = (flags & SQLITE_OPEN_READONLY);
++ int isReadWrite = (flags & SQLITE_OPEN_READWRITE);
+
+-#if defined(SQLITE_WIN32_HAS_WIDE)
+- sqlite3_vfs_register(&winLongPathVfs, 0);
++#ifndef NDEBUG
++ int isOpenJournal = (isCreate && (
++ eType==SQLITE_OPEN_MASTER_JOURNAL
++ || eType==SQLITE_OPEN_MAIN_JOURNAL
++ || eType==SQLITE_OPEN_WAL
++ ));
+ #endif
+
+- return SQLITE_OK;
+-}
++ OSTRACE(("OPEN name=%s, pFile=%p, flags=%x, pOutFlags=%p\n",
++ zUtf8Name, id, flags, pOutFlags));
++
++ /* Check the following statements are true:
++ **
++ ** (a) Exactly one of the READWRITE and READONLY flags must be set, and
++ ** (b) if CREATE is set, then READWRITE must also be set, and
++ ** (c) if EXCLUSIVE is set, then CREATE must also be set.
++ ** (d) if DELETEONCLOSE is set, then CREATE must also be set.
++ */
++ assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly));
++ assert(isCreate==0 || isReadWrite);
++ assert(isExclusive==0 || isCreate);
++ assert(isDelete==0 || isCreate);
++
++ /* The main DB, main journal, WAL file and master journal are never
++ ** automatically deleted. Nor are they ever temporary files. */
++ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB );
++ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL );
++ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL );
++ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL );
++
++ /* Assert that the upper layer has set one of the "file-type" flags. */
++ assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB
++ || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
++ || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL
++ || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
++ );
++
++ assert( pFile!=0 );
++ memset(pFile, 0, sizeof(winFile));
++ pFile->h = INVALID_HANDLE_VALUE;
+
+-SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void){
+ #if SQLITE_OS_WINRT
+- if( sleepObj!=NULL ){
+- osCloseHandle(sleepObj);
+- sleepObj = NULL;
++ if( !zUtf8Name && !sqlite3_temp_directory ){
++ sqlite3_log(SQLITE_ERROR,
++ "sqlite3_temp_directory variable should be set for WinRT");
+ }
+ #endif
+- return SQLITE_OK;
+-}
+-
+-#endif /* SQLITE_OS_WIN */
+-
+-/************** End of os_win.c **********************************************/
+-/************** Begin file bitvec.c ******************************************/
+-/*
+-** 2008 February 16
+-**
+-** The author disclaims copyright to this source code. In place of
+-** a legal notice, here is a blessing:
+-**
+-** May you do good and not evil.
+-** May you find forgiveness for yourself and forgive others.
+-** May you share freely, never taking more than you give.
+-**
+-*************************************************************************
+-** This file implements an object that represents a fixed-length
+-** bitmap. Bits are numbered starting with 1.
+-**
+-** A bitmap is used to record which pages of a database file have been
+-** journalled during a transaction, or which pages have the "dont-write"
+-** property. Usually only a few pages are meet either condition.
+-** So the bitmap is usually sparse and has low cardinality.
+-** But sometimes (for example when during a DROP of a large table) most
+-** or all of the pages in a database can get journalled. In those cases,
+-** the bitmap becomes dense with high cardinality. The algorithm needs
+-** to handle both cases well.
+-**
+-** The size of the bitmap is fixed when the object is created.
+-**
+-** All bits are clear when the bitmap is created. Individual bits
+-** may be set or cleared one at a time.
+-**
+-** Test operations are about 100 times more common that set operations.
+-** Clear operations are exceedingly rare. There are usually between
+-** 5 and 500 set operations per Bitvec object, though the number of sets can
+-** sometimes grow into tens of thousands or larger. The size of the
+-** Bitvec object is the number of pages in the database file at the
+-** start of a transaction, and is thus usually less than a few thousand,
+-** but can be as large as 2 billion for a really big database.
+-*/
+
+-/* Size of the Bitvec structure in bytes. */
+-#define BITVEC_SZ 512
++ /* If the second argument to this function is NULL, generate a
++ ** temporary file name to use
++ */
++ if( !zUtf8Name ){
++ assert( isDelete && !isOpenJournal );
++ rc = winGetTempname(pVfs, &zTmpname);
++ if( rc!=SQLITE_OK ){
++ OSTRACE(("OPEN name=%s, rc=%s", zUtf8Name, sqlite3ErrName(rc)));
++ return rc;
++ }
++ zUtf8Name = zTmpname;
++ }
+
+-/* Round the union size down to the nearest pointer boundary, since that's how
+-** it will be aligned within the Bitvec struct. */
+-#define BITVEC_USIZE (((BITVEC_SZ-(3*sizeof(u32)))/sizeof(Bitvec*))*sizeof(Bitvec*))
++ /* Database filenames are double-zero terminated if they are not
++ ** URIs with parameters. Hence, they can always be passed into
++ ** sqlite3_uri_parameter().
++ */
++ assert( (eType!=SQLITE_OPEN_MAIN_DB) || (flags & SQLITE_OPEN_URI) ||
++ zUtf8Name[sqlite3Strlen30(zUtf8Name)+1]==0 );
+
+-/* Type of the array "element" for the bitmap representation.
+-** Should be a power of 2, and ideally, evenly divide into BITVEC_USIZE.
+-** Setting this to the "natural word" size of your CPU may improve
+-** performance. */
+-#define BITVEC_TELEM u8
+-/* Size, in bits, of the bitmap element. */
+-#define BITVEC_SZELEM 8
+-/* Number of elements in a bitmap array. */
+-#define BITVEC_NELEM (BITVEC_USIZE/sizeof(BITVEC_TELEM))
+-/* Number of bits in the bitmap array. */
+-#define BITVEC_NBIT (BITVEC_NELEM*BITVEC_SZELEM)
++ /* Convert the filename to the system encoding. */
++ zConverted = winConvertFromUtf8Filename(zUtf8Name);
++ if( zConverted==0 ){
++ sqlite3_free(zTmpname);
++ OSTRACE(("OPEN name=%s, rc=SQLITE_IOERR_NOMEM", zUtf8Name));
++ return SQLITE_IOERR_NOMEM;
++ }
+
+-/* Number of u32 values in hash table. */
+-#define BITVEC_NINT (BITVEC_USIZE/sizeof(u32))
+-/* Maximum number of entries in hash table before
+-** sub-dividing and re-hashing. */
+-#define BITVEC_MXHASH (BITVEC_NINT/2)
+-/* Hashing function for the aHash representation.
+-** Empirical testing showed that the *37 multiplier
+-** (an arbitrary prime)in the hash function provided
+-** no fewer collisions than the no-op *1. */
+-#define BITVEC_HASH(X) (((X)*1)%BITVEC_NINT)
++ if( winIsDir(zConverted) ){
++ sqlite3_free(zConverted);
++ sqlite3_free(zTmpname);
++ OSTRACE(("OPEN name=%s, rc=SQLITE_CANTOPEN_ISDIR", zUtf8Name));
++ return SQLITE_CANTOPEN_ISDIR;
++ }
+
+-#define BITVEC_NPTR (BITVEC_USIZE/sizeof(Bitvec *))
++ if( isReadWrite ){
++ dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
++ }else{
++ dwDesiredAccess = GENERIC_READ;
++ }
+
++ /* SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is
++ ** created. SQLite doesn't use it to indicate "exclusive access"
++ ** as it is usually understood.
++ */
++ if( isExclusive ){
++ /* Creates a new file, only if it does not already exist. */
++ /* If the file exists, it fails. */
++ dwCreationDisposition = CREATE_NEW;
++ }else if( isCreate ){
++ /* Open existing file, or create if it doesn't exist */
++ dwCreationDisposition = OPEN_ALWAYS;
++ }else{
++ /* Opens a file, only if it exists. */
++ dwCreationDisposition = OPEN_EXISTING;
++ }
+
+-/*
+-** A bitmap is an instance of the following structure.
+-**
+-** This bitmap records the existence of zero or more bits
+-** with values between 1 and iSize, inclusive.
+-**
+-** There are three possible representations of the bitmap.
+-** If iSize<=BITVEC_NBIT, then Bitvec.u.aBitmap[] is a straight
+-** bitmap. The least significant bit is bit 1.
+-**
+-** If iSize>BITVEC_NBIT and iDivisor==0 then Bitvec.u.aHash[] is
+-** a hash table that will hold up to BITVEC_MXHASH distinct values.
+-**
+-** Otherwise, the value i is redirected into one of BITVEC_NPTR
+-** sub-bitmaps pointed to by Bitvec.u.apSub[]. Each subbitmap
+-** handles up to iDivisor separate values of i. apSub[0] holds
+-** values between 1 and iDivisor. apSub[1] holds values between
+-** iDivisor+1 and 2*iDivisor. apSub[N] holds values between
+-** N*iDivisor+1 and (N+1)*iDivisor. Each subbitmap is normalized
+-** to hold deal with values between 1 and iDivisor.
+-*/
+-struct Bitvec {
+- u32 iSize; /* Maximum bit index. Max iSize is 4,294,967,296. */
+- u32 nSet; /* Number of bits that are set - only valid for aHash
+- ** element. Max is BITVEC_NINT. For BITVEC_SZ of 512,
+- ** this would be 125. */
+- u32 iDivisor; /* Number of bits handled by each apSub[] entry. */
+- /* Should >=0 for apSub element. */
+- /* Max iDivisor is max(u32) / BITVEC_NPTR + 1. */
+- /* For a BITVEC_SZ of 512, this would be 34,359,739. */
+- union {
+- BITVEC_TELEM aBitmap[BITVEC_NELEM]; /* Bitmap representation */
+- u32 aHash[BITVEC_NINT]; /* Hash table representation */
+- Bitvec *apSub[BITVEC_NPTR]; /* Recursive representation */
+- } u;
+-};
++ dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+
+-/*
+-** Create a new bitmap object able to handle bits between 0 and iSize,
+-** inclusive. Return a pointer to the new object. Return NULL if
+-** malloc fails.
+-*/
+-SQLITE_PRIVATE Bitvec *sqlite3BitvecCreate(u32 iSize){
+- Bitvec *p;
+- assert( sizeof(*p)==BITVEC_SZ );
+- p = sqlite3MallocZero( sizeof(*p) );
+- if( p ){
+- p->iSize = iSize;
++ if( isDelete ){
++#if SQLITE_OS_WINCE
++ dwFlagsAndAttributes = FILE_ATTRIBUTE_HIDDEN;
++ isTemp = 1;
++#else
++ dwFlagsAndAttributes = FILE_ATTRIBUTE_TEMPORARY
++ | FILE_ATTRIBUTE_HIDDEN
++ | FILE_FLAG_DELETE_ON_CLOSE;
++#endif
++ }else{
++ dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
+ }
+- return p;
+-}
++ /* Reports from the internet are that performance is always
++ ** better if FILE_FLAG_RANDOM_ACCESS is used. Ticket #2699. */
++#if SQLITE_OS_WINCE
++ dwFlagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS;
++#endif
+
+-/*
+-** Check to see if the i-th bit is set. Return true or false.
+-** If p is NULL (if the bitmap has not been created) or if
+-** i is out of range, then return false.
+-*/
+-SQLITE_PRIVATE int sqlite3BitvecTest(Bitvec *p, u32 i){
+- if( p==0 ) return 0;
+- if( i>p->iSize || i==0 ) return 0;
+- i--;
+- while( p->iDivisor ){
+- u32 bin = i/p->iDivisor;
+- i = i%p->iDivisor;
+- p = p->u.apSub[bin];
+- if (!p) {
+- return 0;
++ if( osIsNT() ){
++#if SQLITE_OS_WINRT
++ CREATEFILE2_EXTENDED_PARAMETERS extendedParameters;
++ extendedParameters.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
++ extendedParameters.dwFileAttributes =
++ dwFlagsAndAttributes & FILE_ATTRIBUTE_MASK;
++ extendedParameters.dwFileFlags = dwFlagsAndAttributes & FILE_FLAG_MASK;
++ extendedParameters.dwSecurityQosFlags = SECURITY_ANONYMOUS;
++ extendedParameters.lpSecurityAttributes = NULL;
++ extendedParameters.hTemplateFile = NULL;
++ while( (h = osCreateFile2((LPCWSTR)zConverted,
++ dwDesiredAccess,
++ dwShareMode,
++ dwCreationDisposition,
++ &extendedParameters))==INVALID_HANDLE_VALUE &&
++ winRetryIoerr(&cnt, &lastErrno) ){
++ /* Noop */
+ }
+- }
+- if( p->iSize<=BITVEC_NBIT ){
+- return (p->u.aBitmap[i/BITVEC_SZELEM] & (1<<(i&(BITVEC_SZELEM-1))))!=0;
+- } else{
+- u32 h = BITVEC_HASH(i++);
+- while( p->u.aHash[h] ){
+- if( p->u.aHash[h]==i ) return 1;
+- h = (h+1) % BITVEC_NINT;
++#else
++ while( (h = osCreateFileW((LPCWSTR)zConverted,
++ dwDesiredAccess,
++ dwShareMode, NULL,
++ dwCreationDisposition,
++ dwFlagsAndAttributes,
++ NULL))==INVALID_HANDLE_VALUE &&
++ winRetryIoerr(&cnt, &lastErrno) ){
++ /* Noop */
+ }
+- return 0;
++#endif
+ }
+-}
+-
+-/*
+-** Set the i-th bit. Return 0 on success and an error code if
+-** anything goes wrong.
+-**
+-** This routine might cause sub-bitmaps to be allocated. Failing
+-** to get the memory needed to hold the sub-bitmap is the only
+-** that can go wrong with an insert, assuming p and i are valid.
+-**
+-** The calling function must ensure that p is a valid Bitvec object
+-** and that the value for "i" is within range of the Bitvec object.
+-** Otherwise the behavior is undefined.
+-*/
+-SQLITE_PRIVATE int sqlite3BitvecSet(Bitvec *p, u32 i){
+- u32 h;
+- if( p==0 ) return SQLITE_OK;
+- assert( i>0 );
+- assert( i<=p->iSize );
+- i--;
+- while((p->iSize > BITVEC_NBIT) && p->iDivisor) {
+- u32 bin = i/p->iDivisor;
+- i = i%p->iDivisor;
+- if( p->u.apSub[bin]==0 ){
+- p->u.apSub[bin] = sqlite3BitvecCreate( p->iDivisor );
+- if( p->u.apSub[bin]==0 ) return SQLITE_NOMEM;
++#ifdef SQLITE_WIN32_HAS_ANSI
++ else{
++ while( (h = osCreateFileA((LPCSTR)zConverted,
++ dwDesiredAccess,
++ dwShareMode, NULL,
++ dwCreationDisposition,
++ dwFlagsAndAttributes,
++ NULL))==INVALID_HANDLE_VALUE &&
++ winRetryIoerr(&cnt, &lastErrno) ){
++ /* Noop */
+ }
+- p = p->u.apSub[bin];
+ }
+- if( p->iSize<=BITVEC_NBIT ){
+- p->u.aBitmap[i/BITVEC_SZELEM] |= 1 << (i&(BITVEC_SZELEM-1));
+- return SQLITE_OK;
+- }
+- h = BITVEC_HASH(i++);
+- /* if there wasn't a hash collision, and this doesn't */
+- /* completely fill the hash, then just add it without */
+- /* worring about sub-dividing and re-hashing. */
+- if( !p->u.aHash[h] ){
+- if (p->nSet<(BITVEC_NINT-1)) {
+- goto bitvec_set_end;
+- } else {
+- goto bitvec_set_rehash;
++#endif
++ winLogIoerr(cnt, __LINE__);
++
++ OSTRACE(("OPEN file=%p, name=%s, access=%lx, rc=%s\n", h, zUtf8Name,
++ dwDesiredAccess, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok"));
++
++ if( h==INVALID_HANDLE_VALUE ){
++ pFile->lastErrno = lastErrno;
++ winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name);
++ sqlite3_free(zConverted);
++ sqlite3_free(zTmpname);
++ if( isReadWrite && !isExclusive ){
++ return winOpen(pVfs, zName, id,
++ ((flags|SQLITE_OPEN_READONLY) &
++ ~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)),
++ pOutFlags);
++ }else{
++ return SQLITE_CANTOPEN_BKPT;
+ }
+ }
+- /* there was a collision, check to see if it's already */
+- /* in hash, if not, try to find a spot for it */
+- do {
+- if( p->u.aHash[h]==i ) return SQLITE_OK;
+- h++;
+- if( h>=BITVEC_NINT ) h = 0;
+- } while( p->u.aHash[h] );
+- /* we didn't find it in the hash. h points to the first */
+- /* available free spot. check to see if this is going to */
+- /* make our hash too "full". */
+-bitvec_set_rehash:
+- if( p->nSet>=BITVEC_MXHASH ){
+- unsigned int j;
+- int rc;
+- u32 *aiValues = sqlite3StackAllocRaw(0, sizeof(p->u.aHash));
+- if( aiValues==0 ){
+- return SQLITE_NOMEM;
++
++ if( pOutFlags ){
++ if( isReadWrite ){
++ *pOutFlags = SQLITE_OPEN_READWRITE;
+ }else{
+- memcpy(aiValues, p->u.aHash, sizeof(p->u.aHash));
+- memset(p->u.apSub, 0, sizeof(p->u.apSub));
+- p->iDivisor = (p->iSize + BITVEC_NPTR - 1)/BITVEC_NPTR;
+- rc = sqlite3BitvecSet(p, i);
+- for(j=0; j<BITVEC_NINT; j++){
+- if( aiValues[j] ) rc |= sqlite3BitvecSet(p, aiValues[j]);
+- }
+- sqlite3StackFree(0, aiValues);
+- return rc;
++ *pOutFlags = SQLITE_OPEN_READONLY;
+ }
+ }
+-bitvec_set_end:
+- p->nSet++;
+- p->u.aHash[h] = i;
+- return SQLITE_OK;
+-}
+
+-/*
+-** Clear the i-th bit.
+-**
+-** pBuf must be a pointer to at least BITVEC_SZ bytes of temporary storage
+-** that BitvecClear can use to rebuilt its hash table.
+-*/
+-SQLITE_PRIVATE void sqlite3BitvecClear(Bitvec *p, u32 i, void *pBuf){
+- if( p==0 ) return;
+- assert( i>0 );
+- i--;
+- while( p->iDivisor ){
+- u32 bin = i/p->iDivisor;
+- i = i%p->iDivisor;
+- p = p->u.apSub[bin];
+- if (!p) {
+- return;
+- }
++ OSTRACE(("OPEN file=%p, name=%s, access=%lx, pOutFlags=%p, *pOutFlags=%d, "
++ "rc=%s\n", h, zUtf8Name, dwDesiredAccess, pOutFlags, pOutFlags ?
++ *pOutFlags : 0, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok"));
++
++#if SQLITE_OS_WINCE
++ if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB
++ && (rc = winceCreateLock(zName, pFile))!=SQLITE_OK
++ ){
++ osCloseHandle(h);
++ sqlite3_free(zConverted);
++ sqlite3_free(zTmpname);
++ OSTRACE(("OPEN-CE-LOCK name=%s, rc=%s\n", zName, sqlite3ErrName(rc)));
++ return rc;
+ }
+- if( p->iSize<=BITVEC_NBIT ){
+- p->u.aBitmap[i/BITVEC_SZELEM] &= ~(1 << (i&(BITVEC_SZELEM-1)));
+- }else{
+- unsigned int j;
+- u32 *aiValues = pBuf;
+- memcpy(aiValues, p->u.aHash, sizeof(p->u.aHash));
+- memset(p->u.aHash, 0, sizeof(p->u.aHash));
+- p->nSet = 0;
+- for(j=0; j<BITVEC_NINT; j++){
+- if( aiValues[j] && aiValues[j]!=(i+1) ){
+- u32 h = BITVEC_HASH(aiValues[j]-1);
+- p->nSet++;
+- while( p->u.aHash[h] ){
+- h++;
+- if( h>=BITVEC_NINT ) h = 0;
+- }
+- p->u.aHash[h] = aiValues[j];
+- }
+- }
++ if( isTemp ){
++ pFile->zDeleteOnClose = zConverted;
++ }else
++#endif
++ {
++ sqlite3_free(zConverted);
+ }
+-}
+
+-/*
+-** Destroy a bitmap object. Reclaim all memory used.
+-*/
+-SQLITE_PRIVATE void sqlite3BitvecDestroy(Bitvec *p){
+- if( p==0 ) return;
+- if( p->iDivisor ){
+- unsigned int i;
+- for(i=0; i<BITVEC_NPTR; i++){
+- sqlite3BitvecDestroy(p->u.apSub[i]);
+- }
++ sqlite3_free(zTmpname);
++ pFile->pMethod = &winIoMethod;
++ pFile->pVfs = pVfs;
++ pFile->h = h;
++ if( isReadonly ){
++ pFile->ctrlFlags |= WINFILE_RDONLY;
+ }
+- sqlite3_free(p);
+-}
++ if( sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE) ){
++ pFile->ctrlFlags |= WINFILE_PSOW;
++ }
++ pFile->lastErrno = NO_ERROR;
++ pFile->zPath = zName;
++#if SQLITE_MAX_MMAP_SIZE>0
++ pFile->hMap = NULL;
++ pFile->pMapRegion = 0;
++ pFile->mmapSize = 0;
++ pFile->mmapSizeActual = 0;
++ pFile->mmapSizeMax = sqlite3GlobalConfig.szMmap;
++#endif
+
+-/*
+-** Return the value of the iSize parameter specified when Bitvec *p
+-** was created.
+-*/
+-SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec *p){
+- return p->iSize;
++ OpenCounter(+1);
++ return rc;
+ }
+
+-#ifndef SQLITE_OMIT_BUILTIN_TEST
+-/*
+-** Let V[] be an array of unsigned characters sufficient to hold
+-** up to N bits. Let I be an integer between 0 and N. 0<=I<N.
+-** Then the following macros can be used to set, clear, or test
+-** individual bits within V.
+-*/
+-#define SETBIT(V,I) V[I>>3] |= (1<<(I&7))
+-#define CLEARBIT(V,I) V[I>>3] &= ~(1<<(I&7))
+-#define TESTBIT(V,I) (V[I>>3]&(1<<(I&7)))!=0
+-
+ /*
+-** This routine runs an extensive test of the Bitvec code.
+-**
+-** The input is an array of integers that acts as a program
+-** to test the Bitvec. The integers are opcodes followed
+-** by 0, 1, or 3 operands, depending on the opcode. Another
+-** opcode follows immediately after the last operand.
+-**
+-** There are 6 opcodes numbered from 0 through 5. 0 is the
+-** "halt" opcode and causes the test to end.
+-**
+-** 0 Halt and return the number of errors
+-** 1 N S X Set N bits beginning with S and incrementing by X
+-** 2 N S X Clear N bits beginning with S and incrementing by X
+-** 3 N Set N randomly chosen bits
+-** 4 N Clear N randomly chosen bits
+-** 5 N S X Set N bits from S increment X in array only, not in bitvec
+-**
+-** The opcodes 1 through 4 perform set and clear operations are performed
+-** on both a Bitvec object and on a linear array of bits obtained from malloc.
+-** Opcode 5 works on the linear array only, not on the Bitvec.
+-** Opcode 5 is used to deliberately induce a fault in order to
+-** confirm that error detection works.
+-**
+-** At the conclusion of the test the linear array is compared
+-** against the Bitvec object. If there are any differences,
+-** an error is returned. If they are the same, zero is returned.
++** Delete the named file.
+ **
+-** If a memory allocation error occurs, return -1.
++** Note that Windows does not allow a file to be deleted if some other
++** process has it open. Sometimes a virus scanner or indexing program
++** will open a journal file shortly after it is created in order to do
++** whatever it does. While this other process is holding the
++** file open, we will be unable to delete it. To work around this
++** problem, we delay 100 milliseconds and try to delete again. Up
++** to MX_DELETION_ATTEMPTs deletion attempts are run before giving
++** up and returning an error.
+ */
+-SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int sz, int *aOp){
+- Bitvec *pBitvec = 0;
+- unsigned char *pV = 0;
+- int rc = -1;
+- int i, nx, pc, op;
+- void *pTmpSpace;
+-
+- /* Allocate the Bitvec to be tested and a linear array of
+- ** bits to act as the reference */
+- pBitvec = sqlite3BitvecCreate( sz );
+- pV = sqlite3MallocZero( (sz+7)/8 + 1 );
+- pTmpSpace = sqlite3_malloc64(BITVEC_SZ);
+- if( pBitvec==0 || pV==0 || pTmpSpace==0 ) goto bitvec_end;
++static int winDelete(
++ sqlite3_vfs *pVfs, /* Not used on win32 */
++ const char *zFilename, /* Name of file to delete */
++ int syncDir /* Not used on win32 */
++){
++ int cnt = 0;
++ int rc;
++ DWORD attr;
++ DWORD lastErrno = 0;
++ void *zConverted;
++ UNUSED_PARAMETER(pVfs);
++ UNUSED_PARAMETER(syncDir);
+
+- /* NULL pBitvec tests */
+- sqlite3BitvecSet(0, 1);
+- sqlite3BitvecClear(0, 1, pTmpSpace);
++ SimulateIOError(return SQLITE_IOERR_DELETE);
++ OSTRACE(("DELETE name=%s, syncDir=%d\n", zFilename, syncDir));
+
+- /* Run the program */
+- pc = 0;
+- while( (op = aOp[pc])!=0 ){
+- switch( op ){
+- case 1:
+- case 2:
+- case 5: {
+- nx = 4;
+- i = aOp[pc+2] - 1;
+- aOp[pc+2] += aOp[pc+3];
++ zConverted = winConvertFromUtf8Filename(zFilename);
++ if( zConverted==0 ){
++ OSTRACE(("DELETE name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename));
++ return SQLITE_IOERR_NOMEM;
++ }
++ if( osIsNT() ){
++ do {
++#if SQLITE_OS_WINRT
++ WIN32_FILE_ATTRIBUTE_DATA sAttrData;
++ memset(&sAttrData, 0, sizeof(sAttrData));
++ if ( osGetFileAttributesExW(zConverted, GetFileExInfoStandard,
++ &sAttrData) ){
++ attr = sAttrData.dwFileAttributes;
++ }else{
++ lastErrno = osGetLastError();
++ if( lastErrno==ERROR_FILE_NOT_FOUND
++ || lastErrno==ERROR_PATH_NOT_FOUND ){
++ rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */
++ }else{
++ rc = SQLITE_ERROR;
++ }
+ break;
+ }
+- case 3:
+- case 4:
+- default: {
+- nx = 2;
+- sqlite3_randomness(sizeof(i), &i);
++#else
++ attr = osGetFileAttributesW(zConverted);
++#endif
++ if ( attr==INVALID_FILE_ATTRIBUTES ){
++ lastErrno = osGetLastError();
++ if( lastErrno==ERROR_FILE_NOT_FOUND
++ || lastErrno==ERROR_PATH_NOT_FOUND ){
++ rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */
++ }else{
++ rc = SQLITE_ERROR;
++ }
+ break;
+ }
+- }
+- if( (--aOp[pc+1]) > 0 ) nx = 0;
+- pc += nx;
+- i = (i & 0x7fffffff)%sz;
+- if( (op & 1)!=0 ){
+- SETBIT(pV, (i+1));
+- if( op!=5 ){
+- if( sqlite3BitvecSet(pBitvec, i+1) ) goto bitvec_end;
++ if ( attr&FILE_ATTRIBUTE_DIRECTORY ){
++ rc = SQLITE_ERROR; /* Files only. */
++ break;
+ }
+- }else{
+- CLEARBIT(pV, (i+1));
+- sqlite3BitvecClear(pBitvec, i+1, pTmpSpace);
+- }
++ if ( osDeleteFileW(zConverted) ){
++ rc = SQLITE_OK; /* Deleted OK. */
++ break;
++ }
++ if ( !winRetryIoerr(&cnt, &lastErrno) ){
++ rc = SQLITE_ERROR; /* No more retries. */
++ break;
++ }
++ } while(1);
++ }
++#ifdef SQLITE_WIN32_HAS_ANSI
++ else{
++ do {
++ attr = osGetFileAttributesA(zConverted);
++ if ( attr==INVALID_FILE_ATTRIBUTES ){
++ lastErrno = osGetLastError();
++ if( lastErrno==ERROR_FILE_NOT_FOUND
++ || lastErrno==ERROR_PATH_NOT_FOUND ){
++ rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */
++ }else{
++ rc = SQLITE_ERROR;
++ }
++ break;
++ }
++ if ( attr&FILE_ATTRIBUTE_DIRECTORY ){
++ rc = SQLITE_ERROR; /* Files only. */
++ break;
++ }
++ if ( osDeleteFileA(zConverted) ){
++ rc = SQLITE_OK; /* Deleted OK. */
++ break;
++ }
++ if ( !winRetryIoerr(&cnt, &lastErrno) ){
++ rc = SQLITE_ERROR; /* No more retries. */
++ break;
++ }
++ } while(1);
+ }
+-
+- /* Test to make sure the linear array exactly matches the
+- ** Bitvec object. Start with the assumption that they do
+- ** match (rc==0). Change rc to non-zero if a discrepancy
+- ** is found.
+- */
+- rc = sqlite3BitvecTest(0,0) + sqlite3BitvecTest(pBitvec, sz+1)
+- + sqlite3BitvecTest(pBitvec, 0)
+- + (sqlite3BitvecSize(pBitvec) - sz);
+- for(i=1; i<=sz; i++){
+- if( (TESTBIT(pV,i))!=sqlite3BitvecTest(pBitvec,i) ){
+- rc = i;
+- break;
+- }
++#endif
++ if( rc && rc!=SQLITE_IOERR_DELETE_NOENT ){
++ rc = winLogError(SQLITE_IOERR_DELETE, lastErrno, "winDelete", zFilename);
++ }else{
++ winLogIoerr(cnt, __LINE__);
+ }
+-
+- /* Free allocated structure */
+-bitvec_end:
+- sqlite3_free(pTmpSpace);
+- sqlite3_free(pV);
+- sqlite3BitvecDestroy(pBitvec);
++ sqlite3_free(zConverted);
++ OSTRACE(("DELETE name=%s, rc=%s\n", zFilename, sqlite3ErrName(rc)));
+ return rc;
+ }
+-#endif /* SQLITE_OMIT_BUILTIN_TEST */
+-
+-/************** End of bitvec.c **********************************************/
+-/************** Begin file pcache.c ******************************************/
+-/*
+-** 2008 August 05
+-**
+-** 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 that page cache.
+-*/
+
+ /*
+-** A complete page cache is an instance of this structure.
++** Check the existence and status of a file.
+ */
+-struct PCache {
+- PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */
+- PgHdr *pSynced; /* Last synced page in dirty page list */
+- int nRef; /* Number of referenced pages */
+- int szCache; /* Configured cache size */
+- int szPage; /* Size of every page in this cache */
+- int szExtra; /* Size of extra space for each page */
+- u8 bPurgeable; /* True if pages are on backing store */
+- u8 eCreate; /* eCreate value for for xFetch() */
+- int (*xStress)(void*,PgHdr*); /* Call to try make a page clean */
+- void *pStress; /* Argument to xStress */
+- sqlite3_pcache *pCache; /* Pluggable cache module */
+- PgHdr *pPage1; /* Reference to page 1 */
+-};
+-
+-/********************************** Linked List Management ********************/
+-
+-/* Allowed values for second argument to pcacheManageDirtyList() */
+-#define PCACHE_DIRTYLIST_REMOVE 1 /* Remove pPage from dirty list */
+-#define PCACHE_DIRTYLIST_ADD 2 /* Add pPage to the dirty list */
+-#define PCACHE_DIRTYLIST_FRONT 3 /* Move pPage to the front of the list */
++static int winAccess(
++ sqlite3_vfs *pVfs, /* Not used on win32 */
++ const char *zFilename, /* Name of file to check */
++ int flags, /* Type of test to make on this file */
++ int *pResOut /* OUT: Result */
++){
++ DWORD attr;
++ int rc = 0;
++ DWORD lastErrno = 0;
++ void *zConverted;
++ UNUSED_PARAMETER(pVfs);
+
+-/*
+-** Manage pPage's participation on the dirty list. Bits of the addRemove
+-** argument determines what operation to do. The 0x01 bit means first
+-** remove pPage from the dirty list. The 0x02 means add pPage back to
+-** the dirty list. Doing both moves pPage to the front of the dirty list.
+-*/
+-static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
+- PCache *p = pPage->pCache;
++ SimulateIOError( return SQLITE_IOERR_ACCESS; );
++ OSTRACE(("ACCESS name=%s, flags=%x, pResOut=%p\n",
++ zFilename, flags, pResOut));
+
+- if( addRemove & PCACHE_DIRTYLIST_REMOVE ){
+- assert( pPage->pDirtyNext || pPage==p->pDirtyTail );
+- assert( pPage->pDirtyPrev || pPage==p->pDirty );
+-
+- /* Update the PCache1.pSynced variable if necessary. */
+- if( p->pSynced==pPage ){
+- PgHdr *pSynced = pPage->pDirtyPrev;
+- while( pSynced && (pSynced->flags&PGHDR_NEED_SYNC) ){
+- pSynced = pSynced->pDirtyPrev;
+- }
+- p->pSynced = pSynced;
+- }
+-
+- if( pPage->pDirtyNext ){
+- pPage->pDirtyNext->pDirtyPrev = pPage->pDirtyPrev;
+- }else{
+- assert( pPage==p->pDirtyTail );
+- p->pDirtyTail = pPage->pDirtyPrev;
+- }
+- if( pPage->pDirtyPrev ){
+- pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext;
+- }else{
+- assert( pPage==p->pDirty );
+- p->pDirty = pPage->pDirtyNext;
+- if( p->pDirty==0 && p->bPurgeable ){
+- assert( p->eCreate==1 );
+- p->eCreate = 2;
+- }
+- }
+- pPage->pDirtyNext = 0;
+- pPage->pDirtyPrev = 0;
++ zConverted = winConvertFromUtf8Filename(zFilename);
++ if( zConverted==0 ){
++ OSTRACE(("ACCESS name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename));
++ return SQLITE_IOERR_NOMEM;
+ }
+- if( addRemove & PCACHE_DIRTYLIST_ADD ){
+- assert( pPage->pDirtyNext==0 && pPage->pDirtyPrev==0 && p->pDirty!=pPage );
+-
+- pPage->pDirtyNext = p->pDirty;
+- if( pPage->pDirtyNext ){
+- assert( pPage->pDirtyNext->pDirtyPrev==0 );
+- pPage->pDirtyNext->pDirtyPrev = pPage;
++ if( osIsNT() ){
++ int cnt = 0;
++ WIN32_FILE_ATTRIBUTE_DATA sAttrData;
++ memset(&sAttrData, 0, sizeof(sAttrData));
++ while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted,
++ GetFileExInfoStandard,
++ &sAttrData)) && winRetryIoerr(&cnt, &lastErrno) ){}
++ if( rc ){
++ /* For an SQLITE_ACCESS_EXISTS query, treat a zero-length file
++ ** as if it does not exist.
++ */
++ if( flags==SQLITE_ACCESS_EXISTS
++ && sAttrData.nFileSizeHigh==0
++ && sAttrData.nFileSizeLow==0 ){
++ attr = INVALID_FILE_ATTRIBUTES;
++ }else{
++ attr = sAttrData.dwFileAttributes;
++ }
+ }else{
+- p->pDirtyTail = pPage;
+- if( p->bPurgeable ){
+- assert( p->eCreate==2 );
+- p->eCreate = 1;
++ winLogIoerr(cnt, __LINE__);
++ if( lastErrno!=ERROR_FILE_NOT_FOUND && lastErrno!=ERROR_PATH_NOT_FOUND ){
++ sqlite3_free(zConverted);
++ return winLogError(SQLITE_IOERR_ACCESS, lastErrno, "winAccess",
++ zFilename);
++ }else{
++ attr = INVALID_FILE_ATTRIBUTES;
+ }
+ }
+- p->pDirty = pPage;
+- if( !p->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) ){
+- p->pSynced = pPage;
+- }
+- }
+-}
+-
+-/*
+-** Wrapper around the pluggable caches xUnpin method. If the cache is
+-** being used for an in-memory database, this function is a no-op.
+-*/
+-static void pcacheUnpin(PgHdr *p){
+- if( p->pCache->bPurgeable ){
+- if( p->pgno==1 ){
+- p->pCache->pPage1 = 0;
+- }
+- sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 0);
+- }
+-}
+-
+-/*
+-** Compute the number of pages of cache requested. p->szCache is the
+-** cache size requested by the "PRAGMA cache_size" statement.
+-**
+-**
+-*/
+-static int numberOfCachePages(PCache *p){
+- if( p->szCache>=0 ){
+- /* IMPLEMENTATION-OF: R-42059-47211 If the argument N is positive then the
+- ** suggested cache size is set to N. */
+- return p->szCache;
+- }else{
+- /* IMPLEMENTATION-OF: R-61436-13639 If the argument N is negative, then
+- ** the number of cache pages is adjusted to use approximately abs(N*1024)
+- ** bytes of memory. */
+- return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra));
+ }
+-}
+-
+-/*************************************************** General Interfaces ******
+-**
+-** Initialize and shutdown the page cache subsystem. Neither of these
+-** functions are threadsafe.
+-*/
+-SQLITE_PRIVATE int sqlite3PcacheInitialize(void){
+- if( sqlite3GlobalConfig.pcache2.xInit==0 ){
+- /* IMPLEMENTATION-OF: R-26801-64137 If the xInit() method is NULL, then the
+- ** built-in default page cache is used instead of the application defined
+- ** page cache. */
+- sqlite3PCacheSetDefault();
++#ifdef SQLITE_WIN32_HAS_ANSI
++ else{
++ attr = osGetFileAttributesA((char*)zConverted);
+ }
+- return sqlite3GlobalConfig.pcache2.xInit(sqlite3GlobalConfig.pcache2.pArg);
+-}
+-SQLITE_PRIVATE void sqlite3PcacheShutdown(void){
+- if( sqlite3GlobalConfig.pcache2.xShutdown ){
+- /* IMPLEMENTATION-OF: R-26000-56589 The xShutdown() method may be NULL. */
+- sqlite3GlobalConfig.pcache2.xShutdown(sqlite3GlobalConfig.pcache2.pArg);
++#endif
++ sqlite3_free(zConverted);
++ switch( flags ){
++ case SQLITE_ACCESS_READ:
++ case SQLITE_ACCESS_EXISTS:
++ rc = attr!=INVALID_FILE_ATTRIBUTES;
++ break;
++ case SQLITE_ACCESS_READWRITE:
++ rc = attr!=INVALID_FILE_ATTRIBUTES &&
++ (attr & FILE_ATTRIBUTE_READONLY)==0;
++ break;
++ default:
++ assert(!"Invalid flags argument");
+ }
++ *pResOut = rc;
++ OSTRACE(("ACCESS name=%s, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n",
++ zFilename, pResOut, *pResOut));
++ return SQLITE_OK;
+ }
+
+ /*
+-** Return the size in bytes of a PCache object.
+-*/
+-SQLITE_PRIVATE int sqlite3PcacheSize(void){ return sizeof(PCache); }
+-
+-/*
+-** Create a new PCache object. Storage space to hold the object
+-** has already been allocated and is passed in as the p pointer.
+-** The caller discovers how much space needs to be allocated by
+-** calling sqlite3PcacheSize().
++** Returns non-zero if the specified path name starts with a drive letter
++** followed by a colon character.
+ */
+-SQLITE_PRIVATE int sqlite3PcacheOpen(
+- int szPage, /* Size of every page */
+- int szExtra, /* Extra space associated with each page */
+- int bPurgeable, /* True if pages are on backing store */
+- int (*xStress)(void*,PgHdr*),/* Call to try to make pages clean */
+- void *pStress, /* Argument to xStress */
+- PCache *p /* Preallocated space for the PCache */
++static BOOL winIsDriveLetterAndColon(
++ const char *zPathname
+ ){
+- memset(p, 0, sizeof(PCache));
+- p->szPage = 1;
+- p->szExtra = szExtra;
+- p->bPurgeable = bPurgeable;
+- p->eCreate = 2;
+- p->xStress = xStress;
+- p->pStress = pStress;
+- p->szCache = 100;
+- return sqlite3PcacheSetPageSize(p, szPage);
+-}
+-
+-/*
+-** Change the page size for PCache object. The caller must ensure that there
+-** are no outstanding page references when this function is called.
+-*/
+-SQLITE_PRIVATE int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
+- assert( pCache->nRef==0 && pCache->pDirty==0 );
+- if( pCache->szPage ){
+- sqlite3_pcache *pNew;
+- pNew = sqlite3GlobalConfig.pcache2.xCreate(
+- szPage, pCache->szExtra + ROUND8(sizeof(PgHdr)),
+- pCache->bPurgeable
+- );
+- if( pNew==0 ) return SQLITE_NOMEM;
+- sqlite3GlobalConfig.pcache2.xCachesize(pNew, numberOfCachePages(pCache));
+- if( pCache->pCache ){
+- sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
+- }
+- pCache->pCache = pNew;
+- pCache->pPage1 = 0;
+- pCache->szPage = szPage;
+- }
+- return SQLITE_OK;
++ return ( sqlite3Isalpha(zPathname[0]) && zPathname[1]==':' );
+ }
+
+ /*
+-** Try to obtain a page from the cache.
+-**
+-** This routine returns a pointer to an sqlite3_pcache_page object if
+-** such an object is already in cache, or if a new one is created.
+-** This routine returns a NULL pointer if the object was not in cache
+-** and could not be created.
+-**
+-** The createFlags should be 0 to check for existing pages and should
+-** be 3 (not 1, but 3) to try to create a new page.
+-**
+-** If the createFlag is 0, then NULL is always returned if the page
+-** is not already in the cache. If createFlag is 1, then a new page
+-** is created only if that can be done without spilling dirty pages
+-** and without exceeding the cache size limit.
+-**
+-** The caller needs to invoke sqlite3PcacheFetchFinish() to properly
+-** initialize the sqlite3_pcache_page object and convert it into a
+-** PgHdr object. The sqlite3PcacheFetch() and sqlite3PcacheFetchFinish()
+-** routines are split this way for performance reasons. When separated
+-** they can both (usually) operate without having to push values to
+-** the stack on entry and pop them back off on exit, which saves a
+-** lot of pushing and popping.
++** Returns non-zero if the specified path name should be used verbatim. If
++** non-zero is returned from this function, the calling function must simply
++** use the provided path name verbatim -OR- resolve it into a full path name
++** using the GetFullPathName Win32 API function (if available).
+ */
+-SQLITE_PRIVATE sqlite3_pcache_page *sqlite3PcacheFetch(
+- PCache *pCache, /* Obtain the page from this cache */
+- Pgno pgno, /* Page number to obtain */
+- int createFlag /* If true, create page if it does not exist already */
++static BOOL winIsVerbatimPathname(
++ const char *zPathname
+ ){
+- int eCreate;
++ /*
++ ** If the path name starts with a forward slash or a backslash, it is either
++ ** a legal UNC name, a volume relative path, or an absolute path name in the
++ ** "Unix" format on Windows. There is no easy way to differentiate between
++ ** the final two cases; therefore, we return the safer return value of TRUE
++ ** so that callers of this function will simply use it verbatim.
++ */
++ if ( winIsDirSep(zPathname[0]) ){
++ return TRUE;
++ }
+
+- assert( pCache!=0 );
+- assert( pCache->pCache!=0 );
+- assert( createFlag==3 || createFlag==0 );
+- assert( pgno>0 );
++ /*
++ ** If the path name starts with a letter and a colon it is either a volume
++ ** relative path or an absolute path. Callers of this function must not
++ ** attempt to treat it as a relative path name (i.e. they should simply use
++ ** it verbatim).
++ */
++ if ( winIsDriveLetterAndColon(zPathname) ){
++ return TRUE;
++ }
+
+- /* eCreate defines what to do if the page does not exist.
+- ** 0 Do not allocate a new page. (createFlag==0)
+- ** 1 Allocate a new page if doing so is inexpensive.
+- ** (createFlag==1 AND bPurgeable AND pDirty)
+- ** 2 Allocate a new page even it doing so is difficult.
+- ** (createFlag==1 AND !(bPurgeable AND pDirty)
++ /*
++ ** If we get to this point, the path name should almost certainly be a purely
++ ** relative one (i.e. not a UNC name, not absolute, and not volume relative).
+ */
+- eCreate = createFlag & pCache->eCreate;
+- assert( eCreate==0 || eCreate==1 || eCreate==2 );
+- assert( createFlag==0 || pCache->eCreate==eCreate );
+- assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) );
+- return sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
++ return FALSE;
+ }
+
+ /*
+-** If the sqlite3PcacheFetch() routine is unable to allocate a new
+-** page because new clean pages are available for reuse and the cache
+-** size limit has been reached, then this routine can be invoked to
+-** try harder to allocate a page. This routine might invoke the stress
+-** callback to spill dirty pages to the journal. It will then try to
+-** allocate the new page and will only fail to allocate a new page on
+-** an OOM error.
+-**
+-** This routine should be invoked only after sqlite3PcacheFetch() fails.
++** Turn a relative pathname into a full pathname. Write the full
++** pathname into zOut[]. zOut[] will be at least pVfs->mxPathname
++** bytes in size.
+ */
+-SQLITE_PRIVATE int sqlite3PcacheFetchStress(
+- PCache *pCache, /* Obtain the page from this cache */
+- Pgno pgno, /* Page number to obtain */
+- sqlite3_pcache_page **ppPage /* Write result here */
++static int winFullPathname(
++ sqlite3_vfs *pVfs, /* Pointer to vfs object */
++ const char *zRelative, /* Possibly relative input path */
++ int nFull, /* Size of output buffer in bytes */
++ char *zFull /* Output buffer */
+ ){
+- PgHdr *pPg;
+- if( pCache->eCreate==2 ) return 0;
+
+-
+- /* Find a dirty page to write-out and recycle. First try to find a
+- ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC
+- ** cleared), but if that is not possible settle for any other
+- ** unreferenced dirty page.
+- */
+- for(pPg=pCache->pSynced;
+- pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC));
+- pPg=pPg->pDirtyPrev
+- );
+- pCache->pSynced = pPg;
+- if( !pPg ){
+- for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev);
+- }
+- if( pPg ){
+- int rc;
+-#ifdef SQLITE_LOG_CACHE_SPILL
+- sqlite3_log(SQLITE_FULL,
+- "spill page %d making room for %d - cache used: %d/%d",
+- pPg->pgno, pgno,
+- sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache),
+- numberOfCachePages(pCache));
+-#endif
+- rc = pCache->xStress(pCache->pStress, pPg);
+- if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
+- return rc;
++#if defined(__CYGWIN__)
++ SimulateIOError( return SQLITE_ERROR );
++ UNUSED_PARAMETER(nFull);
++ assert( nFull>=pVfs->mxPathname );
++ if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){
++ /*
++ ** NOTE: We are dealing with a relative path name and the data
++ ** directory has been set. Therefore, use it as the basis
++ ** for converting the relative path name to an absolute
++ ** one by prepending the data directory and a slash.
++ */
++ char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 );
++ if( !zOut ){
++ return SQLITE_IOERR_NOMEM;
++ }
++ if( cygwin_conv_path(
++ (osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A) |
++ CCP_RELATIVE, zRelative, zOut, pVfs->mxPathname+1)<0 ){
++ sqlite3_free(zOut);
++ return winLogError(SQLITE_CANTOPEN_CONVPATH, (DWORD)errno,
++ "winFullPathname1", zRelative);
++ }else{
++ char *zUtf8 = winConvertToUtf8Filename(zOut);
++ if( !zUtf8 ){
++ sqlite3_free(zOut);
++ return SQLITE_IOERR_NOMEM;
++ }
++ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s",
++ sqlite3_data_directory, winGetDirSep(), zUtf8);
++ sqlite3_free(zUtf8);
++ sqlite3_free(zOut);
++ }
++ }else{
++ char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 );
++ if( !zOut ){
++ return SQLITE_IOERR_NOMEM;
++ }
++ if( cygwin_conv_path(
++ (osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A),
++ zRelative, zOut, pVfs->mxPathname+1)<0 ){
++ sqlite3_free(zOut);
++ return winLogError(SQLITE_CANTOPEN_CONVPATH, (DWORD)errno,
++ "winFullPathname2", zRelative);
++ }else{
++ char *zUtf8 = winConvertToUtf8Filename(zOut);
++ if( !zUtf8 ){
++ sqlite3_free(zOut);
++ return SQLITE_IOERR_NOMEM;
++ }
++ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zUtf8);
++ sqlite3_free(zUtf8);
++ sqlite3_free(zOut);
+ }
+ }
+- *ppPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2);
+- return *ppPage==0 ? SQLITE_NOMEM : SQLITE_OK;
+-}
++ return SQLITE_OK;
++#endif
+
+-/*
+-** This is a helper routine for sqlite3PcacheFetchFinish()
+-**
+-** In the uncommon case where the page being fetched has not been
+-** initialized, this routine is invoked to do the initialization.
+-** This routine is broken out into a separate function since it
+-** requires extra stack manipulation that can be avoided in the common
+-** case.
+-*/
+-static SQLITE_NOINLINE PgHdr *pcacheFetchFinishWithInit(
+- PCache *pCache, /* Obtain the page from this cache */
+- Pgno pgno, /* Page number obtained */
+- sqlite3_pcache_page *pPage /* Page obtained by prior PcacheFetch() call */
+-){
+- PgHdr *pPgHdr;
+- assert( pPage!=0 );
+- pPgHdr = (PgHdr*)pPage->pExtra;
+- assert( pPgHdr->pPage==0 );
+- memset(pPgHdr, 0, sizeof(PgHdr));
+- pPgHdr->pPage = pPage;
+- pPgHdr->pData = pPage->pBuf;
+- pPgHdr->pExtra = (void *)&pPgHdr[1];
+- memset(pPgHdr->pExtra, 0, pCache->szExtra);
+- pPgHdr->pCache = pCache;
+- pPgHdr->pgno = pgno;
+- return sqlite3PcacheFetchFinish(pCache,pgno,pPage);
+-}
++#if (SQLITE_OS_WINCE || SQLITE_OS_WINRT) && !defined(__CYGWIN__)
++ SimulateIOError( return SQLITE_ERROR );
++ /* WinCE has no concept of a relative pathname, or so I am told. */
++ /* WinRT has no way to convert a relative path to an absolute one. */
++ if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){
++ /*
++ ** NOTE: We are dealing with a relative path name and the data
++ ** directory has been set. Therefore, use it as the basis
++ ** for converting the relative path name to an absolute
++ ** one by prepending the data directory and a backslash.
++ */
++ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s",
++ sqlite3_data_directory, winGetDirSep(), zRelative);
++ }else{
++ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zRelative);
++ }
++ return SQLITE_OK;
++#endif
+
+-/*
+-** This routine converts the sqlite3_pcache_page object returned by
+-** sqlite3PcacheFetch() into an initialized PgHdr object. This routine
+-** must be called after sqlite3PcacheFetch() in order to get a usable
+-** result.
+-*/
+-SQLITE_PRIVATE PgHdr *sqlite3PcacheFetchFinish(
+- PCache *pCache, /* Obtain the page from this cache */
+- Pgno pgno, /* Page number obtained */
+- sqlite3_pcache_page *pPage /* Page obtained by prior PcacheFetch() call */
+-){
+- PgHdr *pPgHdr;
++#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__)
++ DWORD nByte;
++ void *zConverted;
++ char *zOut;
+
+- if( pPage==0 ) return 0;
+- pPgHdr = (PgHdr *)pPage->pExtra;
++ /* If this path name begins with "/X:", where "X" is any alphabetic
++ ** character, discard the initial "/" from the pathname.
++ */
++ if( zRelative[0]=='/' && winIsDriveLetterAndColon(zRelative+1) ){
++ zRelative++;
++ }
+
+- if( !pPgHdr->pPage ){
+- return pcacheFetchFinishWithInit(pCache, pgno, pPage);
++ /* It's odd to simulate an io-error here, but really this is just
++ ** using the io-error infrastructure to test that SQLite handles this
++ ** function failing. This function could fail if, for example, the
++ ** current working directory has been unlinked.
++ */
++ SimulateIOError( return SQLITE_ERROR );
++ if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){
++ /*
++ ** NOTE: We are dealing with a relative path name and the data
++ ** directory has been set. Therefore, use it as the basis
++ ** for converting the relative path name to an absolute
++ ** one by prepending the data directory and a backslash.
++ */
++ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s",
++ sqlite3_data_directory, winGetDirSep(), zRelative);
++ return SQLITE_OK;
+ }
+- if( 0==pPgHdr->nRef ){
+- pCache->nRef++;
++ zConverted = winConvertFromUtf8Filename(zRelative);
++ if( zConverted==0 ){
++ return SQLITE_IOERR_NOMEM;
+ }
+- pPgHdr->nRef++;
+- if( pgno==1 ){
+- pCache->pPage1 = pPgHdr;
++ if( osIsNT() ){
++ LPWSTR zTemp;
++ nByte = osGetFullPathNameW((LPCWSTR)zConverted, 0, 0, 0);
++ if( nByte==0 ){
++ sqlite3_free(zConverted);
++ return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(),
++ "winFullPathname1", zRelative);
++ }
++ nByte += 3;
++ zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) );
++ if( zTemp==0 ){
++ sqlite3_free(zConverted);
++ return SQLITE_IOERR_NOMEM;
++ }
++ nByte = osGetFullPathNameW((LPCWSTR)zConverted, nByte, zTemp, 0);
++ if( nByte==0 ){
++ sqlite3_free(zConverted);
++ sqlite3_free(zTemp);
++ return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(),
++ "winFullPathname2", zRelative);
++ }
++ sqlite3_free(zConverted);
++ zOut = winUnicodeToUtf8(zTemp);
++ sqlite3_free(zTemp);
+ }
+- return pPgHdr;
+-}
+-
+-/*
+-** Decrement the reference count on a page. If the page is clean and the
+-** reference count drops to 0, then it is made eligible for recycling.
+-*/
+-SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
+- assert( p->nRef>0 );
+- p->nRef--;
+- if( p->nRef==0 ){
+- p->pCache->nRef--;
+- if( (p->flags&PGHDR_DIRTY)==0 ){
+- pcacheUnpin(p);
+- }else if( p->pDirtyPrev!=0 ){
+- /* Move the page to the head of the dirty list. */
+- pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
++#ifdef SQLITE_WIN32_HAS_ANSI
++ else{
++ char *zTemp;
++ nByte = osGetFullPathNameA((char*)zConverted, 0, 0, 0);
++ if( nByte==0 ){
++ sqlite3_free(zConverted);
++ return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(),
++ "winFullPathname3", zRelative);
++ }
++ nByte += 3;
++ zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) );
++ if( zTemp==0 ){
++ sqlite3_free(zConverted);
++ return SQLITE_IOERR_NOMEM;
++ }
++ nByte = osGetFullPathNameA((char*)zConverted, nByte, zTemp, 0);
++ if( nByte==0 ){
++ sqlite3_free(zConverted);
++ sqlite3_free(zTemp);
++ return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(),
++ "winFullPathname4", zRelative);
+ }
++ sqlite3_free(zConverted);
++ zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
++ sqlite3_free(zTemp);
+ }
++#endif
++ if( zOut ){
++ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut);
++ sqlite3_free(zOut);
++ return SQLITE_OK;
++ }else{
++ return SQLITE_IOERR_NOMEM;
++ }
++#endif
+ }
+
++#ifndef SQLITE_OMIT_LOAD_EXTENSION
+ /*
+-** Increase the reference count of a supplied page by 1.
+-*/
+-SQLITE_PRIVATE void sqlite3PcacheRef(PgHdr *p){
+- assert(p->nRef>0);
+- p->nRef++;
+-}
+-
+-/*
+-** Drop a page from the cache. There must be exactly one reference to the
+-** page. This function deletes that reference, so after it returns the
+-** page pointed to by p is invalid.
++** Interfaces for opening a shared library, finding entry points
++** within the shared library, and closing the shared library.
+ */
+-SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr *p){
+- assert( p->nRef==1 );
+- if( p->flags&PGHDR_DIRTY ){
+- pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
++static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){
++ HANDLE h;
++#if defined(__CYGWIN__)
++ int nFull = pVfs->mxPathname+1;
++ char *zFull = sqlite3MallocZero( nFull );
++ void *zConverted = 0;
++ if( zFull==0 ){
++ OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0));
++ return 0;
+ }
+- p->pCache->nRef--;
+- if( p->pgno==1 ){
+- p->pCache->pPage1 = 0;
++ if( winFullPathname(pVfs, zFilename, nFull, zFull)!=SQLITE_OK ){
++ sqlite3_free(zFull);
++ OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0));
++ return 0;
+ }
+- sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 1);
+-}
+-
+-/*
+-** Make sure the page is marked as dirty. If it isn't dirty already,
+-** make it so.
+-*/
+-SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr *p){
+- p->flags &= ~PGHDR_DONT_WRITE;
+- assert( p->nRef>0 );
+- if( 0==(p->flags & PGHDR_DIRTY) ){
+- p->flags |= PGHDR_DIRTY;
+- pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD);
++ zConverted = winConvertFromUtf8Filename(zFull);
++ sqlite3_free(zFull);
++#else
++ void *zConverted = winConvertFromUtf8Filename(zFilename);
++ UNUSED_PARAMETER(pVfs);
++#endif
++ if( zConverted==0 ){
++ OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0));
++ return 0;
+ }
+-}
+-
+-/*
+-** Make sure the page is marked as clean. If it isn't clean already,
+-** make it so.
+-*/
+-SQLITE_PRIVATE void sqlite3PcacheMakeClean(PgHdr *p){
+- if( (p->flags & PGHDR_DIRTY) ){
+- pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
+- p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC);
+- if( p->nRef==0 ){
+- pcacheUnpin(p);
+- }
++ if( osIsNT() ){
++#if SQLITE_OS_WINRT
++ h = osLoadPackagedLibrary((LPCWSTR)zConverted, 0);
++#else
++ h = osLoadLibraryW((LPCWSTR)zConverted);
++#endif
+ }
+-}
+-
+-/*
+-** Make every page in the cache clean.
+-*/
+-SQLITE_PRIVATE void sqlite3PcacheCleanAll(PCache *pCache){
+- PgHdr *p;
+- while( (p = pCache->pDirty)!=0 ){
+- sqlite3PcacheMakeClean(p);
++#ifdef SQLITE_WIN32_HAS_ANSI
++ else{
++ h = osLoadLibraryA((char*)zConverted);
+ }
++#endif
++ OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)h));
++ sqlite3_free(zConverted);
++ return (void*)h;
+ }
+-
+-/*
+-** Clear the PGHDR_NEED_SYNC flag from all dirty pages.
+-*/
+-SQLITE_PRIVATE void sqlite3PcacheClearSyncFlags(PCache *pCache){
+- PgHdr *p;
+- for(p=pCache->pDirty; p; p=p->pDirtyNext){
+- p->flags &= ~PGHDR_NEED_SYNC;
+- }
+- pCache->pSynced = pCache->pDirtyTail;
++static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
++ UNUSED_PARAMETER(pVfs);
++ winGetLastErrorMsg(osGetLastError(), nBuf, zBufOut);
+ }
+-
+-/*
+-** Change the page number of page p to newPgno.
+-*/
+-SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
+- PCache *pCache = p->pCache;
+- assert( p->nRef>0 );
+- assert( newPgno>0 );
+- sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno);
+- p->pgno = newPgno;
+- if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){
+- pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
+- }
++static void (*winDlSym(sqlite3_vfs *pVfs,void *pH,const char *zSym))(void){
++ FARPROC proc;
++ UNUSED_PARAMETER(pVfs);
++ proc = osGetProcAddressA((HANDLE)pH, zSym);
++ OSTRACE(("DLSYM handle=%p, symbol=%s, address=%p\n",
++ (void*)pH, zSym, (void*)proc));
++ return (void(*)(void))proc;
+ }
++static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){
++ UNUSED_PARAMETER(pVfs);
++ osFreeLibrary((HANDLE)pHandle);
++ OSTRACE(("DLCLOSE handle=%p\n", (void*)pHandle));
++}
++#else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */
++ #define winDlOpen 0
++ #define winDlError 0
++ #define winDlSym 0
++ #define winDlClose 0
++#endif
++
+
+ /*
+-** Drop every cache entry whose page number is greater than "pgno". The
+-** caller must ensure that there are no outstanding references to any pages
+-** other than page 1 with a page number greater than pgno.
+-**
+-** If there is a reference to page 1 and the pgno parameter passed to this
+-** function is 0, then the data area associated with page 1 is zeroed, but
+-** the page object is not dropped.
++** Write up to nBuf bytes of randomness into zBuf.
+ */
+-SQLITE_PRIVATE void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
+- if( pCache->pCache ){
+- PgHdr *p;
+- PgHdr *pNext;
+- for(p=pCache->pDirty; p; p=pNext){
+- pNext = p->pDirtyNext;
+- /* This routine never gets call with a positive pgno except right
+- ** after sqlite3PcacheCleanAll(). So if there are dirty pages,
+- ** it must be that pgno==0.
+- */
+- assert( p->pgno>0 );
+- if( ALWAYS(p->pgno>pgno) ){
+- assert( p->flags&PGHDR_DIRTY );
+- sqlite3PcacheMakeClean(p);
+- }
+- }
+- if( pgno==0 && pCache->pPage1 ){
+- memset(pCache->pPage1->pData, 0, pCache->szPage);
+- pgno = 1;
+- }
+- sqlite3GlobalConfig.pcache2.xTruncate(pCache->pCache, pgno+1);
++static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
++ int n = 0;
++ UNUSED_PARAMETER(pVfs);
++#if defined(SQLITE_TEST) || defined(SQLITE_OMIT_RANDOMNESS)
++ n = nBuf;
++ memset(zBuf, 0, nBuf);
++#else
++ if( sizeof(SYSTEMTIME)<=nBuf-n ){
++ SYSTEMTIME x;
++ osGetSystemTime(&x);
++ memcpy(&zBuf[n], &x, sizeof(x));
++ n += sizeof(x);
++ }
++ if( sizeof(DWORD)<=nBuf-n ){
++ DWORD pid = osGetCurrentProcessId();
++ memcpy(&zBuf[n], &pid, sizeof(pid));
++ n += sizeof(pid);
++ }
++#if SQLITE_OS_WINRT
++ if( sizeof(ULONGLONG)<=nBuf-n ){
++ ULONGLONG cnt = osGetTickCount64();
++ memcpy(&zBuf[n], &cnt, sizeof(cnt));
++ n += sizeof(cnt);
++ }
++#else
++ if( sizeof(DWORD)<=nBuf-n ){
++ DWORD cnt = osGetTickCount();
++ memcpy(&zBuf[n], &cnt, sizeof(cnt));
++ n += sizeof(cnt);
++ }
++#endif
++ if( sizeof(LARGE_INTEGER)<=nBuf-n ){
++ LARGE_INTEGER i;
++ osQueryPerformanceCounter(&i);
++ memcpy(&zBuf[n], &i, sizeof(i));
++ n += sizeof(i);
++ }
++#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID
++ if( sizeof(UUID)<=nBuf-n ){
++ UUID id;
++ memset(&id, 0, sizeof(UUID));
++ osUuidCreate(&id);
++ memcpy(zBuf, &id, sizeof(UUID));
++ n += sizeof(UUID);
++ }
++ if( sizeof(UUID)<=nBuf-n ){
++ UUID id;
++ memset(&id, 0, sizeof(UUID));
++ osUuidCreateSequential(&id);
++ memcpy(zBuf, &id, sizeof(UUID));
++ n += sizeof(UUID);
+ }
++#endif
++#endif /* defined(SQLITE_TEST) || defined(SQLITE_ZERO_PRNG_SEED) */
++ return n;
+ }
+
+-/*
+-** Close a cache.
+-*/
+-SQLITE_PRIVATE void sqlite3PcacheClose(PCache *pCache){
+- assert( pCache->pCache!=0 );
+- sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
+-}
+
+-/*
+-** Discard the contents of the cache.
++/*
++** Sleep for a little while. Return the amount of time slept.
+ */
+-SQLITE_PRIVATE void sqlite3PcacheClear(PCache *pCache){
+- sqlite3PcacheTruncate(pCache, 0);
++static int winSleep(sqlite3_vfs *pVfs, int microsec){
++ sqlite3_win32_sleep((microsec+999)/1000);
++ UNUSED_PARAMETER(pVfs);
++ return ((microsec+999)/1000)*1000;
+ }
+
+ /*
+-** Merge two lists of pages connected by pDirty and in pgno order.
+-** Do not both fixing the pDirtyPrev pointers.
++** The following variable, if set to a non-zero value, is interpreted as
++** the number of seconds since 1970 and is used to set the result of
++** sqlite3OsCurrentTime() during testing.
+ */
+-static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB){
+- PgHdr result, *pTail;
+- pTail = &result;
+- while( pA && pB ){
+- if( pA->pgno<pB->pgno ){
+- pTail->pDirty = pA;
+- pTail = pA;
+- pA = pA->pDirty;
+- }else{
+- pTail->pDirty = pB;
+- pTail = pB;
+- pB = pB->pDirty;
+- }
+- }
+- if( pA ){
+- pTail->pDirty = pA;
+- }else if( pB ){
+- pTail->pDirty = pB;
+- }else{
+- pTail->pDirty = 0;
+- }
+- return result.pDirty;
+-}
++#ifdef SQLITE_TEST
++SQLITE_API int sqlite3_current_time = 0; /* Fake system time in seconds since 1970. */
++#endif
+
+ /*
+-** Sort the list of pages in accending order by pgno. Pages are
+-** connected by pDirty pointers. The pDirtyPrev pointers are
+-** corrupted by this sort.
++** Find the current time (in Universal Coordinated Time). Write into *piNow
++** the current time and date as a Julian Day number times 86_400_000. In
++** other words, write into *piNow the number of milliseconds since the Julian
++** epoch of noon in Greenwich on November 24, 4714 B.C according to the
++** proleptic Gregorian calendar.
+ **
+-** Since there cannot be more than 2^31 distinct pages in a database,
+-** there cannot be more than 31 buckets required by the merge sorter.
+-** One extra bucket is added to catch overflow in case something
+-** ever changes to make the previous sentence incorrect.
++** On success, return SQLITE_OK. Return SQLITE_ERROR if the time and date
++** cannot be found.
+ */
+-#define N_SORT_BUCKET 32
+-static PgHdr *pcacheSortDirtyList(PgHdr *pIn){
+- PgHdr *a[N_SORT_BUCKET], *p;
+- int i;
+- memset(a, 0, sizeof(a));
+- while( pIn ){
+- p = pIn;
+- pIn = p->pDirty;
+- p->pDirty = 0;
+- for(i=0; ALWAYS(i<N_SORT_BUCKET-1); i++){
+- if( a[i]==0 ){
+- a[i] = p;
+- break;
+- }else{
+- p = pcacheMergeDirtyList(a[i], p);
+- a[i] = 0;
+- }
+- }
+- if( NEVER(i==N_SORT_BUCKET-1) ){
+- /* To get here, there need to be 2^(N_SORT_BUCKET) elements in
+- ** the input list. But that is impossible.
+- */
+- a[i] = pcacheMergeDirtyList(a[i], p);
+- }
++static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){
++ /* FILETIME structure is a 64-bit value representing the number of
++ 100-nanosecond intervals since January 1, 1601 (= JD 2305813.5).
++ */
++ FILETIME ft;
++ static const sqlite3_int64 winFiletimeEpoch = 23058135*(sqlite3_int64)8640000;
++#ifdef SQLITE_TEST
++ static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
++#endif
++ /* 2^32 - to avoid use of LL and warnings in gcc */
++ static const sqlite3_int64 max32BitValue =
++ (sqlite3_int64)2000000000 + (sqlite3_int64)2000000000 +
++ (sqlite3_int64)294967296;
++
++#if SQLITE_OS_WINCE
++ SYSTEMTIME time;
++ osGetSystemTime(&time);
++ /* if SystemTimeToFileTime() fails, it returns zero. */
++ if (!osSystemTimeToFileTime(&time,&ft)){
++ return SQLITE_ERROR;
+ }
+- p = a[0];
+- for(i=1; i<N_SORT_BUCKET; i++){
+- p = pcacheMergeDirtyList(p, a[i]);
++#else
++ osGetSystemTimeAsFileTime( &ft );
++#endif
++
++ *piNow = winFiletimeEpoch +
++ ((((sqlite3_int64)ft.dwHighDateTime)*max32BitValue) +
++ (sqlite3_int64)ft.dwLowDateTime)/(sqlite3_int64)10000;
++
++#ifdef SQLITE_TEST
++ if( sqlite3_current_time ){
++ *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch;
+ }
+- return p;
++#endif
++ UNUSED_PARAMETER(pVfs);
++ return SQLITE_OK;
+ }
+
+ /*
+-** Return a list of all dirty pages in the cache, sorted by page number.
++** Find the current time (in Universal Coordinated Time). Write the
++** current time and date as a Julian Day number into *prNow and
++** return 0. Return 1 if the time and date cannot be found.
+ */
+-SQLITE_PRIVATE PgHdr *sqlite3PcacheDirtyList(PCache *pCache){
+- PgHdr *p;
+- for(p=pCache->pDirty; p; p=p->pDirtyNext){
+- p->pDirty = p->pDirtyNext;
++static int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
++ int rc;
++ sqlite3_int64 i;
++ rc = winCurrentTimeInt64(pVfs, &i);
++ if( !rc ){
++ *prNow = i/86400000.0;
+ }
+- return pcacheSortDirtyList(pCache->pDirty);
++ return rc;
+ }
+
+-/*
+-** Return the total number of referenced pages held by the cache.
++/*
++** The idea is that this function works like a combination of
++** GetLastError() and FormatMessage() on Windows (or errno and
++** strerror_r() on Unix). After an error is returned by an OS
++** function, SQLite calls this function with zBuf pointing to
++** a buffer of nBuf bytes. The OS layer should populate the
++** buffer with a nul-terminated UTF-8 encoded error message
++** describing the last IO error to have occurred within the calling
++** thread.
++**
++** If the error message is too large for the supplied buffer,
++** it should be truncated. The return value of xGetLastError
++** is zero if the error message fits in the buffer, or non-zero
++** otherwise (if the message was truncated). If non-zero is returned,
++** then it is not necessary to include the nul-terminator character
++** in the output buffer.
++**
++** Not supplying an error message will have no adverse effect
++** on SQLite. It is fine to have an implementation that never
++** returns an error message:
++**
++** int xGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
++** assert(zBuf[0]=='\0');
++** return 0;
++** }
++**
++** However if an error message is supplied, it will be incorporated
++** by sqlite into the error message available to the user using
++** sqlite3_errmsg(), possibly making IO errors easier to debug.
+ */
+-SQLITE_PRIVATE int sqlite3PcacheRefCount(PCache *pCache){
+- return pCache->nRef;
++static int winGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
++ UNUSED_PARAMETER(pVfs);
++ return winGetLastErrorMsg(osGetLastError(), nBuf, zBuf);
+ }
+
+ /*
+-** Return the number of references to the page supplied as an argument.
++** Initialize and deinitialize the operating system interface.
+ */
+-SQLITE_PRIVATE int sqlite3PcachePageRefcount(PgHdr *p){
+- return p->nRef;
+-}
++SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void){
++ static sqlite3_vfs winVfs = {
++ 3, /* iVersion */
++ sizeof(winFile), /* szOsFile */
++ SQLITE_WIN32_MAX_PATH_BYTES, /* mxPathname */
++ 0, /* pNext */
++ "win32", /* zName */
++ 0, /* pAppData */
++ winOpen, /* xOpen */
++ winDelete, /* xDelete */
++ winAccess, /* xAccess */
++ winFullPathname, /* xFullPathname */
++ winDlOpen, /* xDlOpen */
++ winDlError, /* xDlError */
++ winDlSym, /* xDlSym */
++ winDlClose, /* xDlClose */
++ winRandomness, /* xRandomness */
++ winSleep, /* xSleep */
++ winCurrentTime, /* xCurrentTime */
++ winGetLastError, /* xGetLastError */
++ winCurrentTimeInt64, /* xCurrentTimeInt64 */
++ winSetSystemCall, /* xSetSystemCall */
++ winGetSystemCall, /* xGetSystemCall */
++ winNextSystemCall, /* xNextSystemCall */
++ };
++#if defined(SQLITE_WIN32_HAS_WIDE)
++ static sqlite3_vfs winLongPathVfs = {
++ 3, /* iVersion */
++ sizeof(winFile), /* szOsFile */
++ SQLITE_WINNT_MAX_PATH_BYTES, /* mxPathname */
++ 0, /* pNext */
++ "win32-longpath", /* zName */
++ 0, /* pAppData */
++ winOpen, /* xOpen */
++ winDelete, /* xDelete */
++ winAccess, /* xAccess */
++ winFullPathname, /* xFullPathname */
++ winDlOpen, /* xDlOpen */
++ winDlError, /* xDlError */
++ winDlSym, /* xDlSym */
++ winDlClose, /* xDlClose */
++ winRandomness, /* xRandomness */
++ winSleep, /* xSleep */
++ winCurrentTime, /* xCurrentTime */
++ winGetLastError, /* xGetLastError */
++ winCurrentTimeInt64, /* xCurrentTimeInt64 */
++ winSetSystemCall, /* xSetSystemCall */
++ winGetSystemCall, /* xGetSystemCall */
++ winNextSystemCall, /* xNextSystemCall */
++ };
++#endif
+
+-/*
+-** Return the total number of pages in the cache.
+-*/
+-SQLITE_PRIVATE int sqlite3PcachePagecount(PCache *pCache){
+- assert( pCache->pCache!=0 );
+- return sqlite3GlobalConfig.pcache2.xPagecount(pCache->pCache);
+-}
++ /* Double-check that the aSyscall[] array has been constructed
++ ** correctly. See ticket [bb3a86e890c8e96ab] */
++ assert( ArraySize(aSyscall)==80 );
+
+-#ifdef SQLITE_TEST
+-/*
+-** Get the suggested cache-size value.
+-*/
+-SQLITE_PRIVATE int sqlite3PcacheGetCachesize(PCache *pCache){
+- return numberOfCachePages(pCache);
+-}
++ /* get memory map allocation granularity */
++ memset(&winSysInfo, 0, sizeof(SYSTEM_INFO));
++#if SQLITE_OS_WINRT
++ osGetNativeSystemInfo(&winSysInfo);
++#else
++ osGetSystemInfo(&winSysInfo);
+ #endif
++ assert( winSysInfo.dwAllocationGranularity>0 );
++ assert( winSysInfo.dwPageSize>0 );
+
+-/*
+-** Set the suggested cache-size value.
+-*/
+-SQLITE_PRIVATE void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){
+- assert( pCache->pCache!=0 );
+- pCache->szCache = mxPage;
+- sqlite3GlobalConfig.pcache2.xCachesize(pCache->pCache,
+- numberOfCachePages(pCache));
+-}
+-
+-/*
+-** Free up as much memory as possible from the page cache.
+-*/
+-SQLITE_PRIVATE void sqlite3PcacheShrink(PCache *pCache){
+- assert( pCache->pCache!=0 );
+- sqlite3GlobalConfig.pcache2.xShrink(pCache->pCache);
+-}
++ sqlite3_vfs_register(&winVfs, 1);
+
+-/*
+-** Return the size of the header added by this middleware layer
+-** in the page-cache hierarchy.
+-*/
+-SQLITE_PRIVATE int sqlite3HeaderSizePcache(void){ return ROUND8(sizeof(PgHdr)); }
++#if defined(SQLITE_WIN32_HAS_WIDE)
++ sqlite3_vfs_register(&winLongPathVfs, 0);
++#endif
+
++ return SQLITE_OK;
++}
+
+-#if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
+-/*
+-** For all dirty pages currently in the cache, invoke the specified
+-** callback. This is only used if the SQLITE_CHECK_PAGES macro is
+-** defined.
+-*/
+-SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *)){
+- PgHdr *pDirty;
+- for(pDirty=pCache->pDirty; pDirty; pDirty=pDirty->pDirtyNext){
+- xIter(pDirty);
++SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void){
++#if SQLITE_OS_WINRT
++ if( sleepObj!=NULL ){
++ osCloseHandle(sleepObj);
++ sleepObj = NULL;
+ }
+-}
+ #endif
++ return SQLITE_OK;
++}
+
+-/************** End of pcache.c **********************************************/
+-/************** Begin file pcache1.c *****************************************/
++#endif /* SQLITE_OS_WIN */
++
++/************** End of os_win.c **********************************************/
++/************** Begin file bitvec.c ******************************************/
+ /*
+-** 2008 November 05
++** 2008 February 16
+ **
+ ** The author disclaims copyright to this source code. In place of
+ ** a legal notice, here is a blessing:
+@@ -39935,1052 +42486,1078 @@
+ ** May you share freely, never taking more than you give.
+ **
+ *************************************************************************
++** This file implements an object that represents a fixed-length
++** bitmap. Bits are numbered starting with 1.
+ **
+-** This file implements the default page cache implementation (the
+-** sqlite3_pcache interface). It also contains part of the implementation
+-** of the SQLITE_CONFIG_PAGECACHE and sqlite3_release_memory() features.
+-** If the default page cache implementation is overridden, then neither of
+-** these two features are available.
+-*/
+-
+-
+-typedef struct PCache1 PCache1;
+-typedef struct PgHdr1 PgHdr1;
+-typedef struct PgFreeslot PgFreeslot;
+-typedef struct PGroup PGroup;
+-
+-/* Each page cache (or PCache) belongs to a PGroup. A PGroup is a set
+-** of one or more PCaches that are able to recycle each other's unpinned
+-** pages when they are under memory pressure. A PGroup is an instance of
+-** the following object.
+-**
+-** This page cache implementation works in one of two modes:
+-**
+-** (1) Every PCache is the sole member of its own PGroup. There is
+-** one PGroup per PCache.
+-**
+-** (2) There is a single global PGroup that all PCaches are a member
+-** of.
++** A bitmap is used to record which pages of a database file have been
++** journalled during a transaction, or which pages have the "dont-write"
++** property. Usually only a few pages are meet either condition.
++** So the bitmap is usually sparse and has low cardinality.
++** But sometimes (for example when during a DROP of a large table) most
++** or all of the pages in a database can get journalled. In those cases,
++** the bitmap becomes dense with high cardinality. The algorithm needs
++** to handle both cases well.
+ **
+-** Mode 1 uses more memory (since PCache instances are not able to rob
+-** unused pages from other PCaches) but it also operates without a mutex,
+-** and is therefore often faster. Mode 2 requires a mutex in order to be
+-** threadsafe, but recycles pages more efficiently.
++** The size of the bitmap is fixed when the object is created.
+ **
+-** For mode (1), PGroup.mutex is NULL. For mode (2) there is only a single
+-** PGroup which is the pcache1.grp global variable and its mutex is
+-** SQLITE_MUTEX_STATIC_LRU.
+-*/
+-struct PGroup {
+- sqlite3_mutex *mutex; /* MUTEX_STATIC_LRU or NULL */
+- unsigned int nMaxPage; /* Sum of nMax for purgeable caches */
+- unsigned int nMinPage; /* Sum of nMin for purgeable caches */
+- unsigned int mxPinned; /* nMaxpage + 10 - nMinPage */
+- unsigned int nCurrentPage; /* Number of purgeable pages allocated */
+- PgHdr1 *pLruHead, *pLruTail; /* LRU list of unpinned pages */
+-};
+-
+-/* Each page cache is an instance of the following object. Every
+-** open database file (including each in-memory database and each
+-** temporary or transient database) has a single page cache which
+-** is an instance of this object.
++** All bits are clear when the bitmap is created. Individual bits
++** may be set or cleared one at a time.
+ **
+-** Pointers to structures of this type are cast and returned as
+-** opaque sqlite3_pcache* handles.
++** Test operations are about 100 times more common that set operations.
++** Clear operations are exceedingly rare. There are usually between
++** 5 and 500 set operations per Bitvec object, though the number of sets can
++** sometimes grow into tens of thousands or larger. The size of the
++** Bitvec object is the number of pages in the database file at the
++** start of a transaction, and is thus usually less than a few thousand,
++** but can be as large as 2 billion for a really big database.
+ */
+-struct PCache1 {
+- /* Cache configuration parameters. Page size (szPage) and the purgeable
+- ** flag (bPurgeable) are set when the cache is created. nMax may be
+- ** modified at any time by a call to the pcache1Cachesize() method.
+- ** The PGroup mutex must be held when accessing nMax.
+- */
+- PGroup *pGroup; /* PGroup this cache belongs to */
+- int szPage; /* Size of allocated pages in bytes */
+- int szExtra; /* Size of extra space in bytes */
+- int bPurgeable; /* True if cache is purgeable */
+- unsigned int nMin; /* Minimum number of pages reserved */
+- unsigned int nMax; /* Configured "cache_size" value */
+- unsigned int n90pct; /* nMax*9/10 */
+- unsigned int iMaxKey; /* Largest key seen since xTruncate() */
+
+- /* Hash table of all pages. The following variables may only be accessed
+- ** when the accessor is holding the PGroup mutex.
+- */
+- unsigned int nRecyclable; /* Number of pages in the LRU list */
+- unsigned int nPage; /* Total number of pages in apHash */
+- unsigned int nHash; /* Number of slots in apHash[] */
+- PgHdr1 **apHash; /* Hash table for fast lookup by key */
+-};
++/* Size of the Bitvec structure in bytes. */
++#define BITVEC_SZ 512
+
+-/*
+-** Each cache entry is represented by an instance of the following
+-** structure. Unless SQLITE_PCACHE_SEPARATE_HEADER is defined, a buffer of
+-** PgHdr1.pCache->szPage bytes is allocated directly before this structure
+-** in memory.
+-*/
+-struct PgHdr1 {
+- sqlite3_pcache_page page;
+- unsigned int iKey; /* Key value (page number) */
+- u8 isPinned; /* Page in use, not on the LRU list */
+- PgHdr1 *pNext; /* Next in hash table chain */
+- PCache1 *pCache; /* Cache that currently owns this page */
+- PgHdr1 *pLruNext; /* Next in LRU list of unpinned pages */
+- PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */
+-};
++/* Round the union size down to the nearest pointer boundary, since that's how
++** it will be aligned within the Bitvec struct. */
++#define BITVEC_USIZE (((BITVEC_SZ-(3*sizeof(u32)))/sizeof(Bitvec*))*sizeof(Bitvec*))
+
+-/*
+-** Free slots in the allocator used to divide up the buffer provided using
+-** the SQLITE_CONFIG_PAGECACHE mechanism.
+-*/
+-struct PgFreeslot {
+- PgFreeslot *pNext; /* Next free slot */
+-};
++/* Type of the array "element" for the bitmap representation.
++** Should be a power of 2, and ideally, evenly divide into BITVEC_USIZE.
++** Setting this to the "natural word" size of your CPU may improve
++** performance. */
++#define BITVEC_TELEM u8
++/* Size, in bits, of the bitmap element. */
++#define BITVEC_SZELEM 8
++/* Number of elements in a bitmap array. */
++#define BITVEC_NELEM (BITVEC_USIZE/sizeof(BITVEC_TELEM))
++/* Number of bits in the bitmap array. */
++#define BITVEC_NBIT (BITVEC_NELEM*BITVEC_SZELEM)
+
+-/*
+-** Global data used by this cache.
+-*/
+-static SQLITE_WSD struct PCacheGlobal {
+- PGroup grp; /* The global PGroup for mode (2) */
++/* Number of u32 values in hash table. */
++#define BITVEC_NINT (BITVEC_USIZE/sizeof(u32))
++/* Maximum number of entries in hash table before
++** sub-dividing and re-hashing. */
++#define BITVEC_MXHASH (BITVEC_NINT/2)
++/* Hashing function for the aHash representation.
++** Empirical testing showed that the *37 multiplier
++** (an arbitrary prime)in the hash function provided
++** no fewer collisions than the no-op *1. */
++#define BITVEC_HASH(X) (((X)*1)%BITVEC_NINT)
+
+- /* Variables related to SQLITE_CONFIG_PAGECACHE settings. The
+- ** szSlot, nSlot, pStart, pEnd, nReserve, and isInit values are all
+- ** fixed at sqlite3_initialize() time and do not require mutex protection.
+- ** The nFreeSlot and pFree values do require mutex protection.
+- */
+- int isInit; /* True if initialized */
+- int szSlot; /* Size of each free slot */
+- int nSlot; /* The number of pcache slots */
+- int nReserve; /* Try to keep nFreeSlot above this */
+- void *pStart, *pEnd; /* Bounds of pagecache malloc range */
+- /* Above requires no mutex. Use mutex below for variable that follow. */
+- sqlite3_mutex *mutex; /* Mutex for accessing the following: */
+- PgFreeslot *pFree; /* Free page blocks */
+- int nFreeSlot; /* Number of unused pcache slots */
+- /* The following value requires a mutex to change. We skip the mutex on
+- ** reading because (1) most platforms read a 32-bit integer atomically and
+- ** (2) even if an incorrect value is read, no great harm is done since this
+- ** is really just an optimization. */
+- int bUnderPressure; /* True if low on PAGECACHE memory */
+-} pcache1_g;
++#define BITVEC_NPTR (BITVEC_USIZE/sizeof(Bitvec *))
+
+-/*
+-** All code in this file should access the global structure above via the
+-** alias "pcache1". This ensures that the WSD emulation is used when
+-** compiling for systems that do not support real WSD.
+-*/
+-#define pcache1 (GLOBAL(struct PCacheGlobal, pcache1_g))
+
+ /*
+-** Macros to enter and leave the PCache LRU mutex.
++** A bitmap is an instance of the following structure.
++**
++** This bitmap records the existence of zero or more bits
++** with values between 1 and iSize, inclusive.
++**
++** There are three possible representations of the bitmap.
++** If iSize<=BITVEC_NBIT, then Bitvec.u.aBitmap[] is a straight
++** bitmap. The least significant bit is bit 1.
++**
++** If iSize>BITVEC_NBIT and iDivisor==0 then Bitvec.u.aHash[] is
++** a hash table that will hold up to BITVEC_MXHASH distinct values.
++**
++** Otherwise, the value i is redirected into one of BITVEC_NPTR
++** sub-bitmaps pointed to by Bitvec.u.apSub[]. Each subbitmap
++** handles up to iDivisor separate values of i. apSub[0] holds
++** values between 1 and iDivisor. apSub[1] holds values between
++** iDivisor+1 and 2*iDivisor. apSub[N] holds values between
++** N*iDivisor+1 and (N+1)*iDivisor. Each subbitmap is normalized
++** to hold deal with values between 1 and iDivisor.
+ */
+-#define pcache1EnterMutex(X) sqlite3_mutex_enter((X)->mutex)
+-#define pcache1LeaveMutex(X) sqlite3_mutex_leave((X)->mutex)
+-
+-/******************************************************************************/
+-/******** Page Allocation/SQLITE_CONFIG_PCACHE Related Functions **************/
++struct Bitvec {
++ u32 iSize; /* Maximum bit index. Max iSize is 4,294,967,296. */
++ u32 nSet; /* Number of bits that are set - only valid for aHash
++ ** element. Max is BITVEC_NINT. For BITVEC_SZ of 512,
++ ** this would be 125. */
++ u32 iDivisor; /* Number of bits handled by each apSub[] entry. */
++ /* Should >=0 for apSub element. */
++ /* Max iDivisor is max(u32) / BITVEC_NPTR + 1. */
++ /* For a BITVEC_SZ of 512, this would be 34,359,739. */
++ union {
++ BITVEC_TELEM aBitmap[BITVEC_NELEM]; /* Bitmap representation */
++ u32 aHash[BITVEC_NINT]; /* Hash table representation */
++ Bitvec *apSub[BITVEC_NPTR]; /* Recursive representation */
++ } u;
++};
+
+ /*
+-** This function is called during initialization if a static buffer is
+-** supplied to use for the page-cache by passing the SQLITE_CONFIG_PAGECACHE
+-** verb to sqlite3_config(). Parameter pBuf points to an allocation large
+-** enough to contain 'n' buffers of 'sz' bytes each.
+-**
+-** This routine is called from sqlite3_initialize() and so it is guaranteed
+-** to be serialized already. There is no need for further mutexing.
++** Create a new bitmap object able to handle bits between 0 and iSize,
++** inclusive. Return a pointer to the new object. Return NULL if
++** malloc fails.
+ */
+-SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
+- if( pcache1.isInit ){
+- PgFreeslot *p;
+- sz = ROUNDDOWN8(sz);
+- pcache1.szSlot = sz;
+- pcache1.nSlot = pcache1.nFreeSlot = n;
+- pcache1.nReserve = n>90 ? 10 : (n/10 + 1);
+- pcache1.pStart = pBuf;
+- pcache1.pFree = 0;
+- pcache1.bUnderPressure = 0;
+- while( n-- ){
+- p = (PgFreeslot*)pBuf;
+- p->pNext = pcache1.pFree;
+- pcache1.pFree = p;
+- pBuf = (void*)&((char*)pBuf)[sz];
+- }
+- pcache1.pEnd = pBuf;
++SQLITE_PRIVATE Bitvec *sqlite3BitvecCreate(u32 iSize){
++ Bitvec *p;
++ assert( sizeof(*p)==BITVEC_SZ );
++ p = sqlite3MallocZero( sizeof(*p) );
++ if( p ){
++ p->iSize = iSize;
+ }
++ return p;
+ }
+
+ /*
+-** Malloc function used within this file to allocate space from the buffer
+-** configured using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no
+-** such buffer exists or there is no space left in it, this function falls
+-** back to sqlite3Malloc().
+-**
+-** Multiple threads can run this routine at the same time. Global variables
+-** in pcache1 need to be protected via mutex.
++** Check to see if the i-th bit is set. Return true or false.
++** If p is NULL (if the bitmap has not been created) or if
++** i is out of range, then return false.
+ */
+-static void *pcache1Alloc(int nByte){
+- void *p = 0;
+- assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
+- if( nByte<=pcache1.szSlot ){
+- sqlite3_mutex_enter(pcache1.mutex);
+- p = (PgHdr1 *)pcache1.pFree;
+- if( p ){
+- pcache1.pFree = pcache1.pFree->pNext;
+- pcache1.nFreeSlot--;
+- pcache1.bUnderPressure = pcache1.nFreeSlot<pcache1.nReserve;
+- assert( pcache1.nFreeSlot>=0 );
+- sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
+- sqlite3StatusUp(SQLITE_STATUS_PAGECACHE_USED, 1);
++SQLITE_PRIVATE int sqlite3BitvecTest(Bitvec *p, u32 i){
++ if( p==0 ) return 0;
++ if( i>p->iSize || i==0 ) return 0;
++ i--;
++ while( p->iDivisor ){
++ u32 bin = i/p->iDivisor;
++ i = i%p->iDivisor;
++ p = p->u.apSub[bin];
++ if (!p) {
++ return 0;
+ }
+- sqlite3_mutex_leave(pcache1.mutex);
+ }
+- if( p==0 ){
+- /* Memory is not available in the SQLITE_CONFIG_PAGECACHE pool. Get
+- ** it from sqlite3Malloc instead.
+- */
+- p = sqlite3Malloc(nByte);
+-#ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
+- if( p ){
+- int sz = sqlite3MallocSize(p);
+- sqlite3_mutex_enter(pcache1.mutex);
+- sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
+- sqlite3StatusUp(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz);
+- sqlite3_mutex_leave(pcache1.mutex);
++ if( p->iSize<=BITVEC_NBIT ){
++ return (p->u.aBitmap[i/BITVEC_SZELEM] & (1<<(i&(BITVEC_SZELEM-1))))!=0;
++ } else{
++ u32 h = BITVEC_HASH(i++);
++ while( p->u.aHash[h] ){
++ if( p->u.aHash[h]==i ) return 1;
++ h = (h+1) % BITVEC_NINT;
+ }
+-#endif
+- sqlite3MemdebugSetType(p, MEMTYPE_PCACHE);
++ return 0;
+ }
+- return p;
+ }
+
+ /*
+-** Free an allocated buffer obtained from pcache1Alloc().
++** Set the i-th bit. Return 0 on success and an error code if
++** anything goes wrong.
++**
++** This routine might cause sub-bitmaps to be allocated. Failing
++** to get the memory needed to hold the sub-bitmap is the only
++** that can go wrong with an insert, assuming p and i are valid.
++**
++** The calling function must ensure that p is a valid Bitvec object
++** and that the value for "i" is within range of the Bitvec object.
++** Otherwise the behavior is undefined.
+ */
+-static int pcache1Free(void *p){
+- int nFreed = 0;
+- if( p==0 ) return 0;
+- if( p>=pcache1.pStart && p<pcache1.pEnd ){
+- PgFreeslot *pSlot;
+- sqlite3_mutex_enter(pcache1.mutex);
+- sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_USED, 1);
+- pSlot = (PgFreeslot*)p;
+- pSlot->pNext = pcache1.pFree;
+- pcache1.pFree = pSlot;
+- pcache1.nFreeSlot++;
+- pcache1.bUnderPressure = pcache1.nFreeSlot<pcache1.nReserve;
+- assert( pcache1.nFreeSlot<=pcache1.nSlot );
+- sqlite3_mutex_leave(pcache1.mutex);
+- }else{
+- assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) );
+- sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
+- nFreed = sqlite3MallocSize(p);
+-#ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
+- sqlite3_mutex_enter(pcache1.mutex);
+- sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_OVERFLOW, nFreed);
+- sqlite3_mutex_leave(pcache1.mutex);
+-#endif
+- sqlite3_free(p);
++SQLITE_PRIVATE int sqlite3BitvecSet(Bitvec *p, u32 i){
++ u32 h;
++ if( p==0 ) return SQLITE_OK;
++ assert( i>0 );
++ assert( i<=p->iSize );
++ i--;
++ while((p->iSize > BITVEC_NBIT) && p->iDivisor) {
++ u32 bin = i/p->iDivisor;
++ i = i%p->iDivisor;
++ if( p->u.apSub[bin]==0 ){
++ p->u.apSub[bin] = sqlite3BitvecCreate( p->iDivisor );
++ if( p->u.apSub[bin]==0 ) return SQLITE_NOMEM;
++ }
++ p = p->u.apSub[bin];
+ }
+- return nFreed;
+-}
+-
+-#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+-/*
+-** Return the size of a pcache allocation
+-*/
+-static int pcache1MemSize(void *p){
+- if( p>=pcache1.pStart && p<pcache1.pEnd ){
+- return pcache1.szSlot;
+- }else{
+- int iSize;
+- assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) );
+- sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
+- iSize = sqlite3MallocSize(p);
+- sqlite3MemdebugSetType(p, MEMTYPE_PCACHE);
+- return iSize;
++ if( p->iSize<=BITVEC_NBIT ){
++ p->u.aBitmap[i/BITVEC_SZELEM] |= 1 << (i&(BITVEC_SZELEM-1));
++ return SQLITE_OK;
+ }
++ h = BITVEC_HASH(i++);
++ /* if there wasn't a hash collision, and this doesn't */
++ /* completely fill the hash, then just add it without */
++ /* worring about sub-dividing and re-hashing. */
++ if( !p->u.aHash[h] ){
++ if (p->nSet<(BITVEC_NINT-1)) {
++ goto bitvec_set_end;
++ } else {
++ goto bitvec_set_rehash;
++ }
++ }
++ /* there was a collision, check to see if it's already */
++ /* in hash, if not, try to find a spot for it */
++ do {
++ if( p->u.aHash[h]==i ) return SQLITE_OK;
++ h++;
++ if( h>=BITVEC_NINT ) h = 0;
++ } while( p->u.aHash[h] );
++ /* we didn't find it in the hash. h points to the first */
++ /* available free spot. check to see if this is going to */
++ /* make our hash too "full". */
++bitvec_set_rehash:
++ if( p->nSet>=BITVEC_MXHASH ){
++ unsigned int j;
++ int rc;
++ u32 *aiValues = sqlite3StackAllocRaw(0, sizeof(p->u.aHash));
++ if( aiValues==0 ){
++ return SQLITE_NOMEM;
++ }else{
++ memcpy(aiValues, p->u.aHash, sizeof(p->u.aHash));
++ memset(p->u.apSub, 0, sizeof(p->u.apSub));
++ p->iDivisor = (p->iSize + BITVEC_NPTR - 1)/BITVEC_NPTR;
++ rc = sqlite3BitvecSet(p, i);
++ for(j=0; j<BITVEC_NINT; j++){
++ if( aiValues[j] ) rc |= sqlite3BitvecSet(p, aiValues[j]);
++ }
++ sqlite3StackFree(0, aiValues);
++ return rc;
++ }
++ }
++bitvec_set_end:
++ p->nSet++;
++ p->u.aHash[h] = i;
++ return SQLITE_OK;
+ }
+-#endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */
+
+ /*
+-** Allocate a new page object initially associated with cache pCache.
++** Clear the i-th bit.
++**
++** pBuf must be a pointer to at least BITVEC_SZ bytes of temporary storage
++** that BitvecClear can use to rebuilt its hash table.
+ */
+-static PgHdr1 *pcache1AllocPage(PCache1 *pCache){
+- PgHdr1 *p = 0;
+- void *pPg;
+-
+- /* The group mutex must be released before pcache1Alloc() is called. This
+- ** is because it may call sqlite3_release_memory(), which assumes that
+- ** this mutex is not held. */
+- assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
+- pcache1LeaveMutex(pCache->pGroup);
+-#ifdef SQLITE_PCACHE_SEPARATE_HEADER
+- pPg = pcache1Alloc(pCache->szPage);
+- p = sqlite3Malloc(sizeof(PgHdr1) + pCache->szExtra);
+- if( !pPg || !p ){
+- pcache1Free(pPg);
+- sqlite3_free(p);
+- pPg = 0;
++SQLITE_PRIVATE void sqlite3BitvecClear(Bitvec *p, u32 i, void *pBuf){
++ if( p==0 ) return;
++ assert( i>0 );
++ i--;
++ while( p->iDivisor ){
++ u32 bin = i/p->iDivisor;
++ i = i%p->iDivisor;
++ p = p->u.apSub[bin];
++ if (!p) {
++ return;
++ }
+ }
+-#else
+- pPg = pcache1Alloc(ROUND8(sizeof(PgHdr1)) + pCache->szPage + pCache->szExtra);
+- p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
+-#endif
+- pcache1EnterMutex(pCache->pGroup);
+-
+- if( pPg ){
+- p->page.pBuf = pPg;
+- p->page.pExtra = &p[1];
+- if( pCache->bPurgeable ){
+- pCache->pGroup->nCurrentPage++;
++ if( p->iSize<=BITVEC_NBIT ){
++ p->u.aBitmap[i/BITVEC_SZELEM] &= ~(1 << (i&(BITVEC_SZELEM-1)));
++ }else{
++ unsigned int j;
++ u32 *aiValues = pBuf;
++ memcpy(aiValues, p->u.aHash, sizeof(p->u.aHash));
++ memset(p->u.aHash, 0, sizeof(p->u.aHash));
++ p->nSet = 0;
++ for(j=0; j<BITVEC_NINT; j++){
++ if( aiValues[j] && aiValues[j]!=(i+1) ){
++ u32 h = BITVEC_HASH(aiValues[j]-1);
++ p->nSet++;
++ while( p->u.aHash[h] ){
++ h++;
++ if( h>=BITVEC_NINT ) h = 0;
++ }
++ p->u.aHash[h] = aiValues[j];
++ }
+ }
+- return p;
+ }
+- return 0;
+ }
+
+ /*
+-** Free a page object allocated by pcache1AllocPage().
+-**
+-** The pointer is allowed to be NULL, which is prudent. But it turns out
+-** that the current implementation happens to never call this routine
+-** with a NULL pointer, so we mark the NULL test with ALWAYS().
++** Destroy a bitmap object. Reclaim all memory used.
+ */
+-static void pcache1FreePage(PgHdr1 *p){
+- if( ALWAYS(p) ){
+- PCache1 *pCache = p->pCache;
+- assert( sqlite3_mutex_held(p->pCache->pGroup->mutex) );
+- pcache1Free(p->page.pBuf);
+-#ifdef SQLITE_PCACHE_SEPARATE_HEADER
+- sqlite3_free(p);
+-#endif
+- if( pCache->bPurgeable ){
+- pCache->pGroup->nCurrentPage--;
++SQLITE_PRIVATE void sqlite3BitvecDestroy(Bitvec *p){
++ if( p==0 ) return;
++ if( p->iDivisor ){
++ unsigned int i;
++ for(i=0; i<BITVEC_NPTR; i++){
++ sqlite3BitvecDestroy(p->u.apSub[i]);
+ }
+ }
++ sqlite3_free(p);
+ }
+
+ /*
+-** Malloc function used by SQLite to obtain space from the buffer configured
+-** using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no such buffer
+-** exists, this function falls back to sqlite3Malloc().
++** Return the value of the iSize parameter specified when Bitvec *p
++** was created.
+ */
+-SQLITE_PRIVATE void *sqlite3PageMalloc(int sz){
+- return pcache1Alloc(sz);
++SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec *p){
++ return p->iSize;
+ }
+
++#ifndef SQLITE_OMIT_BUILTIN_TEST
+ /*
+-** Free an allocated buffer obtained from sqlite3PageMalloc().
++** Let V[] be an array of unsigned characters sufficient to hold
++** up to N bits. Let I be an integer between 0 and N. 0<=I<N.
++** Then the following macros can be used to set, clear, or test
++** individual bits within V.
+ */
+-SQLITE_PRIVATE void sqlite3PageFree(void *p){
+- pcache1Free(p);
+-}
+-
++#define SETBIT(V,I) V[I>>3] |= (1<<(I&7))
++#define CLEARBIT(V,I) V[I>>3] &= ~(1<<(I&7))
++#define TESTBIT(V,I) (V[I>>3]&(1<<(I&7)))!=0
+
+ /*
+-** Return true if it desirable to avoid allocating a new page cache
+-** entry.
++** This routine runs an extensive test of the Bitvec code.
+ **
+-** If memory was allocated specifically to the page cache using
+-** SQLITE_CONFIG_PAGECACHE but that memory has all been used, then
+-** it is desirable to avoid allocating a new page cache entry because
+-** presumably SQLITE_CONFIG_PAGECACHE was suppose to be sufficient
+-** for all page cache needs and we should not need to spill the
+-** allocation onto the heap.
++** The input is an array of integers that acts as a program
++** to test the Bitvec. The integers are opcodes followed
++** by 0, 1, or 3 operands, depending on the opcode. Another
++** opcode follows immediately after the last operand.
+ **
+-** Or, the heap is used for all page cache memory but the heap is
+-** under memory pressure, then again it is desirable to avoid
+-** allocating a new page cache entry in order to avoid stressing
+-** the heap even further.
+-*/
+-static int pcache1UnderMemoryPressure(PCache1 *pCache){
+- if( pcache1.nSlot && (pCache->szPage+pCache->szExtra)<=pcache1.szSlot ){
+- return pcache1.bUnderPressure;
+- }else{
+- return sqlite3HeapNearlyFull();
+- }
+-}
+-
+-/******************************************************************************/
+-/******** General Implementation Functions ************************************/
+-
+-/*
+-** This function is used to resize the hash table used by the cache passed
+-** as the first argument.
++** There are 6 opcodes numbered from 0 through 5. 0 is the
++** "halt" opcode and causes the test to end.
+ **
+-** The PCache mutex must be held when this function is called.
++** 0 Halt and return the number of errors
++** 1 N S X Set N bits beginning with S and incrementing by X
++** 2 N S X Clear N bits beginning with S and incrementing by X
++** 3 N Set N randomly chosen bits
++** 4 N Clear N randomly chosen bits
++** 5 N S X Set N bits from S increment X in array only, not in bitvec
++**
++** The opcodes 1 through 4 perform set and clear operations are performed
++** on both a Bitvec object and on a linear array of bits obtained from malloc.
++** Opcode 5 works on the linear array only, not on the Bitvec.
++** Opcode 5 is used to deliberately induce a fault in order to
++** confirm that error detection works.
++**
++** At the conclusion of the test the linear array is compared
++** against the Bitvec object. If there are any differences,
++** an error is returned. If they are the same, zero is returned.
++**
++** If a memory allocation error occurs, return -1.
+ */
+-static void pcache1ResizeHash(PCache1 *p){
+- PgHdr1 **apNew;
+- unsigned int nNew;
+- unsigned int i;
++SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int sz, int *aOp){
++ Bitvec *pBitvec = 0;
++ unsigned char *pV = 0;
++ int rc = -1;
++ int i, nx, pc, op;
++ void *pTmpSpace;
+
+- assert( sqlite3_mutex_held(p->pGroup->mutex) );
++ /* Allocate the Bitvec to be tested and a linear array of
++ ** bits to act as the reference */
++ pBitvec = sqlite3BitvecCreate( sz );
++ pV = sqlite3MallocZero( (sz+7)/8 + 1 );
++ pTmpSpace = sqlite3_malloc64(BITVEC_SZ);
++ if( pBitvec==0 || pV==0 || pTmpSpace==0 ) goto bitvec_end;
+
+- nNew = p->nHash*2;
+- if( nNew<256 ){
+- nNew = 256;
+- }
++ /* NULL pBitvec tests */
++ sqlite3BitvecSet(0, 1);
++ sqlite3BitvecClear(0, 1, pTmpSpace);
+
+- pcache1LeaveMutex(p->pGroup);
+- if( p->nHash ){ sqlite3BeginBenignMalloc(); }
+- apNew = (PgHdr1 **)sqlite3MallocZero(sizeof(PgHdr1 *)*nNew);
+- if( p->nHash ){ sqlite3EndBenignMalloc(); }
+- pcache1EnterMutex(p->pGroup);
+- if( apNew ){
+- for(i=0; i<p->nHash; i++){
+- PgHdr1 *pPage;
+- PgHdr1 *pNext = p->apHash[i];
+- while( (pPage = pNext)!=0 ){
+- unsigned int h = pPage->iKey % nNew;
+- pNext = pPage->pNext;
+- pPage->pNext = apNew[h];
+- apNew[h] = pPage;
++ /* Run the program */
++ pc = 0;
++ while( (op = aOp[pc])!=0 ){
++ switch( op ){
++ case 1:
++ case 2:
++ case 5: {
++ nx = 4;
++ i = aOp[pc+2] - 1;
++ aOp[pc+2] += aOp[pc+3];
++ break;
++ }
++ case 3:
++ case 4:
++ default: {
++ nx = 2;
++ sqlite3_randomness(sizeof(i), &i);
++ break;
+ }
+ }
+- sqlite3_free(p->apHash);
+- p->apHash = apNew;
+- p->nHash = nNew;
++ if( (--aOp[pc+1]) > 0 ) nx = 0;
++ pc += nx;
++ i = (i & 0x7fffffff)%sz;
++ if( (op & 1)!=0 ){
++ SETBIT(pV, (i+1));
++ if( op!=5 ){
++ if( sqlite3BitvecSet(pBitvec, i+1) ) goto bitvec_end;
++ }
++ }else{
++ CLEARBIT(pV, (i+1));
++ sqlite3BitvecClear(pBitvec, i+1, pTmpSpace);
++ }
++ }
++
++ /* Test to make sure the linear array exactly matches the
++ ** Bitvec object. Start with the assumption that they do
++ ** match (rc==0). Change rc to non-zero if a discrepancy
++ ** is found.
++ */
++ rc = sqlite3BitvecTest(0,0) + sqlite3BitvecTest(pBitvec, sz+1)
++ + sqlite3BitvecTest(pBitvec, 0)
++ + (sqlite3BitvecSize(pBitvec) - sz);
++ for(i=1; i<=sz; i++){
++ if( (TESTBIT(pV,i))!=sqlite3BitvecTest(pBitvec,i) ){
++ rc = i;
++ break;
++ }
+ }
++
++ /* Free allocated structure */
++bitvec_end:
++ sqlite3_free(pTmpSpace);
++ sqlite3_free(pV);
++ sqlite3BitvecDestroy(pBitvec);
++ return rc;
+ }
++#endif /* SQLITE_OMIT_BUILTIN_TEST */
+
++/************** End of bitvec.c **********************************************/
++/************** Begin file pcache.c ******************************************/
+ /*
+-** This function is used internally to remove the page pPage from the
+-** PGroup LRU list, if is part of it. If pPage is not part of the PGroup
+-** LRU list, then this function is a no-op.
++** 2008 August 05
+ **
+-** The PGroup mutex must be held when this function is called.
++** 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 that page cache.
+ */
+-static void pcache1PinPage(PgHdr1 *pPage){
+- PCache1 *pCache;
+- PGroup *pGroup;
+
+- assert( pPage!=0 );
+- assert( pPage->isPinned==0 );
+- pCache = pPage->pCache;
+- pGroup = pCache->pGroup;
+- assert( pPage->pLruNext || pPage==pGroup->pLruTail );
+- assert( pPage->pLruPrev || pPage==pGroup->pLruHead );
+- assert( sqlite3_mutex_held(pGroup->mutex) );
+- if( pPage->pLruPrev ){
+- pPage->pLruPrev->pLruNext = pPage->pLruNext;
+- }else{
+- pGroup->pLruHead = pPage->pLruNext;
+- }
+- if( pPage->pLruNext ){
+- pPage->pLruNext->pLruPrev = pPage->pLruPrev;
+- }else{
+- pGroup->pLruTail = pPage->pLruPrev;
+- }
+- pPage->pLruNext = 0;
+- pPage->pLruPrev = 0;
+- pPage->isPinned = 1;
+- pCache->nRecyclable--;
+-}
++/*
++** A complete page cache is an instance of this structure.
++*/
++struct PCache {
++ PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */
++ PgHdr *pSynced; /* Last synced page in dirty page list */
++ int nRef; /* Number of referenced pages */
++ int szCache; /* Configured cache size */
++ int szPage; /* Size of every page in this cache */
++ int szExtra; /* Size of extra space for each page */
++ u8 bPurgeable; /* True if pages are on backing store */
++ u8 eCreate; /* eCreate value for for xFetch() */
++ int (*xStress)(void*,PgHdr*); /* Call to try make a page clean */
++ void *pStress; /* Argument to xStress */
++ sqlite3_pcache *pCache; /* Pluggable cache module */
++ PgHdr *pPage1; /* Reference to page 1 */
++};
++
++/********************************** Linked List Management ********************/
+
++/* Allowed values for second argument to pcacheManageDirtyList() */
++#define PCACHE_DIRTYLIST_REMOVE 1 /* Remove pPage from dirty list */
++#define PCACHE_DIRTYLIST_ADD 2 /* Add pPage to the dirty list */
++#define PCACHE_DIRTYLIST_FRONT 3 /* Move pPage to the front of the list */
+
+ /*
+-** Remove the page supplied as an argument from the hash table
+-** (PCache1.apHash structure) that it is currently stored in.
+-**
+-** The PGroup mutex must be held when this function is called.
++** Manage pPage's participation on the dirty list. Bits of the addRemove
++** argument determines what operation to do. The 0x01 bit means first
++** remove pPage from the dirty list. The 0x02 means add pPage back to
++** the dirty list. Doing both moves pPage to the front of the dirty list.
+ */
+-static void pcache1RemoveFromHash(PgHdr1 *pPage){
+- unsigned int h;
+- PCache1 *pCache = pPage->pCache;
+- PgHdr1 **pp;
+-
+- assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
+- h = pPage->iKey % pCache->nHash;
+- for(pp=&pCache->apHash[h]; (*pp)!=pPage; pp=&(*pp)->pNext);
+- *pp = (*pp)->pNext;
++static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
++ PCache *p = pPage->pCache;
+
+- pCache->nPage--;
++ if( addRemove & PCACHE_DIRTYLIST_REMOVE ){
++ assert( pPage->pDirtyNext || pPage==p->pDirtyTail );
++ assert( pPage->pDirtyPrev || pPage==p->pDirty );
++
++ /* Update the PCache1.pSynced variable if necessary. */
++ if( p->pSynced==pPage ){
++ PgHdr *pSynced = pPage->pDirtyPrev;
++ while( pSynced && (pSynced->flags&PGHDR_NEED_SYNC) ){
++ pSynced = pSynced->pDirtyPrev;
++ }
++ p->pSynced = pSynced;
++ }
++
++ if( pPage->pDirtyNext ){
++ pPage->pDirtyNext->pDirtyPrev = pPage->pDirtyPrev;
++ }else{
++ assert( pPage==p->pDirtyTail );
++ p->pDirtyTail = pPage->pDirtyPrev;
++ }
++ if( pPage->pDirtyPrev ){
++ pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext;
++ }else{
++ assert( pPage==p->pDirty );
++ p->pDirty = pPage->pDirtyNext;
++ if( p->pDirty==0 && p->bPurgeable ){
++ assert( p->eCreate==1 );
++ p->eCreate = 2;
++ }
++ }
++ pPage->pDirtyNext = 0;
++ pPage->pDirtyPrev = 0;
++ }
++ if( addRemove & PCACHE_DIRTYLIST_ADD ){
++ assert( pPage->pDirtyNext==0 && pPage->pDirtyPrev==0 && p->pDirty!=pPage );
++
++ pPage->pDirtyNext = p->pDirty;
++ if( pPage->pDirtyNext ){
++ assert( pPage->pDirtyNext->pDirtyPrev==0 );
++ pPage->pDirtyNext->pDirtyPrev = pPage;
++ }else{
++ p->pDirtyTail = pPage;
++ if( p->bPurgeable ){
++ assert( p->eCreate==2 );
++ p->eCreate = 1;
++ }
++ }
++ p->pDirty = pPage;
++ if( !p->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) ){
++ p->pSynced = pPage;
++ }
++ }
+ }
+
+ /*
+-** If there are currently more than nMaxPage pages allocated, try
+-** to recycle pages to reduce the number allocated to nMaxPage.
++** Wrapper around the pluggable caches xUnpin method. If the cache is
++** being used for an in-memory database, this function is a no-op.
+ */
+-static void pcache1EnforceMaxPage(PGroup *pGroup){
+- assert( sqlite3_mutex_held(pGroup->mutex) );
+- while( pGroup->nCurrentPage>pGroup->nMaxPage && pGroup->pLruTail ){
+- PgHdr1 *p = pGroup->pLruTail;
+- assert( p->pCache->pGroup==pGroup );
+- assert( p->isPinned==0 );
+- pcache1PinPage(p);
+- pcache1RemoveFromHash(p);
+- pcache1FreePage(p);
++static void pcacheUnpin(PgHdr *p){
++ if( p->pCache->bPurgeable ){
++ if( p->pgno==1 ){
++ p->pCache->pPage1 = 0;
++ }
++ sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 0);
+ }
+ }
+
+ /*
+-** Discard all pages from cache pCache with a page number (key value)
+-** greater than or equal to iLimit. Any pinned pages that meet this
+-** criteria are unpinned before they are discarded.
++** Compute the number of pages of cache requested. p->szCache is the
++** cache size requested by the "PRAGMA cache_size" statement.
++**
+ **
+-** The PCache mutex must be held when this function is called.
+ */
+-static void pcache1TruncateUnsafe(
+- PCache1 *pCache, /* The cache to truncate */
+- unsigned int iLimit /* Drop pages with this pgno or larger */
+-){
+- TESTONLY( unsigned int nPage = 0; ) /* To assert pCache->nPage is correct */
+- unsigned int h;
+- assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
+- for(h=0; h<pCache->nHash; h++){
+- PgHdr1 **pp = &pCache->apHash[h];
+- PgHdr1 *pPage;
+- while( (pPage = *pp)!=0 ){
+- if( pPage->iKey>=iLimit ){
+- pCache->nPage--;
+- *pp = pPage->pNext;
+- if( !pPage->isPinned ) pcache1PinPage(pPage);
+- pcache1FreePage(pPage);
+- }else{
+- pp = &pPage->pNext;
+- TESTONLY( nPage++; )
+- }
+- }
++static int numberOfCachePages(PCache *p){
++ if( p->szCache>=0 ){
++ /* IMPLEMENTATION-OF: R-42059-47211 If the argument N is positive then the
++ ** suggested cache size is set to N. */
++ return p->szCache;
++ }else{
++ /* IMPLEMENTATION-OF: R-61436-13639 If the argument N is negative, then
++ ** the number of cache pages is adjusted to use approximately abs(N*1024)
++ ** bytes of memory. */
++ return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra));
++ }
++}
++
++/*************************************************** General Interfaces ******
++**
++** Initialize and shutdown the page cache subsystem. Neither of these
++** functions are threadsafe.
++*/
++SQLITE_PRIVATE int sqlite3PcacheInitialize(void){
++ if( sqlite3GlobalConfig.pcache2.xInit==0 ){
++ /* IMPLEMENTATION-OF: R-26801-64137 If the xInit() method is NULL, then the
++ ** built-in default page cache is used instead of the application defined
++ ** page cache. */
++ sqlite3PCacheSetDefault();
++ }
++ return sqlite3GlobalConfig.pcache2.xInit(sqlite3GlobalConfig.pcache2.pArg);
++}
++SQLITE_PRIVATE void sqlite3PcacheShutdown(void){
++ if( sqlite3GlobalConfig.pcache2.xShutdown ){
++ /* IMPLEMENTATION-OF: R-26000-56589 The xShutdown() method may be NULL. */
++ sqlite3GlobalConfig.pcache2.xShutdown(sqlite3GlobalConfig.pcache2.pArg);
+ }
+- assert( pCache->nPage==nPage );
+ }
+
+-/******************************************************************************/
+-/******** sqlite3_pcache Methods **********************************************/
++/*
++** Return the size in bytes of a PCache object.
++*/
++SQLITE_PRIVATE int sqlite3PcacheSize(void){ return sizeof(PCache); }
+
+ /*
+-** Implementation of the sqlite3_pcache.xInit method.
++** Create a new PCache object. Storage space to hold the object
++** has already been allocated and is passed in as the p pointer.
++** The caller discovers how much space needs to be allocated by
++** calling sqlite3PcacheSize().
+ */
+-static int pcache1Init(void *NotUsed){
+- UNUSED_PARAMETER(NotUsed);
+- assert( pcache1.isInit==0 );
+- memset(&pcache1, 0, sizeof(pcache1));
+- if( sqlite3GlobalConfig.bCoreMutex ){
+- pcache1.grp.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU);
+- pcache1.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PMEM);
++SQLITE_PRIVATE int sqlite3PcacheOpen(
++ int szPage, /* Size of every page */
++ int szExtra, /* Extra space associated with each page */
++ int bPurgeable, /* True if pages are on backing store */
++ int (*xStress)(void*,PgHdr*),/* Call to try to make pages clean */
++ void *pStress, /* Argument to xStress */
++ PCache *p /* Preallocated space for the PCache */
++){
++ memset(p, 0, sizeof(PCache));
++ p->szPage = 1;
++ p->szExtra = szExtra;
++ p->bPurgeable = bPurgeable;
++ p->eCreate = 2;
++ p->xStress = xStress;
++ p->pStress = pStress;
++ p->szCache = 100;
++ return sqlite3PcacheSetPageSize(p, szPage);
++}
++
++/*
++** Change the page size for PCache object. The caller must ensure that there
++** are no outstanding page references when this function is called.
++*/
++SQLITE_PRIVATE int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
++ assert( pCache->nRef==0 && pCache->pDirty==0 );
++ if( pCache->szPage ){
++ sqlite3_pcache *pNew;
++ pNew = sqlite3GlobalConfig.pcache2.xCreate(
++ szPage, pCache->szExtra + ROUND8(sizeof(PgHdr)),
++ pCache->bPurgeable
++ );
++ if( pNew==0 ) return SQLITE_NOMEM;
++ sqlite3GlobalConfig.pcache2.xCachesize(pNew, numberOfCachePages(pCache));
++ if( pCache->pCache ){
++ sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
++ }
++ pCache->pCache = pNew;
++ pCache->pPage1 = 0;
++ pCache->szPage = szPage;
+ }
+- pcache1.grp.mxPinned = 10;
+- pcache1.isInit = 1;
+ return SQLITE_OK;
+ }
+
+ /*
+-** Implementation of the sqlite3_pcache.xShutdown method.
+-** Note that the static mutex allocated in xInit does
+-** not need to be freed.
++** Try to obtain a page from the cache.
++**
++** This routine returns a pointer to an sqlite3_pcache_page object if
++** such an object is already in cache, or if a new one is created.
++** This routine returns a NULL pointer if the object was not in cache
++** and could not be created.
++**
++** The createFlags should be 0 to check for existing pages and should
++** be 3 (not 1, but 3) to try to create a new page.
++**
++** If the createFlag is 0, then NULL is always returned if the page
++** is not already in the cache. If createFlag is 1, then a new page
++** is created only if that can be done without spilling dirty pages
++** and without exceeding the cache size limit.
++**
++** The caller needs to invoke sqlite3PcacheFetchFinish() to properly
++** initialize the sqlite3_pcache_page object and convert it into a
++** PgHdr object. The sqlite3PcacheFetch() and sqlite3PcacheFetchFinish()
++** routines are split this way for performance reasons. When separated
++** they can both (usually) operate without having to push values to
++** the stack on entry and pop them back off on exit, which saves a
++** lot of pushing and popping.
+ */
+-static void pcache1Shutdown(void *NotUsed){
+- UNUSED_PARAMETER(NotUsed);
+- assert( pcache1.isInit!=0 );
+- memset(&pcache1, 0, sizeof(pcache1));
+-}
++SQLITE_PRIVATE sqlite3_pcache_page *sqlite3PcacheFetch(
++ PCache *pCache, /* Obtain the page from this cache */
++ Pgno pgno, /* Page number to obtain */
++ int createFlag /* If true, create page if it does not exist already */
++){
++ int eCreate;
+
+-/* forward declaration */
+-static void pcache1Destroy(sqlite3_pcache *p);
++ assert( pCache!=0 );
++ assert( pCache->pCache!=0 );
++ assert( createFlag==3 || createFlag==0 );
++ assert( pgno>0 );
++
++ /* eCreate defines what to do if the page does not exist.
++ ** 0 Do not allocate a new page. (createFlag==0)
++ ** 1 Allocate a new page if doing so is inexpensive.
++ ** (createFlag==1 AND bPurgeable AND pDirty)
++ ** 2 Allocate a new page even it doing so is difficult.
++ ** (createFlag==1 AND !(bPurgeable AND pDirty)
++ */
++ eCreate = createFlag & pCache->eCreate;
++ assert( eCreate==0 || eCreate==1 || eCreate==2 );
++ assert( createFlag==0 || pCache->eCreate==eCreate );
++ assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) );
++ return sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
++}
+
+ /*
+-** Implementation of the sqlite3_pcache.xCreate method.
++** If the sqlite3PcacheFetch() routine is unable to allocate a new
++** page because new clean pages are available for reuse and the cache
++** size limit has been reached, then this routine can be invoked to
++** try harder to allocate a page. This routine might invoke the stress
++** callback to spill dirty pages to the journal. It will then try to
++** allocate the new page and will only fail to allocate a new page on
++** an OOM error.
+ **
+-** Allocate a new cache.
++** This routine should be invoked only after sqlite3PcacheFetch() fails.
+ */
+-static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
+- PCache1 *pCache; /* The newly created page cache */
+- PGroup *pGroup; /* The group the new page cache will belong to */
+- int sz; /* Bytes of memory required to allocate the new cache */
++SQLITE_PRIVATE int sqlite3PcacheFetchStress(
++ PCache *pCache, /* Obtain the page from this cache */
++ Pgno pgno, /* Page number to obtain */
++ sqlite3_pcache_page **ppPage /* Write result here */
++){
++ PgHdr *pPg;
++ if( pCache->eCreate==2 ) return 0;
+
+- /*
+- ** The separateCache variable is true if each PCache has its own private
+- ** PGroup. In other words, separateCache is true for mode (1) where no
+- ** mutexing is required.
+- **
+- ** * Always use a unified cache (mode-2) if ENABLE_MEMORY_MANAGEMENT
+- **
+- ** * Always use a unified cache in single-threaded applications
+- **
+- ** * Otherwise (if multi-threaded and ENABLE_MEMORY_MANAGEMENT is off)
+- ** use separate caches (mode-1)
++
++ /* Find a dirty page to write-out and recycle. First try to find a
++ ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC
++ ** cleared), but if that is not possible settle for any other
++ ** unreferenced dirty page.
+ */
+-#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) || SQLITE_THREADSAFE==0
+- const int separateCache = 0;
+-#else
+- int separateCache = sqlite3GlobalConfig.bCoreMutex>0;
++ for(pPg=pCache->pSynced;
++ pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC));
++ pPg=pPg->pDirtyPrev
++ );
++ pCache->pSynced = pPg;
++ if( !pPg ){
++ for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev);
++ }
++ if( pPg ){
++ int rc;
++#ifdef SQLITE_LOG_CACHE_SPILL
++ sqlite3_log(SQLITE_FULL,
++ "spill page %d making room for %d - cache used: %d/%d",
++ pPg->pgno, pgno,
++ sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache),
++ numberOfCachePages(pCache));
+ #endif
+-
+- assert( (szPage & (szPage-1))==0 && szPage>=512 && szPage<=65536 );
+- assert( szExtra < 300 );
+-
+- sz = sizeof(PCache1) + sizeof(PGroup)*separateCache;
+- pCache = (PCache1 *)sqlite3MallocZero(sz);
+- if( pCache ){
+- if( separateCache ){
+- pGroup = (PGroup*)&pCache[1];
+- pGroup->mxPinned = 10;
+- }else{
+- pGroup = &pcache1.grp;
+- }
+- pCache->pGroup = pGroup;
+- pCache->szPage = szPage;
+- pCache->szExtra = szExtra;
+- pCache->bPurgeable = (bPurgeable ? 1 : 0);
+- pcache1EnterMutex(pGroup);
+- pcache1ResizeHash(pCache);
+- if( bPurgeable ){
+- pCache->nMin = 10;
+- pGroup->nMinPage += pCache->nMin;
+- pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
+- }
+- pcache1LeaveMutex(pGroup);
+- if( pCache->nHash==0 ){
+- pcache1Destroy((sqlite3_pcache*)pCache);
+- pCache = 0;
++ rc = pCache->xStress(pCache->pStress, pPg);
++ if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
++ return rc;
+ }
+ }
+- return (sqlite3_pcache *)pCache;
++ *ppPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2);
++ return *ppPage==0 ? SQLITE_NOMEM : SQLITE_OK;
+ }
+
+ /*
+-** Implementation of the sqlite3_pcache.xCachesize method.
++** This is a helper routine for sqlite3PcacheFetchFinish()
+ **
+-** Configure the cache_size limit for a cache.
++** In the uncommon case where the page being fetched has not been
++** initialized, this routine is invoked to do the initialization.
++** This routine is broken out into a separate function since it
++** requires extra stack manipulation that can be avoided in the common
++** case.
+ */
+-static void pcache1Cachesize(sqlite3_pcache *p, int nMax){
+- PCache1 *pCache = (PCache1 *)p;
+- if( pCache->bPurgeable ){
+- PGroup *pGroup = pCache->pGroup;
+- pcache1EnterMutex(pGroup);
+- pGroup->nMaxPage += (nMax - pCache->nMax);
+- pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
+- pCache->nMax = nMax;
+- pCache->n90pct = pCache->nMax*9/10;
+- pcache1EnforceMaxPage(pGroup);
+- pcache1LeaveMutex(pGroup);
+- }
++static SQLITE_NOINLINE PgHdr *pcacheFetchFinishWithInit(
++ PCache *pCache, /* Obtain the page from this cache */
++ Pgno pgno, /* Page number obtained */
++ sqlite3_pcache_page *pPage /* Page obtained by prior PcacheFetch() call */
++){
++ PgHdr *pPgHdr;
++ assert( pPage!=0 );
++ pPgHdr = (PgHdr*)pPage->pExtra;
++ assert( pPgHdr->pPage==0 );
++ memset(pPgHdr, 0, sizeof(PgHdr));
++ pPgHdr->pPage = pPage;
++ pPgHdr->pData = pPage->pBuf;
++ pPgHdr->pExtra = (void *)&pPgHdr[1];
++ memset(pPgHdr->pExtra, 0, pCache->szExtra);
++ pPgHdr->pCache = pCache;
++ pPgHdr->pgno = pgno;
++ return sqlite3PcacheFetchFinish(pCache,pgno,pPage);
+ }
+
+ /*
+-** Implementation of the sqlite3_pcache.xShrink method.
+-**
+-** Free up as much memory as possible.
++** This routine converts the sqlite3_pcache_page object returned by
++** sqlite3PcacheFetch() into an initialized PgHdr object. This routine
++** must be called after sqlite3PcacheFetch() in order to get a usable
++** result.
+ */
+-static void pcache1Shrink(sqlite3_pcache *p){
+- PCache1 *pCache = (PCache1*)p;
+- if( pCache->bPurgeable ){
+- PGroup *pGroup = pCache->pGroup;
+- int savedMaxPage;
+- pcache1EnterMutex(pGroup);
+- savedMaxPage = pGroup->nMaxPage;
+- pGroup->nMaxPage = 0;
+- pcache1EnforceMaxPage(pGroup);
+- pGroup->nMaxPage = savedMaxPage;
+- pcache1LeaveMutex(pGroup);
++SQLITE_PRIVATE PgHdr *sqlite3PcacheFetchFinish(
++ PCache *pCache, /* Obtain the page from this cache */
++ Pgno pgno, /* Page number obtained */
++ sqlite3_pcache_page *pPage /* Page obtained by prior PcacheFetch() call */
++){
++ PgHdr *pPgHdr;
++
++ if( pPage==0 ) return 0;
++ pPgHdr = (PgHdr *)pPage->pExtra;
++
++ if( !pPgHdr->pPage ){
++ return pcacheFetchFinishWithInit(pCache, pgno, pPage);
++ }
++ if( 0==pPgHdr->nRef ){
++ pCache->nRef++;
++ }
++ pPgHdr->nRef++;
++ if( pgno==1 ){
++ pCache->pPage1 = pPgHdr;
+ }
++ return pPgHdr;
+ }
+
+ /*
+-** Implementation of the sqlite3_pcache.xPagecount method.
++** Decrement the reference count on a page. If the page is clean and the
++** reference count drops to 0, then it is made eligible for recycling.
+ */
+-static int pcache1Pagecount(sqlite3_pcache *p){
+- int n;
+- PCache1 *pCache = (PCache1*)p;
+- pcache1EnterMutex(pCache->pGroup);
+- n = pCache->nPage;
+- pcache1LeaveMutex(pCache->pGroup);
+- return n;
++SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
++ assert( p->nRef>0 );
++ p->nRef--;
++ if( p->nRef==0 ){
++ p->pCache->nRef--;
++ if( (p->flags&PGHDR_DIRTY)==0 ){
++ pcacheUnpin(p);
++ }else if( p->pDirtyPrev!=0 ){
++ /* Move the page to the head of the dirty list. */
++ pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
++ }
++ }
+ }
+
+-
+ /*
+-** Implement steps 3, 4, and 5 of the pcache1Fetch() algorithm described
+-** in the header of the pcache1Fetch() procedure.
+-**
+-** This steps are broken out into a separate procedure because they are
+-** usually not needed, and by avoiding the stack initialization required
+-** for these steps, the main pcache1Fetch() procedure can run faster.
++** Increase the reference count of a supplied page by 1.
+ */
+-static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
+- PCache1 *pCache,
+- unsigned int iKey,
+- int createFlag
+-){
+- unsigned int nPinned;
+- PGroup *pGroup = pCache->pGroup;
+- PgHdr1 *pPage = 0;
++SQLITE_PRIVATE void sqlite3PcacheRef(PgHdr *p){
++ assert(p->nRef>0);
++ p->nRef++;
++}
+
+- /* Step 3: Abort if createFlag is 1 but the cache is nearly full */
+- assert( pCache->nPage >= pCache->nRecyclable );
+- nPinned = pCache->nPage - pCache->nRecyclable;
+- assert( pGroup->mxPinned == pGroup->nMaxPage + 10 - pGroup->nMinPage );
+- assert( pCache->n90pct == pCache->nMax*9/10 );
+- if( createFlag==1 && (
+- nPinned>=pGroup->mxPinned
+- || nPinned>=pCache->n90pct
+- || (pcache1UnderMemoryPressure(pCache) && pCache->nRecyclable<nPinned)
+- )){
+- return 0;
++/*
++** Drop a page from the cache. There must be exactly one reference to the
++** page. This function deletes that reference, so after it returns the
++** page pointed to by p is invalid.
++*/
++SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr *p){
++ assert( p->nRef==1 );
++ if( p->flags&PGHDR_DIRTY ){
++ pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
+ }
+-
+- if( pCache->nPage>=pCache->nHash ) pcache1ResizeHash(pCache);
+- assert( pCache->nHash>0 && pCache->apHash );
+-
+- /* Step 4. Try to recycle a page. */
+- if( pCache->bPurgeable && pGroup->pLruTail && (
+- (pCache->nPage+1>=pCache->nMax)
+- || pGroup->nCurrentPage>=pGroup->nMaxPage
+- || pcache1UnderMemoryPressure(pCache)
+- )){
+- PCache1 *pOther;
+- pPage = pGroup->pLruTail;
+- assert( pPage->isPinned==0 );
+- pcache1RemoveFromHash(pPage);
+- pcache1PinPage(pPage);
+- pOther = pPage->pCache;
+-
+- /* We want to verify that szPage and szExtra are the same for pOther
+- ** and pCache. Assert that we can verify this by comparing sums. */
+- assert( (pCache->szPage & (pCache->szPage-1))==0 && pCache->szPage>=512 );
+- assert( pCache->szExtra<512 );
+- assert( (pOther->szPage & (pOther->szPage-1))==0 && pOther->szPage>=512 );
+- assert( pOther->szExtra<512 );
+-
+- if( pOther->szPage+pOther->szExtra != pCache->szPage+pCache->szExtra ){
+- pcache1FreePage(pPage);
+- pPage = 0;
+- }else{
+- pGroup->nCurrentPage -= (pOther->bPurgeable - pCache->bPurgeable);
+- }
++ p->pCache->nRef--;
++ if( p->pgno==1 ){
++ p->pCache->pPage1 = 0;
+ }
++ sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 1);
++}
+
+- /* Step 5. If a usable page buffer has still not been found,
+- ** attempt to allocate a new one.
+- */
+- if( !pPage ){
+- if( createFlag==1 ) sqlite3BeginBenignMalloc();
+- pPage = pcache1AllocPage(pCache);
+- if( createFlag==1 ) sqlite3EndBenignMalloc();
++/*
++** Make sure the page is marked as dirty. If it isn't dirty already,
++** make it so.
++*/
++SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr *p){
++ p->flags &= ~PGHDR_DONT_WRITE;
++ assert( p->nRef>0 );
++ if( 0==(p->flags & PGHDR_DIRTY) ){
++ p->flags |= PGHDR_DIRTY;
++ pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD);
+ }
++}
+
+- if( pPage ){
+- unsigned int h = iKey % pCache->nHash;
+- pCache->nPage++;
+- pPage->iKey = iKey;
+- pPage->pNext = pCache->apHash[h];
+- pPage->pCache = pCache;
+- pPage->pLruPrev = 0;
+- pPage->pLruNext = 0;
+- pPage->isPinned = 1;
+- *(void **)pPage->page.pExtra = 0;
+- pCache->apHash[h] = pPage;
+- if( iKey>pCache->iMaxKey ){
+- pCache->iMaxKey = iKey;
++/*
++** Make sure the page is marked as clean. If it isn't clean already,
++** make it so.
++*/
++SQLITE_PRIVATE void sqlite3PcacheMakeClean(PgHdr *p){
++ if( (p->flags & PGHDR_DIRTY) ){
++ pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
++ p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC);
++ if( p->nRef==0 ){
++ pcacheUnpin(p);
+ }
+ }
+- return pPage;
+ }
+
+ /*
+-** Implementation of the sqlite3_pcache.xFetch method.
+-**
+-** Fetch a page by key value.
+-**
+-** Whether or not a new page may be allocated by this function depends on
+-** the value of the createFlag argument. 0 means do not allocate a new
+-** page. 1 means allocate a new page if space is easily available. 2
+-** means to try really hard to allocate a new page.
+-**
+-** For a non-purgeable cache (a cache used as the storage for an in-memory
+-** database) there is really no difference between createFlag 1 and 2. So
+-** the calling function (pcache.c) will never have a createFlag of 1 on
+-** a non-purgeable cache.
+-**
+-** There are three different approaches to obtaining space for a page,
+-** depending on the value of parameter createFlag (which may be 0, 1 or 2).
+-**
+-** 1. Regardless of the value of createFlag, the cache is searched for a
+-** copy of the requested page. If one is found, it is returned.
+-**
+-** 2. If createFlag==0 and the page is not already in the cache, NULL is
+-** returned.
+-**
+-** 3. If createFlag is 1, and the page is not already in the cache, then
+-** return NULL (do not allocate a new page) if any of the following
+-** conditions are true:
+-**
+-** (a) the number of pages pinned by the cache is greater than
+-** PCache1.nMax, or
+-**
+-** (b) the number of pages pinned by the cache is greater than
+-** the sum of nMax for all purgeable caches, less the sum of
+-** nMin for all other purgeable caches, or
+-**
+-** 4. If none of the first three conditions apply and the cache is marked
+-** as purgeable, and if one of the following is true:
+-**
+-** (a) The number of pages allocated for the cache is already
+-** PCache1.nMax, or
+-**
+-** (b) The number of pages allocated for all purgeable caches is
+-** already equal to or greater than the sum of nMax for all
+-** purgeable caches,
+-**
+-** (c) The system is under memory pressure and wants to avoid
+-** unnecessary pages cache entry allocations
+-**
+-** then attempt to recycle a page from the LRU list. If it is the right
+-** size, return the recycled buffer. Otherwise, free the buffer and
+-** proceed to step 5.
+-**
+-** 5. Otherwise, allocate and return a new page buffer.
++** Make every page in the cache clean.
+ */
+-static sqlite3_pcache_page *pcache1Fetch(
+- sqlite3_pcache *p,
+- unsigned int iKey,
+- int createFlag
+-){
+- PCache1 *pCache = (PCache1 *)p;
+- PgHdr1 *pPage = 0;
+-
+- assert( offsetof(PgHdr1,page)==0 );
+- assert( pCache->bPurgeable || createFlag!=1 );
+- assert( pCache->bPurgeable || pCache->nMin==0 );
+- assert( pCache->bPurgeable==0 || pCache->nMin==10 );
+- assert( pCache->nMin==0 || pCache->bPurgeable );
+- assert( pCache->nHash>0 );
+- pcache1EnterMutex(pCache->pGroup);
+-
+- /* Step 1: Search the hash table for an existing entry. */
+- pPage = pCache->apHash[iKey % pCache->nHash];
+- while( pPage && pPage->iKey!=iKey ){ pPage = pPage->pNext; }
++SQLITE_PRIVATE void sqlite3PcacheCleanAll(PCache *pCache){
++ PgHdr *p;
++ while( (p = pCache->pDirty)!=0 ){
++ sqlite3PcacheMakeClean(p);
++ }
++}
+
+- /* Step 2: Abort if no existing page is found and createFlag is 0 */
+- if( pPage ){
+- if( !pPage->isPinned ) pcache1PinPage(pPage);
+- }else if( createFlag ){
+- /* Steps 3, 4, and 5 implemented by this subroutine */
+- pPage = pcache1FetchStage2(pCache, iKey, createFlag);
++/*
++** Clear the PGHDR_NEED_SYNC flag from all dirty pages.
++*/
++SQLITE_PRIVATE void sqlite3PcacheClearSyncFlags(PCache *pCache){
++ PgHdr *p;
++ for(p=pCache->pDirty; p; p=p->pDirtyNext){
++ p->flags &= ~PGHDR_NEED_SYNC;
+ }
+- assert( pPage==0 || pCache->iMaxKey>=iKey );
+- pcache1LeaveMutex(pCache->pGroup);
+- return (sqlite3_pcache_page*)pPage;
++ pCache->pSynced = pCache->pDirtyTail;
+ }
+
++/*
++** Change the page number of page p to newPgno.
++*/
++SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
++ PCache *pCache = p->pCache;
++ assert( p->nRef>0 );
++ assert( newPgno>0 );
++ sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno);
++ p->pgno = newPgno;
++ if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){
++ pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
++ }
++}
+
+ /*
+-** Implementation of the sqlite3_pcache.xUnpin method.
++** Drop every cache entry whose page number is greater than "pgno". The
++** caller must ensure that there are no outstanding references to any pages
++** other than page 1 with a page number greater than pgno.
+ **
+-** Mark a page as unpinned (eligible for asynchronous recycling).
++** If there is a reference to page 1 and the pgno parameter passed to this
++** function is 0, then the data area associated with page 1 is zeroed, but
++** the page object is not dropped.
+ */
+-static void pcache1Unpin(
+- sqlite3_pcache *p,
+- sqlite3_pcache_page *pPg,
+- int reuseUnlikely
+-){
+- PCache1 *pCache = (PCache1 *)p;
+- PgHdr1 *pPage = (PgHdr1 *)pPg;
+- PGroup *pGroup = pCache->pGroup;
+-
+- assert( pPage->pCache==pCache );
+- pcache1EnterMutex(pGroup);
+-
+- /* It is an error to call this function if the page is already
+- ** part of the PGroup LRU list.
+- */
+- assert( pPage->pLruPrev==0 && pPage->pLruNext==0 );
+- assert( pGroup->pLruHead!=pPage && pGroup->pLruTail!=pPage );
+- assert( pPage->isPinned==1 );
+-
+- if( reuseUnlikely || pGroup->nCurrentPage>pGroup->nMaxPage ){
+- pcache1RemoveFromHash(pPage);
+- pcache1FreePage(pPage);
+- }else{
+- /* Add the page to the PGroup LRU list. */
+- if( pGroup->pLruHead ){
+- pGroup->pLruHead->pLruPrev = pPage;
+- pPage->pLruNext = pGroup->pLruHead;
+- pGroup->pLruHead = pPage;
+- }else{
+- pGroup->pLruTail = pPage;
+- pGroup->pLruHead = pPage;
++SQLITE_PRIVATE void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
++ if( pCache->pCache ){
++ PgHdr *p;
++ PgHdr *pNext;
++ for(p=pCache->pDirty; p; p=pNext){
++ pNext = p->pDirtyNext;
++ /* This routine never gets call with a positive pgno except right
++ ** after sqlite3PcacheCleanAll(). So if there are dirty pages,
++ ** it must be that pgno==0.
++ */
++ assert( p->pgno>0 );
++ if( ALWAYS(p->pgno>pgno) ){
++ assert( p->flags&PGHDR_DIRTY );
++ sqlite3PcacheMakeClean(p);
++ }
+ }
+- pCache->nRecyclable++;
+- pPage->isPinned = 0;
++ if( pgno==0 && pCache->pPage1 ){
++ memset(pCache->pPage1->pData, 0, pCache->szPage);
++ pgno = 1;
++ }
++ sqlite3GlobalConfig.pcache2.xTruncate(pCache->pCache, pgno+1);
+ }
+-
+- pcache1LeaveMutex(pCache->pGroup);
+ }
+
+ /*
+-** Implementation of the sqlite3_pcache.xRekey method.
++** Close a cache.
+ */
+-static void pcache1Rekey(
+- sqlite3_pcache *p,
+- sqlite3_pcache_page *pPg,
+- unsigned int iOld,
+- unsigned int iNew
+-){
+- PCache1 *pCache = (PCache1 *)p;
+- PgHdr1 *pPage = (PgHdr1 *)pPg;
+- PgHdr1 **pp;
+- unsigned int h;
+- assert( pPage->iKey==iOld );
+- assert( pPage->pCache==pCache );
++SQLITE_PRIVATE void sqlite3PcacheClose(PCache *pCache){
++ assert( pCache->pCache!=0 );
++ sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
++}
+
+- pcache1EnterMutex(pCache->pGroup);
++/*
++** Discard the contents of the cache.
++*/
++SQLITE_PRIVATE void sqlite3PcacheClear(PCache *pCache){
++ sqlite3PcacheTruncate(pCache, 0);
++}
+
+- h = iOld%pCache->nHash;
+- pp = &pCache->apHash[h];
+- while( (*pp)!=pPage ){
+- pp = &(*pp)->pNext;
++/*
++** Merge two lists of pages connected by pDirty and in pgno order.
++** Do not both fixing the pDirtyPrev pointers.
++*/
++static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB){
++ PgHdr result, *pTail;
++ pTail = &result;
++ while( pA && pB ){
++ if( pA->pgno<pB->pgno ){
++ pTail->pDirty = pA;
++ pTail = pA;
++ pA = pA->pDirty;
++ }else{
++ pTail->pDirty = pB;
++ pTail = pB;
++ pB = pB->pDirty;
++ }
+ }
+- *pp = pPage->pNext;
+-
+- h = iNew%pCache->nHash;
+- pPage->iKey = iNew;
+- pPage->pNext = pCache->apHash[h];
+- pCache->apHash[h] = pPage;
+- if( iNew>pCache->iMaxKey ){
+- pCache->iMaxKey = iNew;
++ if( pA ){
++ pTail->pDirty = pA;
++ }else if( pB ){
++ pTail->pDirty = pB;
++ }else{
++ pTail->pDirty = 0;
+ }
+-
+- pcache1LeaveMutex(pCache->pGroup);
++ return result.pDirty;
+ }
+
+ /*
+-** Implementation of the sqlite3_pcache.xTruncate method.
++** Sort the list of pages in accending order by pgno. Pages are
++** connected by pDirty pointers. The pDirtyPrev pointers are
++** corrupted by this sort.
+ **
+-** Discard all unpinned pages in the cache with a page number equal to
+-** or greater than parameter iLimit. Any pinned pages with a page number
+-** equal to or greater than iLimit are implicitly unpinned.
++** Since there cannot be more than 2^31 distinct pages in a database,
++** there cannot be more than 31 buckets required by the merge sorter.
++** One extra bucket is added to catch overflow in case something
++** ever changes to make the previous sentence incorrect.
+ */
+-static void pcache1Truncate(sqlite3_pcache *p, unsigned int iLimit){
+- PCache1 *pCache = (PCache1 *)p;
+- pcache1EnterMutex(pCache->pGroup);
+- if( iLimit<=pCache->iMaxKey ){
+- pcache1TruncateUnsafe(pCache, iLimit);
+- pCache->iMaxKey = iLimit-1;
++#define N_SORT_BUCKET 32
++static PgHdr *pcacheSortDirtyList(PgHdr *pIn){
++ PgHdr *a[N_SORT_BUCKET], *p;
++ int i;
++ memset(a, 0, sizeof(a));
++ while( pIn ){
++ p = pIn;
++ pIn = p->pDirty;
++ p->pDirty = 0;
++ for(i=0; ALWAYS(i<N_SORT_BUCKET-1); i++){
++ if( a[i]==0 ){
++ a[i] = p;
++ break;
++ }else{
++ p = pcacheMergeDirtyList(a[i], p);
++ a[i] = 0;
++ }
++ }
++ if( NEVER(i==N_SORT_BUCKET-1) ){
++ /* To get here, there need to be 2^(N_SORT_BUCKET) elements in
++ ** the input list. But that is impossible.
++ */
++ a[i] = pcacheMergeDirtyList(a[i], p);
++ }
+ }
+- pcache1LeaveMutex(pCache->pGroup);
++ p = a[0];
++ for(i=1; i<N_SORT_BUCKET; i++){
++ p = pcacheMergeDirtyList(p, a[i]);
++ }
++ return p;
+ }
+
+ /*
+-** Implementation of the sqlite3_pcache.xDestroy method.
+-**
+-** Destroy a cache allocated using pcache1Create().
++** Return a list of all dirty pages in the cache, sorted by page number.
+ */
+-static void pcache1Destroy(sqlite3_pcache *p){
+- PCache1 *pCache = (PCache1 *)p;
+- PGroup *pGroup = pCache->pGroup;
+- assert( pCache->bPurgeable || (pCache->nMax==0 && pCache->nMin==0) );
+- pcache1EnterMutex(pGroup);
+- pcache1TruncateUnsafe(pCache, 0);
+- assert( pGroup->nMaxPage >= pCache->nMax );
+- pGroup->nMaxPage -= pCache->nMax;
+- assert( pGroup->nMinPage >= pCache->nMin );
+- pGroup->nMinPage -= pCache->nMin;
+- pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
+- pcache1EnforceMaxPage(pGroup);
+- pcache1LeaveMutex(pGroup);
+- sqlite3_free(pCache->apHash);
+- sqlite3_free(pCache);
++SQLITE_PRIVATE PgHdr *sqlite3PcacheDirtyList(PCache *pCache){
++ PgHdr *p;
++ for(p=pCache->pDirty; p; p=p->pDirtyNext){
++ p->pDirty = p->pDirtyNext;
++ }
++ return pcacheSortDirtyList(pCache->pDirty);
++}
++
++/*
++** Return the total number of referenced pages held by the cache.
++*/
++SQLITE_PRIVATE int sqlite3PcacheRefCount(PCache *pCache){
++ return pCache->nRef;
+ }
+
+ /*
+-** This function is called during initialization (sqlite3_initialize()) to
+-** install the default pluggable cache module, assuming the user has not
+-** already provided an alternative.
++** Return the number of references to the page supplied as an argument.
+ */
+-SQLITE_PRIVATE void sqlite3PCacheSetDefault(void){
+- static const sqlite3_pcache_methods2 defaultMethods = {
+- 1, /* iVersion */
+- 0, /* pArg */
+- pcache1Init, /* xInit */
+- pcache1Shutdown, /* xShutdown */
+- pcache1Create, /* xCreate */
+- pcache1Cachesize, /* xCachesize */
+- pcache1Pagecount, /* xPagecount */
+- pcache1Fetch, /* xFetch */
+- pcache1Unpin, /* xUnpin */
+- pcache1Rekey, /* xRekey */
+- pcache1Truncate, /* xTruncate */
+- pcache1Destroy, /* xDestroy */
+- pcache1Shrink /* xShrink */
+- };
+- sqlite3_config(SQLITE_CONFIG_PCACHE2, &defaultMethods);
++SQLITE_PRIVATE int sqlite3PcachePageRefcount(PgHdr *p){
++ return p->nRef;
++}
++
++/*
++** Return the total number of pages in the cache.
++*/
++SQLITE_PRIVATE int sqlite3PcachePagecount(PCache *pCache){
++ assert( pCache->pCache!=0 );
++ return sqlite3GlobalConfig.pcache2.xPagecount(pCache->pCache);
+ }
+
++#ifdef SQLITE_TEST
+ /*
+-** Return the size of the header on each page of this PCACHE implementation.
++** Get the suggested cache-size value.
+ */
+-SQLITE_PRIVATE int sqlite3HeaderSizePcache1(void){ return ROUND8(sizeof(PgHdr1)); }
++SQLITE_PRIVATE int sqlite3PcacheGetCachesize(PCache *pCache){
++ return numberOfCachePages(pCache);
++}
++#endif
+
+ /*
+-** Return the global mutex used by this PCACHE implementation. The
+-** sqlite3_status() routine needs access to this mutex.
++** Set the suggested cache-size value.
+ */
+-SQLITE_PRIVATE sqlite3_mutex *sqlite3Pcache1Mutex(void){
+- return pcache1.mutex;
++SQLITE_PRIVATE void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){
++ assert( pCache->pCache!=0 );
++ pCache->szCache = mxPage;
++ sqlite3GlobalConfig.pcache2.xCachesize(pCache->pCache,
++ numberOfCachePages(pCache));
+ }
+
+-#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+ /*
+-** This function is called to free superfluous dynamically allocated memory
+-** held by the pager system. Memory in use by any SQLite pager allocated
+-** by the current thread may be sqlite3_free()ed.
+-**
+-** nReq is the number of bytes of memory required. Once this much has
+-** been released, the function returns. The return value is the total number
+-** of bytes of memory released.
++** Free up as much memory as possible from the page cache.
+ */
+-SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){
+- int nFree = 0;
+- assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
+- assert( sqlite3_mutex_notheld(pcache1.mutex) );
+- if( pcache1.pStart==0 ){
+- PgHdr1 *p;
+- pcache1EnterMutex(&pcache1.grp);
+- while( (nReq<0 || nFree<nReq) && ((p=pcache1.grp.pLruTail)!=0) ){
+- nFree += pcache1MemSize(p->page.pBuf);
+-#ifdef SQLITE_PCACHE_SEPARATE_HEADER
+- nFree += sqlite3MemSize(p);
+-#endif
+- assert( p->isPinned==0 );
+- pcache1PinPage(p);
+- pcache1RemoveFromHash(p);
+- pcache1FreePage(p);
+- }
+- pcache1LeaveMutex(&pcache1.grp);
+- }
+- return nFree;
++SQLITE_PRIVATE void sqlite3PcacheShrink(PCache *pCache){
++ assert( pCache->pCache!=0 );
++ sqlite3GlobalConfig.pcache2.xShrink(pCache->pCache);
+ }
+-#endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */
+
+-#ifdef SQLITE_TEST
+ /*
+-** This function is used by test procedures to inspect the internal state
+-** of the global cache.
++** Return the size of the header added by this middleware layer
++** in the page-cache hierarchy.
+ */
+-SQLITE_PRIVATE void sqlite3PcacheStats(
+- int *pnCurrent, /* OUT: Total number of pages cached */
+- int *pnMax, /* OUT: Global maximum cache size */
+- int *pnMin, /* OUT: Sum of PCache1.nMin for purgeable caches */
+- int *pnRecyclable /* OUT: Total number of pages available for recycling */
+-){
+- PgHdr1 *p;
+- int nRecyclable = 0;
+- for(p=pcache1.grp.pLruHead; p; p=p->pLruNext){
+- assert( p->isPinned==0 );
+- nRecyclable++;
++SQLITE_PRIVATE int sqlite3HeaderSizePcache(void){ return ROUND8(sizeof(PgHdr)); }
++
++
++#if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
++/*
++** For all dirty pages currently in the cache, invoke the specified
++** callback. This is only used if the SQLITE_CHECK_PAGES macro is
++** defined.
++*/
++SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *)){
++ PgHdr *pDirty;
++ for(pDirty=pCache->pDirty; pDirty; pDirty=pDirty->pDirtyNext){
++ xIter(pDirty);
+ }
+- *pnCurrent = pcache1.grp.nCurrentPage;
+- *pnMax = (int)pcache1.grp.nMaxPage;
+- *pnMin = (int)pcache1.grp.nMinPage;
+- *pnRecyclable = nRecyclable;
+ }
+ #endif
+
+-/************** End of pcache1.c *********************************************/
+-/************** Begin file rowset.c ******************************************/
++/************** End of pcache.c **********************************************/
++/************** Begin file pcache1.c *****************************************/
+ /*
+-** 2008 December 3
++** 2008 November 05
+ **
+ ** The author disclaims copyright to this source code. In place of
+ ** a legal notice, here is a blessing:
+@@ -40991,11779 +43568,12180 @@
+ **
+ *************************************************************************
+ **
+-** This module implements an object we call a "RowSet".
+-**
+-** The RowSet object is a collection of rowids. Rowids
+-** are inserted into the RowSet in an arbitrary order. Inserts
+-** can be intermixed with tests to see if a given rowid has been
+-** previously inserted into the RowSet.
+-**
+-** After all inserts are finished, it is possible to extract the
+-** elements of the RowSet in sorted order. Once this extraction
+-** process has started, no new elements may be inserted.
+-**
+-** Hence, the primitive operations for a RowSet are:
+-**
+-** CREATE
+-** INSERT
+-** TEST
+-** SMALLEST
+-** DESTROY
++** This file implements the default page cache implementation (the
++** sqlite3_pcache interface). It also contains part of the implementation
++** of the SQLITE_CONFIG_PAGECACHE and sqlite3_release_memory() features.
++** If the default page cache implementation is overridden, then neither of
++** these two features are available.
++*/
++
++
++typedef struct PCache1 PCache1;
++typedef struct PgHdr1 PgHdr1;
++typedef struct PgFreeslot PgFreeslot;
++typedef struct PGroup PGroup;
++
++/* Each page cache (or PCache) belongs to a PGroup. A PGroup is a set
++** of one or more PCaches that are able to recycle each other's unpinned
++** pages when they are under memory pressure. A PGroup is an instance of
++** the following object.
+ **
+-** The CREATE and DESTROY primitives are the constructor and destructor,
+-** obviously. The INSERT primitive adds a new element to the RowSet.
+-** TEST checks to see if an element is already in the RowSet. SMALLEST
+-** extracts the least value from the RowSet.
++** This page cache implementation works in one of two modes:
+ **
+-** The INSERT primitive might allocate additional memory. Memory is
+-** allocated in chunks so most INSERTs do no allocation. There is an
+-** upper bound on the size of allocated memory. No memory is freed
+-** until DESTROY.
++** (1) Every PCache is the sole member of its own PGroup. There is
++** one PGroup per PCache.
+ **
+-** The TEST primitive includes a "batch" number. The TEST primitive
+-** will only see elements that were inserted before the last change
+-** in the batch number. In other words, if an INSERT occurs between
+-** two TESTs where the TESTs have the same batch nubmer, then the
+-** value added by the INSERT will not be visible to the second TEST.
+-** The initial batch number is zero, so if the very first TEST contains
+-** a non-zero batch number, it will see all prior INSERTs.
++** (2) There is a single global PGroup that all PCaches are a member
++** of.
+ **
+-** No INSERTs may occurs after a SMALLEST. An assertion will fail if
+-** that is attempted.
++** Mode 1 uses more memory (since PCache instances are not able to rob
++** unused pages from other PCaches) but it also operates without a mutex,
++** and is therefore often faster. Mode 2 requires a mutex in order to be
++** threadsafe, but recycles pages more efficiently.
+ **
+-** The cost of an INSERT is roughly constant. (Sometimes new memory
+-** has to be allocated on an INSERT.) The cost of a TEST with a new
+-** batch number is O(NlogN) where N is the number of elements in the RowSet.
+-** The cost of a TEST using the same batch number is O(logN). The cost
+-** of the first SMALLEST is O(NlogN). Second and subsequent SMALLEST
+-** primitives are constant time. The cost of DESTROY is O(N).
++** For mode (1), PGroup.mutex is NULL. For mode (2) there is only a single
++** PGroup which is the pcache1.grp global variable and its mutex is
++** SQLITE_MUTEX_STATIC_LRU.
++*/
++struct PGroup {
++ sqlite3_mutex *mutex; /* MUTEX_STATIC_LRU or NULL */
++ unsigned int nMaxPage; /* Sum of nMax for purgeable caches */
++ unsigned int nMinPage; /* Sum of nMin for purgeable caches */
++ unsigned int mxPinned; /* nMaxpage + 10 - nMinPage */
++ unsigned int nCurrentPage; /* Number of purgeable pages allocated */
++ PgHdr1 *pLruHead, *pLruTail; /* LRU list of unpinned pages */
++};
++
++/* Each page cache is an instance of the following object. Every
++** open database file (including each in-memory database and each
++** temporary or transient database) has a single page cache which
++** is an instance of this object.
+ **
+-** There is an added cost of O(N) when switching between TEST and
+-** SMALLEST primitives.
++** Pointers to structures of this type are cast and returned as
++** opaque sqlite3_pcache* handles.
+ */
++struct PCache1 {
++ /* Cache configuration parameters. Page size (szPage) and the purgeable
++ ** flag (bPurgeable) are set when the cache is created. nMax may be
++ ** modified at any time by a call to the pcache1Cachesize() method.
++ ** The PGroup mutex must be held when accessing nMax.
++ */
++ PGroup *pGroup; /* PGroup this cache belongs to */
++ int szPage; /* Size of allocated pages in bytes */
++ int szExtra; /* Size of extra space in bytes */
++ int bPurgeable; /* True if cache is purgeable */
++ unsigned int nMin; /* Minimum number of pages reserved */
++ unsigned int nMax; /* Configured "cache_size" value */
++ unsigned int n90pct; /* nMax*9/10 */
++ unsigned int iMaxKey; /* Largest key seen since xTruncate() */
+
++ /* Hash table of all pages. The following variables may only be accessed
++ ** when the accessor is holding the PGroup mutex.
++ */
++ unsigned int nRecyclable; /* Number of pages in the LRU list */
++ unsigned int nPage; /* Total number of pages in apHash */
++ unsigned int nHash; /* Number of slots in apHash[] */
++ PgHdr1 **apHash; /* Hash table for fast lookup by key */
++};
+
+ /*
+-** Target size for allocation chunks.
++** Each cache entry is represented by an instance of the following
++** structure. Unless SQLITE_PCACHE_SEPARATE_HEADER is defined, a buffer of
++** PgHdr1.pCache->szPage bytes is allocated directly before this structure
++** in memory.
+ */
+-#define ROWSET_ALLOCATION_SIZE 1024
++struct PgHdr1 {
++ sqlite3_pcache_page page;
++ unsigned int iKey; /* Key value (page number) */
++ u8 isPinned; /* Page in use, not on the LRU list */
++ PgHdr1 *pNext; /* Next in hash table chain */
++ PCache1 *pCache; /* Cache that currently owns this page */
++ PgHdr1 *pLruNext; /* Next in LRU list of unpinned pages */
++ PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */
++};
+
+ /*
+-** The number of rowset entries per allocation chunk.
++** Free slots in the allocator used to divide up the buffer provided using
++** the SQLITE_CONFIG_PAGECACHE mechanism.
+ */
+-#define ROWSET_ENTRY_PER_CHUNK \
+- ((ROWSET_ALLOCATION_SIZE-8)/sizeof(struct RowSetEntry))
++struct PgFreeslot {
++ PgFreeslot *pNext; /* Next free slot */
++};
+
+ /*
+-** Each entry in a RowSet is an instance of the following object.
+-**
+-** This same object is reused to store a linked list of trees of RowSetEntry
+-** objects. In that alternative use, pRight points to the next entry
+-** in the list, pLeft points to the tree, and v is unused. The
+-** RowSet.pForest value points to the head of this forest list.
++** Global data used by this cache.
+ */
+-struct RowSetEntry {
+- i64 v; /* ROWID value for this entry */
+- struct RowSetEntry *pRight; /* Right subtree (larger entries) or list */
+- struct RowSetEntry *pLeft; /* Left subtree (smaller entries) */
+-};
++static SQLITE_WSD struct PCacheGlobal {
++ PGroup grp; /* The global PGroup for mode (2) */
++
++ /* Variables related to SQLITE_CONFIG_PAGECACHE settings. The
++ ** szSlot, nSlot, pStart, pEnd, nReserve, and isInit values are all
++ ** fixed at sqlite3_initialize() time and do not require mutex protection.
++ ** The nFreeSlot and pFree values do require mutex protection.
++ */
++ int isInit; /* True if initialized */
++ int szSlot; /* Size of each free slot */
++ int nSlot; /* The number of pcache slots */
++ int nReserve; /* Try to keep nFreeSlot above this */
++ void *pStart, *pEnd; /* Bounds of pagecache malloc range */
++ /* Above requires no mutex. Use mutex below for variable that follow. */
++ sqlite3_mutex *mutex; /* Mutex for accessing the following: */
++ PgFreeslot *pFree; /* Free page blocks */
++ int nFreeSlot; /* Number of unused pcache slots */
++ /* The following value requires a mutex to change. We skip the mutex on
++ ** reading because (1) most platforms read a 32-bit integer atomically and
++ ** (2) even if an incorrect value is read, no great harm is done since this
++ ** is really just an optimization. */
++ int bUnderPressure; /* True if low on PAGECACHE memory */
++} pcache1_g;
+
+ /*
+-** RowSetEntry objects are allocated in large chunks (instances of the
+-** following structure) to reduce memory allocation overhead. The
+-** chunks are kept on a linked list so that they can be deallocated
+-** when the RowSet is destroyed.
++** All code in this file should access the global structure above via the
++** alias "pcache1". This ensures that the WSD emulation is used when
++** compiling for systems that do not support real WSD.
+ */
+-struct RowSetChunk {
+- struct RowSetChunk *pNextChunk; /* Next chunk on list of them all */
+- struct RowSetEntry aEntry[ROWSET_ENTRY_PER_CHUNK]; /* Allocated entries */
+-};
++#define pcache1 (GLOBAL(struct PCacheGlobal, pcache1_g))
+
+ /*
+-** A RowSet in an instance of the following structure.
+-**
+-** A typedef of this structure if found in sqliteInt.h.
++** Macros to enter and leave the PCache LRU mutex.
+ */
+-struct RowSet {
+- struct RowSetChunk *pChunk; /* List of all chunk allocations */
+- sqlite3 *db; /* The database connection */
+- struct RowSetEntry *pEntry; /* List of entries using pRight */
+- struct RowSetEntry *pLast; /* Last entry on the pEntry list */
+- struct RowSetEntry *pFresh; /* Source of new entry objects */
+- struct RowSetEntry *pForest; /* List of binary trees of entries */
+- u16 nFresh; /* Number of objects on pFresh */
+- u16 rsFlags; /* Various flags */
+- int iBatch; /* Current insert batch */
+-};
++#define pcache1EnterMutex(X) sqlite3_mutex_enter((X)->mutex)
++#define pcache1LeaveMutex(X) sqlite3_mutex_leave((X)->mutex)
++
++/******************************************************************************/
++/******** Page Allocation/SQLITE_CONFIG_PCACHE Related Functions **************/
+
+ /*
+-** Allowed values for RowSet.rsFlags
++** This function is called during initialization if a static buffer is
++** supplied to use for the page-cache by passing the SQLITE_CONFIG_PAGECACHE
++** verb to sqlite3_config(). Parameter pBuf points to an allocation large
++** enough to contain 'n' buffers of 'sz' bytes each.
++**
++** This routine is called from sqlite3_initialize() and so it is guaranteed
++** to be serialized already. There is no need for further mutexing.
+ */
+-#define ROWSET_SORTED 0x01 /* True if RowSet.pEntry is sorted */
+-#define ROWSET_NEXT 0x02 /* True if sqlite3RowSetNext() has been called */
++SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
++ if( pcache1.isInit ){
++ PgFreeslot *p;
++ sz = ROUNDDOWN8(sz);
++ pcache1.szSlot = sz;
++ pcache1.nSlot = pcache1.nFreeSlot = n;
++ pcache1.nReserve = n>90 ? 10 : (n/10 + 1);
++ pcache1.pStart = pBuf;
++ pcache1.pFree = 0;
++ pcache1.bUnderPressure = 0;
++ while( n-- ){
++ p = (PgFreeslot*)pBuf;
++ p->pNext = pcache1.pFree;
++ pcache1.pFree = p;
++ pBuf = (void*)&((char*)pBuf)[sz];
++ }
++ pcache1.pEnd = pBuf;
++ }
++}
+
+ /*
+-** Turn bulk memory into a RowSet object. N bytes of memory
+-** are available at pSpace. The db pointer is used as a memory context
+-** for any subsequent allocations that need to occur.
+-** Return a pointer to the new RowSet object.
++** Malloc function used within this file to allocate space from the buffer
++** configured using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no
++** such buffer exists or there is no space left in it, this function falls
++** back to sqlite3Malloc().
+ **
+-** It must be the case that N is sufficient to make a Rowset. If not
+-** an assertion fault occurs.
+-**
+-** If N is larger than the minimum, use the surplus as an initial
+-** allocation of entries available to be filled.
++** Multiple threads can run this routine at the same time. Global variables
++** in pcache1 need to be protected via mutex.
+ */
+-SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3 *db, void *pSpace, unsigned int N){
+- RowSet *p;
+- assert( N >= ROUND8(sizeof(*p)) );
+- p = pSpace;
+- p->pChunk = 0;
+- p->db = db;
+- p->pEntry = 0;
+- p->pLast = 0;
+- p->pForest = 0;
+- p->pFresh = (struct RowSetEntry*)(ROUND8(sizeof(*p)) + (char*)p);
+- p->nFresh = (u16)((N - ROUND8(sizeof(*p)))/sizeof(struct RowSetEntry));
+- p->rsFlags = ROWSET_SORTED;
+- p->iBatch = 0;
++static void *pcache1Alloc(int nByte){
++ void *p = 0;
++ assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
++ if( nByte<=pcache1.szSlot ){
++ sqlite3_mutex_enter(pcache1.mutex);
++ p = (PgHdr1 *)pcache1.pFree;
++ if( p ){
++ pcache1.pFree = pcache1.pFree->pNext;
++ pcache1.nFreeSlot--;
++ pcache1.bUnderPressure = pcache1.nFreeSlot<pcache1.nReserve;
++ assert( pcache1.nFreeSlot>=0 );
++ sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
++ sqlite3StatusUp(SQLITE_STATUS_PAGECACHE_USED, 1);
++ }
++ sqlite3_mutex_leave(pcache1.mutex);
++ }
++ if( p==0 ){
++ /* Memory is not available in the SQLITE_CONFIG_PAGECACHE pool. Get
++ ** it from sqlite3Malloc instead.
++ */
++ p = sqlite3Malloc(nByte);
++#ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
++ if( p ){
++ int sz = sqlite3MallocSize(p);
++ sqlite3_mutex_enter(pcache1.mutex);
++ sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
++ sqlite3StatusUp(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz);
++ sqlite3_mutex_leave(pcache1.mutex);
++ }
++#endif
++ sqlite3MemdebugSetType(p, MEMTYPE_PCACHE);
++ }
+ return p;
+ }
+
+ /*
+-** Deallocate all chunks from a RowSet. This frees all memory that
+-** the RowSet has allocated over its lifetime. This routine is
+-** the destructor for the RowSet.
++** Free an allocated buffer obtained from pcache1Alloc().
+ */
+-SQLITE_PRIVATE void sqlite3RowSetClear(RowSet *p){
+- struct RowSetChunk *pChunk, *pNextChunk;
+- for(pChunk=p->pChunk; pChunk; pChunk = pNextChunk){
+- pNextChunk = pChunk->pNextChunk;
+- sqlite3DbFree(p->db, pChunk);
++static int pcache1Free(void *p){
++ int nFreed = 0;
++ if( p==0 ) return 0;
++ if( p>=pcache1.pStart && p<pcache1.pEnd ){
++ PgFreeslot *pSlot;
++ sqlite3_mutex_enter(pcache1.mutex);
++ sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_USED, 1);
++ pSlot = (PgFreeslot*)p;
++ pSlot->pNext = pcache1.pFree;
++ pcache1.pFree = pSlot;
++ pcache1.nFreeSlot++;
++ pcache1.bUnderPressure = pcache1.nFreeSlot<pcache1.nReserve;
++ assert( pcache1.nFreeSlot<=pcache1.nSlot );
++ sqlite3_mutex_leave(pcache1.mutex);
++ }else{
++ assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) );
++ sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
++ nFreed = sqlite3MallocSize(p);
++#ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
++ sqlite3_mutex_enter(pcache1.mutex);
++ sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_OVERFLOW, nFreed);
++ sqlite3_mutex_leave(pcache1.mutex);
++#endif
++ sqlite3_free(p);
+ }
+- p->pChunk = 0;
+- p->nFresh = 0;
+- p->pEntry = 0;
+- p->pLast = 0;
+- p->pForest = 0;
+- p->rsFlags = ROWSET_SORTED;
++ return nFreed;
+ }
+
++#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+ /*
+-** Allocate a new RowSetEntry object that is associated with the
+-** given RowSet. Return a pointer to the new and completely uninitialized
+-** objected.
+-**
+-** In an OOM situation, the RowSet.db->mallocFailed flag is set and this
+-** routine returns NULL.
++** Return the size of a pcache allocation
+ */
+-static struct RowSetEntry *rowSetEntryAlloc(RowSet *p){
+- assert( p!=0 );
+- if( p->nFresh==0 ){
+- struct RowSetChunk *pNew;
+- pNew = sqlite3DbMallocRaw(p->db, sizeof(*pNew));
+- if( pNew==0 ){
+- return 0;
+- }
+- pNew->pNextChunk = p->pChunk;
+- p->pChunk = pNew;
+- p->pFresh = pNew->aEntry;
+- p->nFresh = ROWSET_ENTRY_PER_CHUNK;
++static int pcache1MemSize(void *p){
++ if( p>=pcache1.pStart && p<pcache1.pEnd ){
++ return pcache1.szSlot;
++ }else{
++ int iSize;
++ assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) );
++ sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
++ iSize = sqlite3MallocSize(p);
++ sqlite3MemdebugSetType(p, MEMTYPE_PCACHE);
++ return iSize;
+ }
+- p->nFresh--;
+- return p->pFresh++;
+ }
++#endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */
+
+ /*
+-** Insert a new value into a RowSet.
+-**
+-** The mallocFailed flag of the database connection is set if a
+-** memory allocation fails.
++** Allocate a new page object initially associated with cache pCache.
+ */
+-SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet *p, i64 rowid){
+- struct RowSetEntry *pEntry; /* The new entry */
+- struct RowSetEntry *pLast; /* The last prior entry */
++static PgHdr1 *pcache1AllocPage(PCache1 *pCache){
++ PgHdr1 *p = 0;
++ void *pPg;
+
+- /* This routine is never called after sqlite3RowSetNext() */
+- assert( p!=0 && (p->rsFlags & ROWSET_NEXT)==0 );
++ /* The group mutex must be released before pcache1Alloc() is called. This
++ ** is because it may call sqlite3_release_memory(), which assumes that
++ ** this mutex is not held. */
++ assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
++ pcache1LeaveMutex(pCache->pGroup);
++#ifdef SQLITE_PCACHE_SEPARATE_HEADER
++ pPg = pcache1Alloc(pCache->szPage);
++ p = sqlite3Malloc(sizeof(PgHdr1) + pCache->szExtra);
++ if( !pPg || !p ){
++ pcache1Free(pPg);
++ sqlite3_free(p);
++ pPg = 0;
++ }
++#else
++ pPg = pcache1Alloc(ROUND8(sizeof(PgHdr1)) + pCache->szPage + pCache->szExtra);
++ p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
++#endif
++ pcache1EnterMutex(pCache->pGroup);
+
+- pEntry = rowSetEntryAlloc(p);
+- if( pEntry==0 ) return;
+- pEntry->v = rowid;
+- pEntry->pRight = 0;
+- pLast = p->pLast;
+- if( pLast ){
+- if( (p->rsFlags & ROWSET_SORTED)!=0 && rowid<=pLast->v ){
+- p->rsFlags &= ~ROWSET_SORTED;
++ if( pPg ){
++ p->page.pBuf = pPg;
++ p->page.pExtra = &p[1];
++ if( pCache->bPurgeable ){
++ pCache->pGroup->nCurrentPage++;
+ }
+- pLast->pRight = pEntry;
+- }else{
+- p->pEntry = pEntry;
++ return p;
+ }
+- p->pLast = pEntry;
++ return 0;
+ }
+
+ /*
+-** Merge two lists of RowSetEntry objects. Remove duplicates.
++** Free a page object allocated by pcache1AllocPage().
+ **
+-** The input lists are connected via pRight pointers and are
+-** assumed to each already be in sorted order.
++** The pointer is allowed to be NULL, which is prudent. But it turns out
++** that the current implementation happens to never call this routine
++** with a NULL pointer, so we mark the NULL test with ALWAYS().
+ */
+-static struct RowSetEntry *rowSetEntryMerge(
+- struct RowSetEntry *pA, /* First sorted list to be merged */
+- struct RowSetEntry *pB /* Second sorted list to be merged */
+-){
+- struct RowSetEntry head;
+- struct RowSetEntry *pTail;
+-
+- pTail = &head;
+- while( pA && pB ){
+- assert( pA->pRight==0 || pA->v<=pA->pRight->v );
+- assert( pB->pRight==0 || pB->v<=pB->pRight->v );
+- if( pA->v<pB->v ){
+- pTail->pRight = pA;
+- pA = pA->pRight;
+- pTail = pTail->pRight;
+- }else if( pB->v<pA->v ){
+- pTail->pRight = pB;
+- pB = pB->pRight;
+- pTail = pTail->pRight;
+- }else{
+- pA = pA->pRight;
++static void pcache1FreePage(PgHdr1 *p){
++ if( ALWAYS(p) ){
++ PCache1 *pCache = p->pCache;
++ assert( sqlite3_mutex_held(p->pCache->pGroup->mutex) );
++ pcache1Free(p->page.pBuf);
++#ifdef SQLITE_PCACHE_SEPARATE_HEADER
++ sqlite3_free(p);
++#endif
++ if( pCache->bPurgeable ){
++ pCache->pGroup->nCurrentPage--;
+ }
+ }
+- if( pA ){
+- assert( pA->pRight==0 || pA->v<=pA->pRight->v );
+- pTail->pRight = pA;
+- }else{
+- assert( pB==0 || pB->pRight==0 || pB->v<=pB->pRight->v );
+- pTail->pRight = pB;
+- }
+- return head.pRight;
+ }
+
+ /*
+-** Sort all elements on the list of RowSetEntry objects into order of
+-** increasing v.
+-*/
+-static struct RowSetEntry *rowSetEntrySort(struct RowSetEntry *pIn){
+- unsigned int i;
+- struct RowSetEntry *pNext, *aBucket[40];
+-
+- memset(aBucket, 0, sizeof(aBucket));
+- while( pIn ){
+- pNext = pIn->pRight;
+- pIn->pRight = 0;
+- for(i=0; aBucket[i]; i++){
+- pIn = rowSetEntryMerge(aBucket[i], pIn);
+- aBucket[i] = 0;
+- }
+- aBucket[i] = pIn;
+- pIn = pNext;
+- }
+- pIn = 0;
+- for(i=0; i<sizeof(aBucket)/sizeof(aBucket[0]); i++){
+- pIn = rowSetEntryMerge(pIn, aBucket[i]);
+- }
+- return pIn;
++** Malloc function used by SQLite to obtain space from the buffer configured
++** using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no such buffer
++** exists, this function falls back to sqlite3Malloc().
++*/
++SQLITE_PRIVATE void *sqlite3PageMalloc(int sz){
++ return pcache1Alloc(sz);
+ }
+
+-
+ /*
+-** The input, pIn, is a binary tree (or subtree) of RowSetEntry objects.
+-** Convert this tree into a linked list connected by the pRight pointers
+-** and return pointers to the first and last elements of the new list.
++** Free an allocated buffer obtained from sqlite3PageMalloc().
+ */
+-static void rowSetTreeToList(
+- struct RowSetEntry *pIn, /* Root of the input tree */
+- struct RowSetEntry **ppFirst, /* Write head of the output list here */
+- struct RowSetEntry **ppLast /* Write tail of the output list here */
+-){
+- assert( pIn!=0 );
+- if( pIn->pLeft ){
+- struct RowSetEntry *p;
+- rowSetTreeToList(pIn->pLeft, ppFirst, &p);
+- p->pRight = pIn;
+- }else{
+- *ppFirst = pIn;
+- }
+- if( pIn->pRight ){
+- rowSetTreeToList(pIn->pRight, &pIn->pRight, ppLast);
+- }else{
+- *ppLast = pIn;
+- }
+- assert( (*ppLast)->pRight==0 );
++SQLITE_PRIVATE void sqlite3PageFree(void *p){
++ pcache1Free(p);
+ }
+
+
+ /*
+-** Convert a sorted list of elements (connected by pRight) into a binary
+-** tree with depth of iDepth. A depth of 1 means the tree contains a single
+-** node taken from the head of *ppList. A depth of 2 means a tree with
+-** three nodes. And so forth.
++** Return true if it desirable to avoid allocating a new page cache
++** entry.
+ **
+-** Use as many entries from the input list as required and update the
+-** *ppList to point to the unused elements of the list. If the input
+-** list contains too few elements, then construct an incomplete tree
+-** and leave *ppList set to NULL.
++** If memory was allocated specifically to the page cache using
++** SQLITE_CONFIG_PAGECACHE but that memory has all been used, then
++** it is desirable to avoid allocating a new page cache entry because
++** presumably SQLITE_CONFIG_PAGECACHE was suppose to be sufficient
++** for all page cache needs and we should not need to spill the
++** allocation onto the heap.
+ **
+-** Return a pointer to the root of the constructed binary tree.
++** Or, the heap is used for all page cache memory but the heap is
++** under memory pressure, then again it is desirable to avoid
++** allocating a new page cache entry in order to avoid stressing
++** the heap even further.
+ */
+-static struct RowSetEntry *rowSetNDeepTree(
+- struct RowSetEntry **ppList,
+- int iDepth
+-){
+- struct RowSetEntry *p; /* Root of the new tree */
+- struct RowSetEntry *pLeft; /* Left subtree */
+- if( *ppList==0 ){
+- return 0;
+- }
+- if( iDepth==1 ){
+- p = *ppList;
+- *ppList = p->pRight;
+- p->pLeft = p->pRight = 0;
+- return p;
+- }
+- pLeft = rowSetNDeepTree(ppList, iDepth-1);
+- p = *ppList;
+- if( p==0 ){
+- return pLeft;
++static int pcache1UnderMemoryPressure(PCache1 *pCache){
++ if( pcache1.nSlot && (pCache->szPage+pCache->szExtra)<=pcache1.szSlot ){
++ return pcache1.bUnderPressure;
++ }else{
++ return sqlite3HeapNearlyFull();
+ }
+- p->pLeft = pLeft;
+- *ppList = p->pRight;
+- p->pRight = rowSetNDeepTree(ppList, iDepth-1);
+- return p;
+ }
+
+-/*
+-** Convert a sorted list of elements into a binary tree. Make the tree
+-** as deep as it needs to be in order to contain the entire list.
+-*/
+-static struct RowSetEntry *rowSetListToTree(struct RowSetEntry *pList){
+- int iDepth; /* Depth of the tree so far */
+- struct RowSetEntry *p; /* Current tree root */
+- struct RowSetEntry *pLeft; /* Left subtree */
+-
+- assert( pList!=0 );
+- p = pList;
+- pList = p->pRight;
+- p->pLeft = p->pRight = 0;
+- for(iDepth=1; pList; iDepth++){
+- pLeft = p;
+- p = pList;
+- pList = p->pRight;
+- p->pLeft = pLeft;
+- p->pRight = rowSetNDeepTree(&pList, iDepth);
+- }
+- return p;
+-}
++/******************************************************************************/
++/******** General Implementation Functions ************************************/
+
+ /*
+-** Take all the entries on p->pEntry and on the trees in p->pForest and
+-** sort them all together into one big ordered list on p->pEntry.
++** This function is used to resize the hash table used by the cache passed
++** as the first argument.
+ **
+-** This routine should only be called once in the life of a RowSet.
++** The PCache mutex must be held when this function is called.
+ */
+-static void rowSetToList(RowSet *p){
++static void pcache1ResizeHash(PCache1 *p){
++ PgHdr1 **apNew;
++ unsigned int nNew;
++ unsigned int i;
+
+- /* This routine is called only once */
+- assert( p!=0 && (p->rsFlags & ROWSET_NEXT)==0 );
++ assert( sqlite3_mutex_held(p->pGroup->mutex) );
+
+- if( (p->rsFlags & ROWSET_SORTED)==0 ){
+- p->pEntry = rowSetEntrySort(p->pEntry);
++ nNew = p->nHash*2;
++ if( nNew<256 ){
++ nNew = 256;
+ }
+
+- /* While this module could theoretically support it, sqlite3RowSetNext()
+- ** is never called after sqlite3RowSetText() for the same RowSet. So
+- ** there is never a forest to deal with. Should this change, simply
+- ** remove the assert() and the #if 0. */
+- assert( p->pForest==0 );
+-#if 0
+- while( p->pForest ){
+- struct RowSetEntry *pTree = p->pForest->pLeft;
+- if( pTree ){
+- struct RowSetEntry *pHead, *pTail;
+- rowSetTreeToList(pTree, &pHead, &pTail);
+- p->pEntry = rowSetEntryMerge(p->pEntry, pHead);
++ pcache1LeaveMutex(p->pGroup);
++ if( p->nHash ){ sqlite3BeginBenignMalloc(); }
++ apNew = (PgHdr1 **)sqlite3MallocZero(sizeof(PgHdr1 *)*nNew);
++ if( p->nHash ){ sqlite3EndBenignMalloc(); }
++ pcache1EnterMutex(p->pGroup);
++ if( apNew ){
++ for(i=0; i<p->nHash; i++){
++ PgHdr1 *pPage;
++ PgHdr1 *pNext = p->apHash[i];
++ while( (pPage = pNext)!=0 ){
++ unsigned int h = pPage->iKey % nNew;
++ pNext = pPage->pNext;
++ pPage->pNext = apNew[h];
++ apNew[h] = pPage;
++ }
+ }
+- p->pForest = p->pForest->pRight;
++ sqlite3_free(p->apHash);
++ p->apHash = apNew;
++ p->nHash = nNew;
+ }
+-#endif
+- p->rsFlags |= ROWSET_NEXT; /* Verify this routine is never called again */
+ }
+
+ /*
+-** Extract the smallest element from the RowSet.
+-** Write the element into *pRowid. Return 1 on success. Return
+-** 0 if the RowSet is already empty.
++** This function is used internally to remove the page pPage from the
++** PGroup LRU list, if is part of it. If pPage is not part of the PGroup
++** LRU list, then this function is a no-op.
+ **
+-** After this routine has been called, the sqlite3RowSetInsert()
+-** routine may not be called again.
++** The PGroup mutex must be held when this function is called.
+ */
+-SQLITE_PRIVATE int sqlite3RowSetNext(RowSet *p, i64 *pRowid){
+- assert( p!=0 );
+-
+- /* Merge the forest into a single sorted list on first call */
+- if( (p->rsFlags & ROWSET_NEXT)==0 ) rowSetToList(p);
++static void pcache1PinPage(PgHdr1 *pPage){
++ PCache1 *pCache;
++ PGroup *pGroup;
+
+- /* Return the next entry on the list */
+- if( p->pEntry ){
+- *pRowid = p->pEntry->v;
+- p->pEntry = p->pEntry->pRight;
+- if( p->pEntry==0 ){
+- sqlite3RowSetClear(p);
+- }
+- return 1;
++ assert( pPage!=0 );
++ assert( pPage->isPinned==0 );
++ pCache = pPage->pCache;
++ pGroup = pCache->pGroup;
++ assert( pPage->pLruNext || pPage==pGroup->pLruTail );
++ assert( pPage->pLruPrev || pPage==pGroup->pLruHead );
++ assert( sqlite3_mutex_held(pGroup->mutex) );
++ if( pPage->pLruPrev ){
++ pPage->pLruPrev->pLruNext = pPage->pLruNext;
+ }else{
+- return 0;
++ pGroup->pLruHead = pPage->pLruNext;
++ }
++ if( pPage->pLruNext ){
++ pPage->pLruNext->pLruPrev = pPage->pLruPrev;
++ }else{
++ pGroup->pLruTail = pPage->pLruPrev;
+ }
++ pPage->pLruNext = 0;
++ pPage->pLruPrev = 0;
++ pPage->isPinned = 1;
++ pCache->nRecyclable--;
+ }
+
++
+ /*
+-** Check to see if element iRowid was inserted into the rowset as
+-** part of any insert batch prior to iBatch. Return 1 or 0.
++** Remove the page supplied as an argument from the hash table
++** (PCache1.apHash structure) that it is currently stored in.
+ **
+-** If this is the first test of a new batch and if there exist entries
+-** on pRowSet->pEntry, then sort those entries into the forest at
+-** pRowSet->pForest so that they can be tested.
++** The PGroup mutex must be held when this function is called.
+ */
+-SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64 iRowid){
+- struct RowSetEntry *p, *pTree;
++static void pcache1RemoveFromHash(PgHdr1 *pPage){
++ unsigned int h;
++ PCache1 *pCache = pPage->pCache;
++ PgHdr1 **pp;
+
+- /* This routine is never called after sqlite3RowSetNext() */
+- assert( pRowSet!=0 && (pRowSet->rsFlags & ROWSET_NEXT)==0 );
++ assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
++ h = pPage->iKey % pCache->nHash;
++ for(pp=&pCache->apHash[h]; (*pp)!=pPage; pp=&(*pp)->pNext);
++ *pp = (*pp)->pNext;
+
+- /* Sort entries into the forest on the first test of a new batch
+- */
+- if( iBatch!=pRowSet->iBatch ){
+- p = pRowSet->pEntry;
+- if( p ){
+- struct RowSetEntry **ppPrevTree = &pRowSet->pForest;
+- if( (pRowSet->rsFlags & ROWSET_SORTED)==0 ){
+- p = rowSetEntrySort(p);
+- }
+- for(pTree = pRowSet->pForest; pTree; pTree=pTree->pRight){
+- ppPrevTree = &pTree->pRight;
+- if( pTree->pLeft==0 ){
+- pTree->pLeft = rowSetListToTree(p);
+- break;
+- }else{
+- struct RowSetEntry *pAux, *pTail;
+- rowSetTreeToList(pTree->pLeft, &pAux, &pTail);
+- pTree->pLeft = 0;
+- p = rowSetEntryMerge(pAux, p);
+- }
+- }
+- if( pTree==0 ){
+- *ppPrevTree = pTree = rowSetEntryAlloc(pRowSet);
+- if( pTree ){
+- pTree->v = 0;
+- pTree->pRight = 0;
+- pTree->pLeft = rowSetListToTree(p);
+- }
+- }
+- pRowSet->pEntry = 0;
+- pRowSet->pLast = 0;
+- pRowSet->rsFlags |= ROWSET_SORTED;
+- }
+- pRowSet->iBatch = iBatch;
++ pCache->nPage--;
++}
++
++/*
++** If there are currently more than nMaxPage pages allocated, try
++** to recycle pages to reduce the number allocated to nMaxPage.
++*/
++static void pcache1EnforceMaxPage(PGroup *pGroup){
++ assert( sqlite3_mutex_held(pGroup->mutex) );
++ while( pGroup->nCurrentPage>pGroup->nMaxPage && pGroup->pLruTail ){
++ PgHdr1 *p = pGroup->pLruTail;
++ assert( p->pCache->pGroup==pGroup );
++ assert( p->isPinned==0 );
++ pcache1PinPage(p);
++ pcache1RemoveFromHash(p);
++ pcache1FreePage(p);
+ }
++}
+
+- /* Test to see if the iRowid value appears anywhere in the forest.
+- ** Return 1 if it does and 0 if not.
+- */
+- for(pTree = pRowSet->pForest; pTree; pTree=pTree->pRight){
+- p = pTree->pLeft;
+- while( p ){
+- if( p->v<iRowid ){
+- p = p->pRight;
+- }else if( p->v>iRowid ){
+- p = p->pLeft;
++/*
++** Discard all pages from cache pCache with a page number (key value)
++** greater than or equal to iLimit. Any pinned pages that meet this
++** criteria are unpinned before they are discarded.
++**
++** The PCache mutex must be held when this function is called.
++*/
++static void pcache1TruncateUnsafe(
++ PCache1 *pCache, /* The cache to truncate */
++ unsigned int iLimit /* Drop pages with this pgno or larger */
++){
++ TESTONLY( unsigned int nPage = 0; ) /* To assert pCache->nPage is correct */
++ unsigned int h;
++ assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
++ for(h=0; h<pCache->nHash; h++){
++ PgHdr1 **pp = &pCache->apHash[h];
++ PgHdr1 *pPage;
++ while( (pPage = *pp)!=0 ){
++ if( pPage->iKey>=iLimit ){
++ pCache->nPage--;
++ *pp = pPage->pNext;
++ if( !pPage->isPinned ) pcache1PinPage(pPage);
++ pcache1FreePage(pPage);
+ }else{
+- return 1;
++ pp = &pPage->pNext;
++ TESTONLY( nPage++; )
+ }
+ }
+ }
+- return 0;
++ assert( pCache->nPage==nPage );
+ }
+
+-/************** End of rowset.c **********************************************/
+-/************** Begin file pager.c *******************************************/
++/******************************************************************************/
++/******** sqlite3_pcache Methods **********************************************/
++
+ /*
+-** 2001 September 15
+-**
+-** The author disclaims copyright to this source code. In place of
+-** a legal notice, here is a blessing:
+-**
+-** May you do good and not evil.
+-** May you find forgiveness for yourself and forgive others.
+-** May you share freely, never taking more than you give.
+-**
+-*************************************************************************
+-** This is the implementation of the page cache subsystem or "pager".
+-**
+-** The pager is used to access a database disk file. It implements
+-** atomic commit and rollback through the use of a journal file that
+-** is separate from the database file. The pager also implements file
+-** locking to prevent two processes from writing the same database
+-** file simultaneously, or one process from reading the database while
+-** another is writing.
++** Implementation of the sqlite3_pcache.xInit method.
+ */
+-#ifndef SQLITE_OMIT_DISKIO
+-/************** Include wal.h in the middle of pager.c ***********************/
+-/************** Begin file wal.h *********************************************/
++static int pcache1Init(void *NotUsed){
++ UNUSED_PARAMETER(NotUsed);
++ assert( pcache1.isInit==0 );
++ memset(&pcache1, 0, sizeof(pcache1));
++ if( sqlite3GlobalConfig.bCoreMutex ){
++ pcache1.grp.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU);
++ pcache1.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PMEM);
++ }
++ pcache1.grp.mxPinned = 10;
++ pcache1.isInit = 1;
++ return SQLITE_OK;
++}
++
+ /*
+-** 2010 February 1
+-**
+-** 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 header file defines the interface to the write-ahead logging
+-** system. Refer to the comments below and the header comment attached to
+-** the implementation of each function in log.c for further details.
++** Implementation of the sqlite3_pcache.xShutdown method.
++** Note that the static mutex allocated in xInit does
++** not need to be freed.
+ */
++static void pcache1Shutdown(void *NotUsed){
++ UNUSED_PARAMETER(NotUsed);
++ assert( pcache1.isInit!=0 );
++ memset(&pcache1, 0, sizeof(pcache1));
++}
+
+-#ifndef _WAL_H_
+-#define _WAL_H_
+-
++/* forward declaration */
++static void pcache1Destroy(sqlite3_pcache *p);
+
+-/* Additional values that can be added to the sync_flags argument of
+-** sqlite3WalFrames():
++/*
++** Implementation of the sqlite3_pcache.xCreate method.
++**
++** Allocate a new cache.
+ */
+-#define WAL_SYNC_TRANSACTIONS 0x20 /* Sync at the end of each transaction */
+-#define SQLITE_SYNC_MASK 0x13 /* Mask off the SQLITE_SYNC_* values */
++static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
++ PCache1 *pCache; /* The newly created page cache */
++ PGroup *pGroup; /* The group the new page cache will belong to */
++ int sz; /* Bytes of memory required to allocate the new cache */
+
+-#ifdef SQLITE_OMIT_WAL
+-# define sqlite3WalOpen(x,y,z) 0
+-# define sqlite3WalLimit(x,y)
+-# define sqlite3WalClose(w,x,y,z) 0
+-# define sqlite3WalBeginReadTransaction(y,z) 0
+-# define sqlite3WalEndReadTransaction(z)
+-# define sqlite3WalDbsize(y) 0
+-# define sqlite3WalBeginWriteTransaction(y) 0
+-# define sqlite3WalEndWriteTransaction(x) 0
+-# define sqlite3WalUndo(x,y,z) 0
+-# define sqlite3WalSavepoint(y,z)
+-# define sqlite3WalSavepointUndo(y,z) 0
+-# define sqlite3WalFrames(u,v,w,x,y,z) 0
+-# define sqlite3WalCheckpoint(r,s,t,u,v,w,x,y,z) 0
+-# define sqlite3WalCallback(z) 0
+-# define sqlite3WalExclusiveMode(y,z) 0
+-# define sqlite3WalHeapMemory(z) 0
+-# define sqlite3WalFramesize(z) 0
+-# define sqlite3WalFindFrame(x,y,z) 0
++ /*
++ ** The separateCache variable is true if each PCache has its own private
++ ** PGroup. In other words, separateCache is true for mode (1) where no
++ ** mutexing is required.
++ **
++ ** * Always use a unified cache (mode-2) if ENABLE_MEMORY_MANAGEMENT
++ **
++ ** * Always use a unified cache in single-threaded applications
++ **
++ ** * Otherwise (if multi-threaded and ENABLE_MEMORY_MANAGEMENT is off)
++ ** use separate caches (mode-1)
++ */
++#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) || SQLITE_THREADSAFE==0
++ const int separateCache = 0;
+ #else
++ int separateCache = sqlite3GlobalConfig.bCoreMutex>0;
++#endif
+
+-#define WAL_SAVEPOINT_NDATA 4
+-
+-/* Connection to a write-ahead log (WAL) file.
+-** There is one object of this type for each pager.
+-*/
+-typedef struct Wal Wal;
+-
+-/* Open and close a connection to a write-ahead log. */
+-SQLITE_PRIVATE int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *, int, i64, Wal**);
+-SQLITE_PRIVATE int sqlite3WalClose(Wal *pWal, int sync_flags, int, u8 *);
++ assert( (szPage & (szPage-1))==0 && szPage>=512 && szPage<=65536 );
++ assert( szExtra < 300 );
+
+-/* Set the limiting size of a WAL file. */
+-SQLITE_PRIVATE void sqlite3WalLimit(Wal*, i64);
++ sz = sizeof(PCache1) + sizeof(PGroup)*separateCache;
++ pCache = (PCache1 *)sqlite3MallocZero(sz);
++ if( pCache ){
++ if( separateCache ){
++ pGroup = (PGroup*)&pCache[1];
++ pGroup->mxPinned = 10;
++ }else{
++ pGroup = &pcache1.grp;
++ }
++ pCache->pGroup = pGroup;
++ pCache->szPage = szPage;
++ pCache->szExtra = szExtra;
++ pCache->bPurgeable = (bPurgeable ? 1 : 0);
++ pcache1EnterMutex(pGroup);
++ pcache1ResizeHash(pCache);
++ if( bPurgeable ){
++ pCache->nMin = 10;
++ pGroup->nMinPage += pCache->nMin;
++ pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
++ }
++ pcache1LeaveMutex(pGroup);
++ if( pCache->nHash==0 ){
++ pcache1Destroy((sqlite3_pcache*)pCache);
++ pCache = 0;
++ }
++ }
++ return (sqlite3_pcache *)pCache;
++}
+
+-/* Used by readers to open (lock) and close (unlock) a snapshot. A
+-** snapshot is like a read-transaction. It is the state of the database
+-** at an instant in time. sqlite3WalOpenSnapshot gets a read lock and
+-** preserves the current state even if the other threads or processes
+-** write to or checkpoint the WAL. sqlite3WalCloseSnapshot() closes the
+-** transaction and releases the lock.
++/*
++** Implementation of the sqlite3_pcache.xCachesize method.
++**
++** Configure the cache_size limit for a cache.
+ */
+-SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *);
+-SQLITE_PRIVATE void sqlite3WalEndReadTransaction(Wal *pWal);
+-
+-/* Read a page from the write-ahead log, if it is present. */
+-SQLITE_PRIVATE int sqlite3WalFindFrame(Wal *, Pgno, u32 *);
+-SQLITE_PRIVATE int sqlite3WalReadFrame(Wal *, u32, int, u8 *);
+-
+-/* If the WAL is not empty, return the size of the database. */
+-SQLITE_PRIVATE Pgno sqlite3WalDbsize(Wal *pWal);
+-
+-/* Obtain or release the WRITER lock. */
+-SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal);
+-SQLITE_PRIVATE int sqlite3WalEndWriteTransaction(Wal *pWal);
+-
+-/* Undo any frames written (but not committed) to the log */
+-SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx);
+-
+-/* Return an integer that records the current (uncommitted) write
+-** position in the WAL */
+-SQLITE_PRIVATE void sqlite3WalSavepoint(Wal *pWal, u32 *aWalData);
+-
+-/* Move the write position of the WAL back to iFrame. Called in
+-** response to a ROLLBACK TO command. */
+-SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData);
+-
+-/* Write a frame or frames to the log. */
+-SQLITE_PRIVATE int sqlite3WalFrames(Wal *pWal, int, PgHdr *, Pgno, int, int);
+-
+-/* Copy pages from the log to the database file */
+-SQLITE_PRIVATE int sqlite3WalCheckpoint(
+- Wal *pWal, /* Write-ahead log connection */
+- int eMode, /* One of PASSIVE, FULL and RESTART */
+- int (*xBusy)(void*), /* Function to call when busy */
+- void *pBusyArg, /* Context argument for xBusyHandler */
+- int sync_flags, /* Flags to sync db file with (or 0) */
+- int nBuf, /* Size of buffer nBuf */
+- u8 *zBuf, /* Temporary buffer to use */
+- int *pnLog, /* OUT: Number of frames in WAL */
+- int *pnCkpt /* OUT: Number of backfilled frames in WAL */
+-);
++static void pcache1Cachesize(sqlite3_pcache *p, int nMax){
++ PCache1 *pCache = (PCache1 *)p;
++ if( pCache->bPurgeable ){
++ PGroup *pGroup = pCache->pGroup;
++ pcache1EnterMutex(pGroup);
++ pGroup->nMaxPage += (nMax - pCache->nMax);
++ pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
++ pCache->nMax = nMax;
++ pCache->n90pct = pCache->nMax*9/10;
++ pcache1EnforceMaxPage(pGroup);
++ pcache1LeaveMutex(pGroup);
++ }
++}
+
+-/* Return the value to pass to a sqlite3_wal_hook callback, the
+-** number of frames in the WAL at the point of the last commit since
+-** sqlite3WalCallback() was called. If no commits have occurred since
+-** the last call, then return 0.
++/*
++** Implementation of the sqlite3_pcache.xShrink method.
++**
++** Free up as much memory as possible.
+ */
+-SQLITE_PRIVATE int sqlite3WalCallback(Wal *pWal);
++static void pcache1Shrink(sqlite3_pcache *p){
++ PCache1 *pCache = (PCache1*)p;
++ if( pCache->bPurgeable ){
++ PGroup *pGroup = pCache->pGroup;
++ int savedMaxPage;
++ pcache1EnterMutex(pGroup);
++ savedMaxPage = pGroup->nMaxPage;
++ pGroup->nMaxPage = 0;
++ pcache1EnforceMaxPage(pGroup);
++ pGroup->nMaxPage = savedMaxPage;
++ pcache1LeaveMutex(pGroup);
++ }
++}
+
+-/* Tell the wal layer that an EXCLUSIVE lock has been obtained (or released)
+-** by the pager layer on the database file.
++/*
++** Implementation of the sqlite3_pcache.xPagecount method.
+ */
+-SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op);
++static int pcache1Pagecount(sqlite3_pcache *p){
++ int n;
++ PCache1 *pCache = (PCache1*)p;
++ pcache1EnterMutex(pCache->pGroup);
++ n = pCache->nPage;
++ pcache1LeaveMutex(pCache->pGroup);
++ return n;
++}
+
+-/* Return true if the argument is non-NULL and the WAL module is using
+-** heap-memory for the wal-index. Otherwise, if the argument is NULL or the
+-** WAL module is using shared-memory, return false.
+-*/
+-SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal);
+
+-#ifdef SQLITE_ENABLE_ZIPVFS
+-/* If the WAL file is not empty, return the number of bytes of content
+-** stored in each frame (i.e. the db page-size when the WAL was created).
++/*
++** Implement steps 3, 4, and 5 of the pcache1Fetch() algorithm described
++** in the header of the pcache1Fetch() procedure.
++**
++** This steps are broken out into a separate procedure because they are
++** usually not needed, and by avoiding the stack initialization required
++** for these steps, the main pcache1Fetch() procedure can run faster.
+ */
+-SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal);
+-#endif
++static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
++ PCache1 *pCache,
++ unsigned int iKey,
++ int createFlag
++){
++ unsigned int nPinned;
++ PGroup *pGroup = pCache->pGroup;
++ PgHdr1 *pPage = 0;
+
+-#endif /* ifndef SQLITE_OMIT_WAL */
+-#endif /* _WAL_H_ */
++ /* Step 3: Abort if createFlag is 1 but the cache is nearly full */
++ assert( pCache->nPage >= pCache->nRecyclable );
++ nPinned = pCache->nPage - pCache->nRecyclable;
++ assert( pGroup->mxPinned == pGroup->nMaxPage + 10 - pGroup->nMinPage );
++ assert( pCache->n90pct == pCache->nMax*9/10 );
++ if( createFlag==1 && (
++ nPinned>=pGroup->mxPinned
++ || nPinned>=pCache->n90pct
++ || (pcache1UnderMemoryPressure(pCache) && pCache->nRecyclable<nPinned)
++ )){
++ return 0;
++ }
+
+-/************** End of wal.h *************************************************/
+-/************** Continuing where we left off in pager.c **********************/
++ if( pCache->nPage>=pCache->nHash ) pcache1ResizeHash(pCache);
++ assert( pCache->nHash>0 && pCache->apHash );
+
++ /* Step 4. Try to recycle a page. */
++ if( pCache->bPurgeable && pGroup->pLruTail && (
++ (pCache->nPage+1>=pCache->nMax)
++ || pGroup->nCurrentPage>=pGroup->nMaxPage
++ || pcache1UnderMemoryPressure(pCache)
++ )){
++ PCache1 *pOther;
++ pPage = pGroup->pLruTail;
++ assert( pPage->isPinned==0 );
++ pcache1RemoveFromHash(pPage);
++ pcache1PinPage(pPage);
++ pOther = pPage->pCache;
+
+-/******************* NOTES ON THE DESIGN OF THE PAGER ************************
+-**
+-** This comment block describes invariants that hold when using a rollback
+-** journal. These invariants do not apply for journal_mode=WAL,
+-** journal_mode=MEMORY, or journal_mode=OFF.
+-**
+-** Within this comment block, a page is deemed to have been synced
+-** automatically as soon as it is written when PRAGMA synchronous=OFF.
+-** Otherwise, the page is not synced until the xSync method of the VFS
+-** is called successfully on the file containing the page.
+-**
+-** Definition: A page of the database file is said to be "overwriteable" if
+-** one or more of the following are true about the page:
+-**
+-** (a) The original content of the page as it was at the beginning of
+-** the transaction has been written into the rollback journal and
+-** synced.
+-**
+-** (b) The page was a freelist leaf page at the start of the transaction.
+-**
+-** (c) The page number is greater than the largest page that existed in
+-** the database file at the start of the transaction.
+-**
+-** (1) A page of the database file is never overwritten unless one of the
+-** following are true:
+-**
+-** (a) The page and all other pages on the same sector are overwriteable.
+-**
+-** (b) The atomic page write optimization is enabled, and the entire
+-** transaction other than the update of the transaction sequence
+-** number consists of a single page change.
+-**
+-** (2) The content of a page written into the rollback journal exactly matches
+-** both the content in the database when the rollback journal was written
+-** and the content in the database at the beginning of the current
+-** transaction.
+-**
+-** (3) Writes to the database file are an integer multiple of the page size
+-** in length and are aligned on a page boundary.
+-**
+-** (4) Reads from the database file are either aligned on a page boundary and
+-** an integer multiple of the page size in length or are taken from the
+-** first 100 bytes of the database file.
+-**
+-** (5) All writes to the database file are synced prior to the rollback journal
+-** being deleted, truncated, or zeroed.
+-**
+-** (6) If a master journal file is used, then all writes to the database file
+-** are synced prior to the master journal being deleted.
+-**
+-** Definition: Two databases (or the same database at two points it time)
+-** are said to be "logically equivalent" if they give the same answer to
+-** all queries. Note in particular the content of freelist leaf
+-** pages can be changed arbitrarily without affecting the logical equivalence
+-** of the database.
+-**
+-** (7) At any time, if any subset, including the empty set and the total set,
+-** of the unsynced changes to a rollback journal are removed and the
+-** journal is rolled back, the resulting database file will be logically
+-** equivalent to the database file at the beginning of the transaction.
+-**
+-** (8) When a transaction is rolled back, the xTruncate method of the VFS
+-** is called to restore the database file to the same size it was at
+-** the beginning of the transaction. (In some VFSes, the xTruncate
+-** method is a no-op, but that does not change the fact the SQLite will
+-** invoke it.)
+-**
+-** (9) Whenever the database file is modified, at least one bit in the range
+-** of bytes from 24 through 39 inclusive will be changed prior to releasing
+-** the EXCLUSIVE lock, thus signaling other connections on the same
+-** database to flush their caches.
+-**
+-** (10) The pattern of bits in bytes 24 through 39 shall not repeat in less
+-** than one billion transactions.
+-**
+-** (11) A database file is well-formed at the beginning and at the conclusion
+-** of every transaction.
+-**
+-** (12) An EXCLUSIVE lock is held on the database file when writing to
+-** the database file.
+-**
+-** (13) A SHARED lock is held on the database file while reading any
+-** content out of the database file.
+-**
+-******************************************************************************/
++ /* We want to verify that szPage and szExtra are the same for pOther
++ ** and pCache. Assert that we can verify this by comparing sums. */
++ assert( (pCache->szPage & (pCache->szPage-1))==0 && pCache->szPage>=512 );
++ assert( pCache->szExtra<512 );
++ assert( (pOther->szPage & (pOther->szPage-1))==0 && pOther->szPage>=512 );
++ assert( pOther->szExtra<512 );
+
+-/*
+-** Macros for troubleshooting. Normally turned off
+-*/
+-#if 0
+-int sqlite3PagerTrace=1; /* True to enable tracing */
+-#define sqlite3DebugPrintf printf
+-#define PAGERTRACE(X) if( sqlite3PagerTrace ){ sqlite3DebugPrintf X; }
+-#else
+-#define PAGERTRACE(X)
+-#endif
++ if( pOther->szPage+pOther->szExtra != pCache->szPage+pCache->szExtra ){
++ pcache1FreePage(pPage);
++ pPage = 0;
++ }else{
++ pGroup->nCurrentPage -= (pOther->bPurgeable - pCache->bPurgeable);
++ }
++ }
+
+-/*
+-** The following two macros are used within the PAGERTRACE() macros above
+-** to print out file-descriptors.
+-**
+-** PAGERID() takes a pointer to a Pager struct as its argument. The
+-** associated file-descriptor is returned. FILEHANDLEID() takes an sqlite3_file
+-** struct as its argument.
+-*/
+-#define PAGERID(p) ((int)(p->fd))
+-#define FILEHANDLEID(fd) ((int)fd)
++ /* Step 5. If a usable page buffer has still not been found,
++ ** attempt to allocate a new one.
++ */
++ if( !pPage ){
++ if( createFlag==1 ) sqlite3BeginBenignMalloc();
++ pPage = pcache1AllocPage(pCache);
++ if( createFlag==1 ) sqlite3EndBenignMalloc();
++ }
++
++ if( pPage ){
++ unsigned int h = iKey % pCache->nHash;
++ pCache->nPage++;
++ pPage->iKey = iKey;
++ pPage->pNext = pCache->apHash[h];
++ pPage->pCache = pCache;
++ pPage->pLruPrev = 0;
++ pPage->pLruNext = 0;
++ pPage->isPinned = 1;
++ *(void **)pPage->page.pExtra = 0;
++ pCache->apHash[h] = pPage;
++ if( iKey>pCache->iMaxKey ){
++ pCache->iMaxKey = iKey;
++ }
++ }
++ return pPage;
++}
+
+ /*
+-** The Pager.eState variable stores the current 'state' of a pager. A
+-** pager may be in any one of the seven states shown in the following
+-** state diagram.
+-**
+-** OPEN <------+------+
+-** | | |
+-** V | |
+-** +---------> READER-------+ |
+-** | | |
+-** | V |
+-** |<-------WRITER_LOCKED------> ERROR
+-** | | ^
+-** | V |
+-** |<------WRITER_CACHEMOD-------->|
+-** | | |
+-** | V |
+-** |<-------WRITER_DBMOD---------->|
+-** | | |
+-** | V |
+-** +<------WRITER_FINISHED-------->+
+-**
+-**
+-** List of state transitions and the C [function] that performs each:
+-**
+-** OPEN -> READER [sqlite3PagerSharedLock]
+-** READER -> OPEN [pager_unlock]
+-**
+-** READER -> WRITER_LOCKED [sqlite3PagerBegin]
+-** WRITER_LOCKED -> WRITER_CACHEMOD [pager_open_journal]
+-** WRITER_CACHEMOD -> WRITER_DBMOD [syncJournal]
+-** WRITER_DBMOD -> WRITER_FINISHED [sqlite3PagerCommitPhaseOne]
+-** WRITER_*** -> READER [pager_end_transaction]
+-**
+-** WRITER_*** -> ERROR [pager_error]
+-** ERROR -> OPEN [pager_unlock]
+-**
+-**
+-** OPEN:
+-**
+-** The pager starts up in this state. Nothing is guaranteed in this
+-** state - the file may or may not be locked and the database size is
+-** unknown. The database may not be read or written.
+-**
+-** * No read or write transaction is active.
+-** * Any lock, or no lock at all, may be held on the database file.
+-** * The dbSize, dbOrigSize and dbFileSize variables may not be trusted.
+-**
+-** READER:
+-**
+-** In this state all the requirements for reading the database in
+-** rollback (non-WAL) mode are met. Unless the pager is (or recently
+-** was) in exclusive-locking mode, a user-level read transaction is
+-** open. The database size is known in this state.
+-**
+-** A connection running with locking_mode=normal enters this state when
+-** it opens a read-transaction on the database and returns to state
+-** OPEN after the read-transaction is completed. However a connection
+-** running in locking_mode=exclusive (including temp databases) remains in
+-** this state even after the read-transaction is closed. The only way
+-** a locking_mode=exclusive connection can transition from READER to OPEN
+-** is via the ERROR state (see below).
+-**
+-** * A read transaction may be active (but a write-transaction cannot).
+-** * A SHARED or greater lock is held on the database file.
+-** * The dbSize variable may be trusted (even if a user-level read
+-** transaction is not active). The dbOrigSize and dbFileSize variables
+-** may not be trusted at this point.
+-** * If the database is a WAL database, then the WAL connection is open.
+-** * Even if a read-transaction is not open, it is guaranteed that
+-** there is no hot-journal in the file-system.
+-**
+-** WRITER_LOCKED:
+-**
+-** The pager moves to this state from READER when a write-transaction
+-** is first opened on the database. In WRITER_LOCKED state, all locks
+-** required to start a write-transaction are held, but no actual
+-** modifications to the cache or database have taken place.
+-**
+-** In rollback mode, a RESERVED or (if the transaction was opened with
+-** BEGIN EXCLUSIVE) EXCLUSIVE lock is obtained on the database file when
+-** moving to this state, but the journal file is not written to or opened
+-** to in this state. If the transaction is committed or rolled back while
+-** in WRITER_LOCKED state, all that is required is to unlock the database
+-** file.
+-**
+-** IN WAL mode, WalBeginWriteTransaction() is called to lock the log file.
+-** If the connection is running with locking_mode=exclusive, an attempt
+-** is made to obtain an EXCLUSIVE lock on the database file.
+-**
+-** * A write transaction is active.
+-** * If the connection is open in rollback-mode, a RESERVED or greater
+-** lock is held on the database file.
+-** * If the connection is open in WAL-mode, a WAL write transaction
+-** is open (i.e. sqlite3WalBeginWriteTransaction() has been successfully
+-** called).
+-** * The dbSize, dbOrigSize and dbFileSize variables are all valid.
+-** * The contents of the pager cache have not been modified.
+-** * The journal file may or may not be open.
+-** * Nothing (not even the first header) has been written to the journal.
+-**
+-** WRITER_CACHEMOD:
+-**
+-** A pager moves from WRITER_LOCKED state to this state when a page is
+-** first modified by the upper layer. In rollback mode the journal file
+-** is opened (if it is not already open) and a header written to the
+-** start of it. The database file on disk has not been modified.
+-**
+-** * A write transaction is active.
+-** * A RESERVED or greater lock is held on the database file.
+-** * The journal file is open and the first header has been written
+-** to it, but the header has not been synced to disk.
+-** * The contents of the page cache have been modified.
+-**
+-** WRITER_DBMOD:
+-**
+-** The pager transitions from WRITER_CACHEMOD into WRITER_DBMOD state
+-** when it modifies the contents of the database file. WAL connections
+-** never enter this state (since they do not modify the database file,
+-** just the log file).
+-**
+-** * A write transaction is active.
+-** * An EXCLUSIVE or greater lock is held on the database file.
+-** * The journal file is open and the first header has been written
+-** and synced to disk.
+-** * The contents of the page cache have been modified (and possibly
+-** written to disk).
+-**
+-** WRITER_FINISHED:
+-**
+-** It is not possible for a WAL connection to enter this state.
+-**
+-** A rollback-mode pager changes to WRITER_FINISHED state from WRITER_DBMOD
+-** state after the entire transaction has been successfully written into the
+-** database file. In this state the transaction may be committed simply
+-** by finalizing the journal file. Once in WRITER_FINISHED state, it is
+-** not possible to modify the database further. At this point, the upper
+-** layer must either commit or rollback the transaction.
+-**
+-** * A write transaction is active.
+-** * An EXCLUSIVE or greater lock is held on the database file.
+-** * All writing and syncing of journal and database data has finished.
+-** If no error occurred, all that remains is to finalize the journal to
+-** commit the transaction. If an error did occur, the caller will need
+-** to rollback the transaction.
+-**
+-** ERROR:
++** Implementation of the sqlite3_pcache.xFetch method.
+ **
+-** The ERROR state is entered when an IO or disk-full error (including
+-** SQLITE_IOERR_NOMEM) occurs at a point in the code that makes it
+-** difficult to be sure that the in-memory pager state (cache contents,
+-** db size etc.) are consistent with the contents of the file-system.
++** Fetch a page by key value.
+ **
+-** Temporary pager files may enter the ERROR state, but in-memory pagers
+-** cannot.
++** Whether or not a new page may be allocated by this function depends on
++** the value of the createFlag argument. 0 means do not allocate a new
++** page. 1 means allocate a new page if space is easily available. 2
++** means to try really hard to allocate a new page.
+ **
+-** For example, if an IO error occurs while performing a rollback,
+-** the contents of the page-cache may be left in an inconsistent state.
+-** At this point it would be dangerous to change back to READER state
+-** (as usually happens after a rollback). Any subsequent readers might
+-** report database corruption (due to the inconsistent cache), and if
+-** they upgrade to writers, they may inadvertently corrupt the database
+-** file. To avoid this hazard, the pager switches into the ERROR state
+-** instead of READER following such an error.
++** For a non-purgeable cache (a cache used as the storage for an in-memory
++** database) there is really no difference between createFlag 1 and 2. So
++** the calling function (pcache.c) will never have a createFlag of 1 on
++** a non-purgeable cache.
+ **
+-** Once it has entered the ERROR state, any attempt to use the pager
+-** to read or write data returns an error. Eventually, once all
+-** outstanding transactions have been abandoned, the pager is able to
+-** transition back to OPEN state, discarding the contents of the
+-** page-cache and any other in-memory state at the same time. Everything
+-** is reloaded from disk (and, if necessary, hot-journal rollback peformed)
+-** when a read-transaction is next opened on the pager (transitioning
+-** the pager into READER state). At that point the system has recovered
+-** from the error.
++** There are three different approaches to obtaining space for a page,
++** depending on the value of parameter createFlag (which may be 0, 1 or 2).
+ **
+-** Specifically, the pager jumps into the ERROR state if:
++** 1. Regardless of the value of createFlag, the cache is searched for a
++** copy of the requested page. If one is found, it is returned.
+ **
+-** 1. An error occurs while attempting a rollback. This happens in
+-** function sqlite3PagerRollback().
++** 2. If createFlag==0 and the page is not already in the cache, NULL is
++** returned.
+ **
+-** 2. An error occurs while attempting to finalize a journal file
+-** following a commit in function sqlite3PagerCommitPhaseTwo().
++** 3. If createFlag is 1, and the page is not already in the cache, then
++** return NULL (do not allocate a new page) if any of the following
++** conditions are true:
+ **
+-** 3. An error occurs while attempting to write to the journal or
+-** database file in function pagerStress() in order to free up
+-** memory.
++** (a) the number of pages pinned by the cache is greater than
++** PCache1.nMax, or
+ **
+-** In other cases, the error is returned to the b-tree layer. The b-tree
+-** layer then attempts a rollback operation. If the error condition
+-** persists, the pager enters the ERROR state via condition (1) above.
++** (b) the number of pages pinned by the cache is greater than
++** the sum of nMax for all purgeable caches, less the sum of
++** nMin for all other purgeable caches, or
+ **
+-** Condition (3) is necessary because it can be triggered by a read-only
+-** statement executed within a transaction. In this case, if the error
+-** code were simply returned to the user, the b-tree layer would not
+-** automatically attempt a rollback, as it assumes that an error in a
+-** read-only statement cannot leave the pager in an internally inconsistent
+-** state.
++** 4. If none of the first three conditions apply and the cache is marked
++** as purgeable, and if one of the following is true:
+ **
+-** * The Pager.errCode variable is set to something other than SQLITE_OK.
+-** * There are one or more outstanding references to pages (after the
+-** last reference is dropped the pager should move back to OPEN state).
+-** * The pager is not an in-memory pager.
+-**
++** (a) The number of pages allocated for the cache is already
++** PCache1.nMax, or
+ **
+-** Notes:
++** (b) The number of pages allocated for all purgeable caches is
++** already equal to or greater than the sum of nMax for all
++** purgeable caches,
+ **
+-** * A pager is never in WRITER_DBMOD or WRITER_FINISHED state if the
+-** connection is open in WAL mode. A WAL connection is always in one
+-** of the first four states.
++** (c) The system is under memory pressure and wants to avoid
++** unnecessary pages cache entry allocations
+ **
+-** * Normally, a connection open in exclusive mode is never in PAGER_OPEN
+-** state. There are two exceptions: immediately after exclusive-mode has
+-** been turned on (and before any read or write transactions are
+-** executed), and when the pager is leaving the "error state".
++** then attempt to recycle a page from the LRU list. If it is the right
++** size, return the recycled buffer. Otherwise, free the buffer and
++** proceed to step 5.
+ **
+-** * See also: assert_pager_state().
++** 5. Otherwise, allocate and return a new page buffer.
+ */
+-#define PAGER_OPEN 0
+-#define PAGER_READER 1
+-#define PAGER_WRITER_LOCKED 2
+-#define PAGER_WRITER_CACHEMOD 3
+-#define PAGER_WRITER_DBMOD 4
+-#define PAGER_WRITER_FINISHED 5
+-#define PAGER_ERROR 6
++static sqlite3_pcache_page *pcache1Fetch(
++ sqlite3_pcache *p,
++ unsigned int iKey,
++ int createFlag
++){
++ PCache1 *pCache = (PCache1 *)p;
++ PgHdr1 *pPage = 0;
++
++ assert( offsetof(PgHdr1,page)==0 );
++ assert( pCache->bPurgeable || createFlag!=1 );
++ assert( pCache->bPurgeable || pCache->nMin==0 );
++ assert( pCache->bPurgeable==0 || pCache->nMin==10 );
++ assert( pCache->nMin==0 || pCache->bPurgeable );
++ assert( pCache->nHash>0 );
++ pcache1EnterMutex(pCache->pGroup);
++
++ /* Step 1: Search the hash table for an existing entry. */
++ pPage = pCache->apHash[iKey % pCache->nHash];
++ while( pPage && pPage->iKey!=iKey ){ pPage = pPage->pNext; }
++
++ /* Step 2: Abort if no existing page is found and createFlag is 0 */
++ if( pPage ){
++ if( !pPage->isPinned ) pcache1PinPage(pPage);
++ }else if( createFlag ){
++ /* Steps 3, 4, and 5 implemented by this subroutine */
++ pPage = pcache1FetchStage2(pCache, iKey, createFlag);
++ }
++ assert( pPage==0 || pCache->iMaxKey>=iKey );
++ pcache1LeaveMutex(pCache->pGroup);
++ return (sqlite3_pcache_page*)pPage;
++}
++
+
+ /*
+-** The Pager.eLock variable is almost always set to one of the
+-** following locking-states, according to the lock currently held on
+-** the database file: NO_LOCK, SHARED_LOCK, RESERVED_LOCK or EXCLUSIVE_LOCK.
+-** This variable is kept up to date as locks are taken and released by
+-** the pagerLockDb() and pagerUnlockDb() wrappers.
+-**
+-** If the VFS xLock() or xUnlock() returns an error other than SQLITE_BUSY
+-** (i.e. one of the SQLITE_IOERR subtypes), it is not clear whether or not
+-** the operation was successful. In these circumstances pagerLockDb() and
+-** pagerUnlockDb() take a conservative approach - eLock is always updated
+-** when unlocking the file, and only updated when locking the file if the
+-** VFS call is successful. This way, the Pager.eLock variable may be set
+-** to a less exclusive (lower) value than the lock that is actually held
+-** at the system level, but it is never set to a more exclusive value.
+-**
+-** This is usually safe. If an xUnlock fails or appears to fail, there may
+-** be a few redundant xLock() calls or a lock may be held for longer than
+-** required, but nothing really goes wrong.
+-**
+-** The exception is when the database file is unlocked as the pager moves
+-** from ERROR to OPEN state. At this point there may be a hot-journal file
+-** in the file-system that needs to be rolled back (as part of an OPEN->SHARED
+-** transition, by the same pager or any other). If the call to xUnlock()
+-** fails at this point and the pager is left holding an EXCLUSIVE lock, this
+-** can confuse the call to xCheckReservedLock() call made later as part
+-** of hot-journal detection.
++** Implementation of the sqlite3_pcache.xUnpin method.
+ **
+-** xCheckReservedLock() is defined as returning true "if there is a RESERVED
+-** lock held by this process or any others". So xCheckReservedLock may
+-** return true because the caller itself is holding an EXCLUSIVE lock (but
+-** doesn't know it because of a previous error in xUnlock). If this happens
+-** a hot-journal may be mistaken for a journal being created by an active
+-** transaction in another process, causing SQLite to read from the database
+-** without rolling it back.
++** Mark a page as unpinned (eligible for asynchronous recycling).
++*/
++static void pcache1Unpin(
++ sqlite3_pcache *p,
++ sqlite3_pcache_page *pPg,
++ int reuseUnlikely
++){
++ PCache1 *pCache = (PCache1 *)p;
++ PgHdr1 *pPage = (PgHdr1 *)pPg;
++ PGroup *pGroup = pCache->pGroup;
++
++ assert( pPage->pCache==pCache );
++ pcache1EnterMutex(pGroup);
++
++ /* It is an error to call this function if the page is already
++ ** part of the PGroup LRU list.
++ */
++ assert( pPage->pLruPrev==0 && pPage->pLruNext==0 );
++ assert( pGroup->pLruHead!=pPage && pGroup->pLruTail!=pPage );
++ assert( pPage->isPinned==1 );
++
++ if( reuseUnlikely || pGroup->nCurrentPage>pGroup->nMaxPage ){
++ pcache1RemoveFromHash(pPage);
++ pcache1FreePage(pPage);
++ }else{
++ /* Add the page to the PGroup LRU list. */
++ if( pGroup->pLruHead ){
++ pGroup->pLruHead->pLruPrev = pPage;
++ pPage->pLruNext = pGroup->pLruHead;
++ pGroup->pLruHead = pPage;
++ }else{
++ pGroup->pLruTail = pPage;
++ pGroup->pLruHead = pPage;
++ }
++ pCache->nRecyclable++;
++ pPage->isPinned = 0;
++ }
++
++ pcache1LeaveMutex(pCache->pGroup);
++}
++
++/*
++** Implementation of the sqlite3_pcache.xRekey method.
++*/
++static void pcache1Rekey(
++ sqlite3_pcache *p,
++ sqlite3_pcache_page *pPg,
++ unsigned int iOld,
++ unsigned int iNew
++){
++ PCache1 *pCache = (PCache1 *)p;
++ PgHdr1 *pPage = (PgHdr1 *)pPg;
++ PgHdr1 **pp;
++ unsigned int h;
++ assert( pPage->iKey==iOld );
++ assert( pPage->pCache==pCache );
++
++ pcache1EnterMutex(pCache->pGroup);
++
++ h = iOld%pCache->nHash;
++ pp = &pCache->apHash[h];
++ while( (*pp)!=pPage ){
++ pp = &(*pp)->pNext;
++ }
++ *pp = pPage->pNext;
++
++ h = iNew%pCache->nHash;
++ pPage->iKey = iNew;
++ pPage->pNext = pCache->apHash[h];
++ pCache->apHash[h] = pPage;
++ if( iNew>pCache->iMaxKey ){
++ pCache->iMaxKey = iNew;
++ }
++
++ pcache1LeaveMutex(pCache->pGroup);
++}
++
++/*
++** Implementation of the sqlite3_pcache.xTruncate method.
+ **
+-** To work around this, if a call to xUnlock() fails when unlocking the
+-** database in the ERROR state, Pager.eLock is set to UNKNOWN_LOCK. It
+-** is only changed back to a real locking state after a successful call
+-** to xLock(EXCLUSIVE). Also, the code to do the OPEN->SHARED state transition
+-** omits the check for a hot-journal if Pager.eLock is set to UNKNOWN_LOCK
+-** lock. Instead, it assumes a hot-journal exists and obtains an EXCLUSIVE
+-** lock on the database file before attempting to roll it back. See function
+-** PagerSharedLock() for more detail.
++** Discard all unpinned pages in the cache with a page number equal to
++** or greater than parameter iLimit. Any pinned pages with a page number
++** equal to or greater than iLimit are implicitly unpinned.
++*/
++static void pcache1Truncate(sqlite3_pcache *p, unsigned int iLimit){
++ PCache1 *pCache = (PCache1 *)p;
++ pcache1EnterMutex(pCache->pGroup);
++ if( iLimit<=pCache->iMaxKey ){
++ pcache1TruncateUnsafe(pCache, iLimit);
++ pCache->iMaxKey = iLimit-1;
++ }
++ pcache1LeaveMutex(pCache->pGroup);
++}
++
++/*
++** Implementation of the sqlite3_pcache.xDestroy method.
+ **
+-** Pager.eLock may only be set to UNKNOWN_LOCK when the pager is in
+-** PAGER_OPEN state.
++** Destroy a cache allocated using pcache1Create().
+ */
+-#define UNKNOWN_LOCK (EXCLUSIVE_LOCK+1)
++static void pcache1Destroy(sqlite3_pcache *p){
++ PCache1 *pCache = (PCache1 *)p;
++ PGroup *pGroup = pCache->pGroup;
++ assert( pCache->bPurgeable || (pCache->nMax==0 && pCache->nMin==0) );
++ pcache1EnterMutex(pGroup);
++ pcache1TruncateUnsafe(pCache, 0);
++ assert( pGroup->nMaxPage >= pCache->nMax );
++ pGroup->nMaxPage -= pCache->nMax;
++ assert( pGroup->nMinPage >= pCache->nMin );
++ pGroup->nMinPage -= pCache->nMin;
++ pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
++ pcache1EnforceMaxPage(pGroup);
++ pcache1LeaveMutex(pGroup);
++ sqlite3_free(pCache->apHash);
++ sqlite3_free(pCache);
++}
+
+ /*
+-** A macro used for invoking the codec if there is one
++** This function is called during initialization (sqlite3_initialize()) to
++** install the default pluggable cache module, assuming the user has not
++** already provided an alternative.
++*/
++SQLITE_PRIVATE void sqlite3PCacheSetDefault(void){
++ static const sqlite3_pcache_methods2 defaultMethods = {
++ 1, /* iVersion */
++ 0, /* pArg */
++ pcache1Init, /* xInit */
++ pcache1Shutdown, /* xShutdown */
++ pcache1Create, /* xCreate */
++ pcache1Cachesize, /* xCachesize */
++ pcache1Pagecount, /* xPagecount */
++ pcache1Fetch, /* xFetch */
++ pcache1Unpin, /* xUnpin */
++ pcache1Rekey, /* xRekey */
++ pcache1Truncate, /* xTruncate */
++ pcache1Destroy, /* xDestroy */
++ pcache1Shrink /* xShrink */
++ };
++ sqlite3_config(SQLITE_CONFIG_PCACHE2, &defaultMethods);
++}
++
++/*
++** Return the size of the header on each page of this PCACHE implementation.
+ */
+-#ifdef SQLITE_HAS_CODEC
+-# define CODEC1(P,D,N,X,E) \
+- if( P->xCodec && P->xCodec(P->pCodec,D,N,X)==0 ){ E; }
+-# define CODEC2(P,D,N,X,E,O) \
+- if( P->xCodec==0 ){ O=(char*)D; }else \
+- if( (O=(char*)(P->xCodec(P->pCodec,D,N,X)))==0 ){ E; }
+-#else
+-# define CODEC1(P,D,N,X,E) /* NO-OP */
+-# define CODEC2(P,D,N,X,E,O) O=(char*)D
+-#endif
++SQLITE_PRIVATE int sqlite3HeaderSizePcache1(void){ return ROUND8(sizeof(PgHdr1)); }
+
+ /*
+-** The maximum allowed sector size. 64KiB. If the xSectorsize() method
+-** returns a value larger than this, then MAX_SECTOR_SIZE is used instead.
+-** This could conceivably cause corruption following a power failure on
+-** such a system. This is currently an undocumented limit.
++** Return the global mutex used by this PCACHE implementation. The
++** sqlite3_status() routine needs access to this mutex.
+ */
+-#define MAX_SECTOR_SIZE 0x10000
++SQLITE_PRIVATE sqlite3_mutex *sqlite3Pcache1Mutex(void){
++ return pcache1.mutex;
++}
+
++#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+ /*
+-** An instance of the following structure is allocated for each active
+-** savepoint and statement transaction in the system. All such structures
+-** are stored in the Pager.aSavepoint[] array, which is allocated and
+-** resized using sqlite3Realloc().
++** This function is called to free superfluous dynamically allocated memory
++** held by the pager system. Memory in use by any SQLite pager allocated
++** by the current thread may be sqlite3_free()ed.
+ **
+-** When a savepoint is created, the PagerSavepoint.iHdrOffset field is
+-** set to 0. If a journal-header is written into the main journal while
+-** the savepoint is active, then iHdrOffset is set to the byte offset
+-** immediately following the last journal record written into the main
+-** journal before the journal-header. This is required during savepoint
+-** rollback (see pagerPlaybackSavepoint()).
++** nReq is the number of bytes of memory required. Once this much has
++** been released, the function returns. The return value is the total number
++** of bytes of memory released.
+ */
+-typedef struct PagerSavepoint PagerSavepoint;
+-struct PagerSavepoint {
+- i64 iOffset; /* Starting offset in main journal */
+- i64 iHdrOffset; /* See above */
+- Bitvec *pInSavepoint; /* Set of pages in this savepoint */
+- Pgno nOrig; /* Original number of pages in file */
+- Pgno iSubRec; /* Index of first record in sub-journal */
+-#ifndef SQLITE_OMIT_WAL
+- u32 aWalData[WAL_SAVEPOINT_NDATA]; /* WAL savepoint context */
++SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){
++ int nFree = 0;
++ assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
++ assert( sqlite3_mutex_notheld(pcache1.mutex) );
++ if( pcache1.pStart==0 ){
++ PgHdr1 *p;
++ pcache1EnterMutex(&pcache1.grp);
++ while( (nReq<0 || nFree<nReq) && ((p=pcache1.grp.pLruTail)!=0) ){
++ nFree += pcache1MemSize(p->page.pBuf);
++#ifdef SQLITE_PCACHE_SEPARATE_HEADER
++ nFree += sqlite3MemSize(p);
+ #endif
+-};
++ assert( p->isPinned==0 );
++ pcache1PinPage(p);
++ pcache1RemoveFromHash(p);
++ pcache1FreePage(p);
++ }
++ pcache1LeaveMutex(&pcache1.grp);
++ }
++ return nFree;
++}
++#endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */
+
++#ifdef SQLITE_TEST
+ /*
+-** Bits of the Pager.doNotSpill flag. See further description below.
++** This function is used by test procedures to inspect the internal state
++** of the global cache.
+ */
+-#define SPILLFLAG_OFF 0x01 /* Never spill cache. Set via pragma */
+-#define SPILLFLAG_ROLLBACK 0x02 /* Current rolling back, so do not spill */
+-#define SPILLFLAG_NOSYNC 0x04 /* Spill is ok, but do not sync */
++SQLITE_PRIVATE void sqlite3PcacheStats(
++ int *pnCurrent, /* OUT: Total number of pages cached */
++ int *pnMax, /* OUT: Global maximum cache size */
++ int *pnMin, /* OUT: Sum of PCache1.nMin for purgeable caches */
++ int *pnRecyclable /* OUT: Total number of pages available for recycling */
++){
++ PgHdr1 *p;
++ int nRecyclable = 0;
++ for(p=pcache1.grp.pLruHead; p; p=p->pLruNext){
++ assert( p->isPinned==0 );
++ nRecyclable++;
++ }
++ *pnCurrent = pcache1.grp.nCurrentPage;
++ *pnMax = (int)pcache1.grp.nMaxPage;
++ *pnMin = (int)pcache1.grp.nMinPage;
++ *pnRecyclable = nRecyclable;
++}
++#endif
+
++/************** End of pcache1.c *********************************************/
++/************** Begin file rowset.c ******************************************/
+ /*
+-** An open page cache is an instance of struct Pager. A description of
+-** some of the more important member variables follows:
+-**
+-** eState
+-**
+-** The current 'state' of the pager object. See the comment and state
+-** diagram above for a description of the pager state.
+-**
+-** eLock
+-**
+-** For a real on-disk database, the current lock held on the database file -
+-** NO_LOCK, SHARED_LOCK, RESERVED_LOCK or EXCLUSIVE_LOCK.
+-**
+-** For a temporary or in-memory database (neither of which require any
+-** locks), this variable is always set to EXCLUSIVE_LOCK. Since such
+-** databases always have Pager.exclusiveMode==1, this tricks the pager
+-** logic into thinking that it already has all the locks it will ever
+-** need (and no reason to release them).
+-**
+-** In some (obscure) circumstances, this variable may also be set to
+-** UNKNOWN_LOCK. See the comment above the #define of UNKNOWN_LOCK for
+-** details.
+-**
+-** changeCountDone
+-**
+-** This boolean variable is used to make sure that the change-counter
+-** (the 4-byte header field at byte offset 24 of the database file) is
+-** not updated more often than necessary.
+-**
+-** It is set to true when the change-counter field is updated, which
+-** can only happen if an exclusive lock is held on the database file.
+-** It is cleared (set to false) whenever an exclusive lock is
+-** relinquished on the database file. Each time a transaction is committed,
+-** The changeCountDone flag is inspected. If it is true, the work of
+-** updating the change-counter is omitted for the current transaction.
+-**
+-** This mechanism means that when running in exclusive mode, a connection
+-** need only update the change-counter once, for the first transaction
+-** committed.
+-**
+-** setMaster
+-**
+-** When PagerCommitPhaseOne() is called to commit a transaction, it may
+-** (or may not) specify a master-journal name to be written into the
+-** journal file before it is synced to disk.
+-**
+-** Whether or not a journal file contains a master-journal pointer affects
+-** the way in which the journal file is finalized after the transaction is
+-** committed or rolled back when running in "journal_mode=PERSIST" mode.
+-** If a journal file does not contain a master-journal pointer, it is
+-** finalized by overwriting the first journal header with zeroes. If
+-** it does contain a master-journal pointer the journal file is finalized
+-** by truncating it to zero bytes, just as if the connection were
+-** running in "journal_mode=truncate" mode.
+-**
+-** Journal files that contain master journal pointers cannot be finalized
+-** simply by overwriting the first journal-header with zeroes, as the
+-** master journal pointer could interfere with hot-journal rollback of any
+-** subsequently interrupted transaction that reuses the journal file.
+-**
+-** The flag is cleared as soon as the journal file is finalized (either
+-** by PagerCommitPhaseTwo or PagerRollback). If an IO error prevents the
+-** journal file from being successfully finalized, the setMaster flag
+-** is cleared anyway (and the pager will move to ERROR state).
+-**
+-** doNotSpill
+-**
+-** This variables control the behavior of cache-spills (calls made by
+-** the pcache module to the pagerStress() routine to write cached data
+-** to the file-system in order to free up memory).
++** 2008 December 3
+ **
+-** When bits SPILLFLAG_OFF or SPILLFLAG_ROLLBACK of doNotSpill are set,
+-** writing to the database from pagerStress() is disabled altogether.
+-** The SPILLFLAG_ROLLBACK case is done in a very obscure case that
+-** comes up during savepoint rollback that requires the pcache module
+-** to allocate a new page to prevent the journal file from being written
+-** while it is being traversed by code in pager_playback(). The SPILLFLAG_OFF
+-** case is a user preference.
+-**
+-** If the SPILLFLAG_NOSYNC bit is set, writing to the database from pagerStress()
+-** is permitted, but syncing the journal file is not. This flag is set
+-** by sqlite3PagerWrite() when the file-system sector-size is larger than
+-** the database page-size in order to prevent a journal sync from happening
+-** in between the journalling of two pages on the same sector.
++** The author disclaims copyright to this source code. In place of
++** a legal notice, here is a blessing:
+ **
+-** subjInMemory
++** 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 is a boolean variable. If true, then any required sub-journal
+-** is opened as an in-memory journal file. If false, then in-memory
+-** sub-journals are only used for in-memory pager files.
++*************************************************************************
+ **
+-** This variable is updated by the upper layer each time a new
+-** write-transaction is opened.
++** This module implements an object we call a "RowSet".
+ **
+-** dbSize, dbOrigSize, dbFileSize
++** The RowSet object is a collection of rowids. Rowids
++** are inserted into the RowSet in an arbitrary order. Inserts
++** can be intermixed with tests to see if a given rowid has been
++** previously inserted into the RowSet.
+ **
+-** Variable dbSize is set to the number of pages in the database file.
+-** It is valid in PAGER_READER and higher states (all states except for
+-** OPEN and ERROR).
++** After all inserts are finished, it is possible to extract the
++** elements of the RowSet in sorted order. Once this extraction
++** process has started, no new elements may be inserted.
+ **
+-** dbSize is set based on the size of the database file, which may be
+-** larger than the size of the database (the value stored at offset
+-** 28 of the database header by the btree). If the size of the file
+-** is not an integer multiple of the page-size, the value stored in
+-** dbSize is rounded down (i.e. a 5KB file with 2K page-size has dbSize==2).
+-** Except, any file that is greater than 0 bytes in size is considered
+-** to have at least one page. (i.e. a 1KB file with 2K page-size leads
+-** to dbSize==1).
++** Hence, the primitive operations for a RowSet are:
+ **
+-** During a write-transaction, if pages with page-numbers greater than
+-** dbSize are modified in the cache, dbSize is updated accordingly.
+-** Similarly, if the database is truncated using PagerTruncateImage(),
+-** dbSize is updated.
++** CREATE
++** INSERT
++** TEST
++** SMALLEST
++** DESTROY
+ **
+-** Variables dbOrigSize and dbFileSize are valid in states
+-** PAGER_WRITER_LOCKED and higher. dbOrigSize is a copy of the dbSize
+-** variable at the start of the transaction. It is used during rollback,
+-** and to determine whether or not pages need to be journalled before
+-** being modified.
++** The CREATE and DESTROY primitives are the constructor and destructor,
++** obviously. The INSERT primitive adds a new element to the RowSet.
++** TEST checks to see if an element is already in the RowSet. SMALLEST
++** extracts the least value from the RowSet.
+ **
+-** Throughout a write-transaction, dbFileSize contains the size of
+-** the file on disk in pages. It is set to a copy of dbSize when the
+-** write-transaction is first opened, and updated when VFS calls are made
+-** to write or truncate the database file on disk.
++** The INSERT primitive might allocate additional memory. Memory is
++** allocated in chunks so most INSERTs do no allocation. There is an
++** upper bound on the size of allocated memory. No memory is freed
++** until DESTROY.
+ **
+-** The only reason the dbFileSize variable is required is to suppress
+-** unnecessary calls to xTruncate() after committing a transaction. If,
+-** when a transaction is committed, the dbFileSize variable indicates
+-** that the database file is larger than the database image (Pager.dbSize),
+-** pager_truncate() is called. The pager_truncate() call uses xFilesize()
+-** to measure the database file on disk, and then truncates it if required.
+-** dbFileSize is not used when rolling back a transaction. In this case
+-** pager_truncate() is called unconditionally (which means there may be
+-** a call to xFilesize() that is not strictly required). In either case,
+-** pager_truncate() may cause the file to become smaller or larger.
++** The TEST primitive includes a "batch" number. The TEST primitive
++** will only see elements that were inserted before the last change
++** in the batch number. In other words, if an INSERT occurs between
++** two TESTs where the TESTs have the same batch nubmer, then the
++** value added by the INSERT will not be visible to the second TEST.
++** The initial batch number is zero, so if the very first TEST contains
++** a non-zero batch number, it will see all prior INSERTs.
+ **
+-** dbHintSize
++** No INSERTs may occurs after a SMALLEST. An assertion will fail if
++** that is attempted.
+ **
+-** The dbHintSize variable is used to limit the number of calls made to
+-** the VFS xFileControl(FCNTL_SIZE_HINT) method.
++** The cost of an INSERT is roughly constant. (Sometimes new memory
++** has to be allocated on an INSERT.) The cost of a TEST with a new
++** batch number is O(NlogN) where N is the number of elements in the RowSet.
++** The cost of a TEST using the same batch number is O(logN). The cost
++** of the first SMALLEST is O(NlogN). Second and subsequent SMALLEST
++** primitives are constant time. The cost of DESTROY is O(N).
+ **
+-** dbHintSize is set to a copy of the dbSize variable when a
+-** write-transaction is opened (at the same time as dbFileSize and
+-** dbOrigSize). If the xFileControl(FCNTL_SIZE_HINT) method is called,
+-** dbHintSize is increased to the number of pages that correspond to the
+-** size-hint passed to the method call. See pager_write_pagelist() for
+-** details.
++** There is an added cost of O(N) when switching between TEST and
++** SMALLEST primitives.
++*/
++
++
++/*
++** Target size for allocation chunks.
++*/
++#define ROWSET_ALLOCATION_SIZE 1024
++
++/*
++** The number of rowset entries per allocation chunk.
++*/
++#define ROWSET_ENTRY_PER_CHUNK \
++ ((ROWSET_ALLOCATION_SIZE-8)/sizeof(struct RowSetEntry))
++
++/*
++** Each entry in a RowSet is an instance of the following object.
+ **
+-** errCode
++** This same object is reused to store a linked list of trees of RowSetEntry
++** objects. In that alternative use, pRight points to the next entry
++** in the list, pLeft points to the tree, and v is unused. The
++** RowSet.pForest value points to the head of this forest list.
++*/
++struct RowSetEntry {
++ i64 v; /* ROWID value for this entry */
++ struct RowSetEntry *pRight; /* Right subtree (larger entries) or list */
++ struct RowSetEntry *pLeft; /* Left subtree (smaller entries) */
++};
++
++/*
++** RowSetEntry objects are allocated in large chunks (instances of the
++** following structure) to reduce memory allocation overhead. The
++** chunks are kept on a linked list so that they can be deallocated
++** when the RowSet is destroyed.
++*/
++struct RowSetChunk {
++ struct RowSetChunk *pNextChunk; /* Next chunk on list of them all */
++ struct RowSetEntry aEntry[ROWSET_ENTRY_PER_CHUNK]; /* Allocated entries */
++};
++
++/*
++** A RowSet in an instance of the following structure.
+ **
+-** The Pager.errCode variable is only ever used in PAGER_ERROR state. It
+-** is set to zero in all other states. In PAGER_ERROR state, Pager.errCode
+-** is always set to SQLITE_FULL, SQLITE_IOERR or one of the SQLITE_IOERR_XXX
+-** sub-codes.
++** A typedef of this structure if found in sqliteInt.h.
+ */
+-struct Pager {
+- sqlite3_vfs *pVfs; /* OS functions to use for IO */
+- u8 exclusiveMode; /* Boolean. True if locking_mode==EXCLUSIVE */
+- u8 journalMode; /* One of the PAGER_JOURNALMODE_* values */
+- u8 useJournal; /* Use a rollback journal on this file */
+- u8 noSync; /* Do not sync the journal if true */
+- u8 fullSync; /* Do extra syncs of the journal for robustness */
+- u8 ckptSyncFlags; /* SYNC_NORMAL or SYNC_FULL for checkpoint */
+- u8 walSyncFlags; /* SYNC_NORMAL or SYNC_FULL for wal writes */
+- u8 syncFlags; /* SYNC_NORMAL or SYNC_FULL otherwise */
+- u8 tempFile; /* zFilename is a temporary or immutable file */
+- u8 noLock; /* Do not lock (except in WAL mode) */
+- u8 readOnly; /* True for a read-only database */
+- u8 memDb; /* True to inhibit all file I/O */
++struct RowSet {
++ struct RowSetChunk *pChunk; /* List of all chunk allocations */
++ sqlite3 *db; /* The database connection */
++ struct RowSetEntry *pEntry; /* List of entries using pRight */
++ struct RowSetEntry *pLast; /* Last entry on the pEntry list */
++ struct RowSetEntry *pFresh; /* Source of new entry objects */
++ struct RowSetEntry *pForest; /* List of binary trees of entries */
++ u16 nFresh; /* Number of objects on pFresh */
++ u16 rsFlags; /* Various flags */
++ int iBatch; /* Current insert batch */
++};
+
+- /**************************************************************************
+- ** The following block contains those class members that change during
+- ** routine operation. Class members not in this block are either fixed
+- ** when the pager is first created or else only change when there is a
+- ** significant mode change (such as changing the page_size, locking_mode,
+- ** or the journal_mode). From another view, these class members describe
+- ** the "state" of the pager, while other class members describe the
+- ** "configuration" of the pager.
+- */
+- u8 eState; /* Pager state (OPEN, READER, WRITER_LOCKED..) */
+- u8 eLock; /* Current lock held on database file */
+- u8 changeCountDone; /* Set after incrementing the change-counter */
+- u8 setMaster; /* True if a m-j name has been written to jrnl */
+- u8 doNotSpill; /* Do not spill the cache when non-zero */
+- u8 subjInMemory; /* True to use in-memory sub-journals */
+- u8 bUseFetch; /* True to use xFetch() */
+- u8 hasBeenUsed; /* True if any content previously read from this pager*/
+- Pgno dbSize; /* Number of pages in the database */
+- Pgno dbOrigSize; /* dbSize before the current transaction */
+- Pgno dbFileSize; /* Number of pages in the database file */
+- Pgno dbHintSize; /* Value passed to FCNTL_SIZE_HINT call */
+- int errCode; /* One of several kinds of errors */
+- int nRec; /* Pages journalled since last j-header written */
+- u32 cksumInit; /* Quasi-random value added to every checksum */
+- u32 nSubRec; /* Number of records written to sub-journal */
+- Bitvec *pInJournal; /* One bit for each page in the database file */
+- sqlite3_file *fd; /* File descriptor for database */
+- sqlite3_file *jfd; /* File descriptor for main journal */
+- sqlite3_file *sjfd; /* File descriptor for sub-journal */
+- i64 journalOff; /* Current write offset in the journal file */
+- i64 journalHdr; /* Byte offset to previous journal header */
+- sqlite3_backup *pBackup; /* Pointer to list of ongoing backup processes */
+- PagerSavepoint *aSavepoint; /* Array of active savepoints */
+- int nSavepoint; /* Number of elements in aSavepoint[] */
+- u32 iDataVersion; /* Changes whenever database content changes */
+- char dbFileVers[16]; /* Changes whenever database file changes */
++/*
++** Allowed values for RowSet.rsFlags
++*/
++#define ROWSET_SORTED 0x01 /* True if RowSet.pEntry is sorted */
++#define ROWSET_NEXT 0x02 /* True if sqlite3RowSetNext() has been called */
+
+- int nMmapOut; /* Number of mmap pages currently outstanding */
+- sqlite3_int64 szMmap; /* Desired maximum mmap size */
+- PgHdr *pMmapFreelist; /* List of free mmap page headers (pDirty) */
+- /*
+- ** End of the routinely-changing class members
+- ***************************************************************************/
++/*
++** Turn bulk memory into a RowSet object. N bytes of memory
++** are available at pSpace. The db pointer is used as a memory context
++** for any subsequent allocations that need to occur.
++** Return a pointer to the new RowSet object.
++**
++** It must be the case that N is sufficient to make a Rowset. If not
++** an assertion fault occurs.
++**
++** If N is larger than the minimum, use the surplus as an initial
++** allocation of entries available to be filled.
++*/
++SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3 *db, void *pSpace, unsigned int N){
++ RowSet *p;
++ assert( N >= ROUND8(sizeof(*p)) );
++ p = pSpace;
++ p->pChunk = 0;
++ p->db = db;
++ p->pEntry = 0;
++ p->pLast = 0;
++ p->pForest = 0;
++ p->pFresh = (struct RowSetEntry*)(ROUND8(sizeof(*p)) + (char*)p);
++ p->nFresh = (u16)((N - ROUND8(sizeof(*p)))/sizeof(struct RowSetEntry));
++ p->rsFlags = ROWSET_SORTED;
++ p->iBatch = 0;
++ return p;
++}
+
+- u16 nExtra; /* Add this many bytes to each in-memory page */
+- i16 nReserve; /* Number of unused bytes at end of each page */
+- u32 vfsFlags; /* Flags for sqlite3_vfs.xOpen() */
+- u32 sectorSize; /* Assumed sector size during rollback */
+- int pageSize; /* Number of bytes in a page */
+- Pgno mxPgno; /* Maximum allowed size of the database */
+- i64 journalSizeLimit; /* Size limit for persistent journal files */
+- char *zFilename; /* Name of the database file */
+- char *zJournal; /* Name of the journal file */
+- int (*xBusyHandler)(void*); /* Function to call when busy */
+- void *pBusyHandlerArg; /* Context argument for xBusyHandler */
+- int aStat[3]; /* Total cache hits, misses and writes */
+-#ifdef SQLITE_TEST
+- int nRead; /* Database pages read */
+-#endif
+- void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */
+-#ifdef SQLITE_HAS_CODEC
+- void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */
+- void (*xCodecSizeChng)(void*,int,int); /* Notify of page size changes */
+- void (*xCodecFree)(void*); /* Destructor for the codec */
+- void *pCodec; /* First argument to xCodec... methods */
+-#endif
+- char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */
+- PCache *pPCache; /* Pointer to page cache object */
+-#ifndef SQLITE_OMIT_WAL
+- Wal *pWal; /* Write-ahead log used by "journal_mode=wal" */
+- char *zWal; /* File name for write-ahead log */
+-#endif
+-};
++/*
++** Deallocate all chunks from a RowSet. This frees all memory that
++** the RowSet has allocated over its lifetime. This routine is
++** the destructor for the RowSet.
++*/
++SQLITE_PRIVATE void sqlite3RowSetClear(RowSet *p){
++ struct RowSetChunk *pChunk, *pNextChunk;
++ for(pChunk=p->pChunk; pChunk; pChunk = pNextChunk){
++ pNextChunk = pChunk->pNextChunk;
++ sqlite3DbFree(p->db, pChunk);
++ }
++ p->pChunk = 0;
++ p->nFresh = 0;
++ p->pEntry = 0;
++ p->pLast = 0;
++ p->pForest = 0;
++ p->rsFlags = ROWSET_SORTED;
++}
+
+ /*
+-** Indexes for use with Pager.aStat[]. The Pager.aStat[] array contains
+-** the values accessed by passing SQLITE_DBSTATUS_CACHE_HIT, CACHE_MISS
+-** or CACHE_WRITE to sqlite3_db_status().
++** Allocate a new RowSetEntry object that is associated with the
++** given RowSet. Return a pointer to the new and completely uninitialized
++** objected.
++**
++** In an OOM situation, the RowSet.db->mallocFailed flag is set and this
++** routine returns NULL.
+ */
+-#define PAGER_STAT_HIT 0
+-#define PAGER_STAT_MISS 1
+-#define PAGER_STAT_WRITE 2
++static struct RowSetEntry *rowSetEntryAlloc(RowSet *p){
++ assert( p!=0 );
++ if( p->nFresh==0 ){
++ struct RowSetChunk *pNew;
++ pNew = sqlite3DbMallocRaw(p->db, sizeof(*pNew));
++ if( pNew==0 ){
++ return 0;
++ }
++ pNew->pNextChunk = p->pChunk;
++ p->pChunk = pNew;
++ p->pFresh = pNew->aEntry;
++ p->nFresh = ROWSET_ENTRY_PER_CHUNK;
++ }
++ p->nFresh--;
++ return p->pFresh++;
++}
+
+ /*
+-** The following global variables hold counters used for
+-** testing purposes only. These variables do not exist in
+-** a non-testing build. These variables are not thread-safe.
++** Insert a new value into a RowSet.
++**
++** The mallocFailed flag of the database connection is set if a
++** memory allocation fails.
+ */
+-#ifdef SQLITE_TEST
+-SQLITE_API int sqlite3_pager_readdb_count = 0; /* Number of full pages read from DB */
+-SQLITE_API int sqlite3_pager_writedb_count = 0; /* Number of full pages written to DB */
+-SQLITE_API int sqlite3_pager_writej_count = 0; /* Number of pages written to journal */
+-# define PAGER_INCR(v) v++
+-#else
+-# define PAGER_INCR(v)
+-#endif
++SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet *p, i64 rowid){
++ struct RowSetEntry *pEntry; /* The new entry */
++ struct RowSetEntry *pLast; /* The last prior entry */
+
++ /* This routine is never called after sqlite3RowSetNext() */
++ assert( p!=0 && (p->rsFlags & ROWSET_NEXT)==0 );
+
++ pEntry = rowSetEntryAlloc(p);
++ if( pEntry==0 ) return;
++ pEntry->v = rowid;
++ pEntry->pRight = 0;
++ pLast = p->pLast;
++ if( pLast ){
++ if( (p->rsFlags & ROWSET_SORTED)!=0 && rowid<=pLast->v ){
++ p->rsFlags &= ~ROWSET_SORTED;
++ }
++ pLast->pRight = pEntry;
++ }else{
++ p->pEntry = pEntry;
++ }
++ p->pLast = pEntry;
++}
+
+ /*
+-** Journal files begin with the following magic string. The data
+-** was obtained from /dev/random. It is used only as a sanity check.
+-**
+-** Since version 2.8.0, the journal format contains additional sanity
+-** checking information. If the power fails while the journal is being
+-** written, semi-random garbage data might appear in the journal
+-** file after power is restored. If an attempt is then made
+-** to roll the journal back, the database could be corrupted. The additional
+-** sanity checking data is an attempt to discover the garbage in the
+-** journal and ignore it.
++** Merge two lists of RowSetEntry objects. Remove duplicates.
+ **
+-** The sanity checking information for the new journal format consists
+-** of a 32-bit checksum on each page of data. The checksum covers both
+-** the page number and the pPager->pageSize bytes of data for the page.
+-** This cksum is initialized to a 32-bit random value that appears in the
+-** journal file right after the header. The random initializer is important,
+-** because garbage data that appears at the end of a journal is likely
+-** data that was once in other files that have now been deleted. If the
+-** garbage data came from an obsolete journal file, the checksums might
+-** be correct. But by initializing the checksum to random value which
+-** is different for every journal, we minimize that risk.
++** The input lists are connected via pRight pointers and are
++** assumed to each already be in sorted order.
+ */
+-static const unsigned char aJournalMagic[] = {
+- 0xd9, 0xd5, 0x05, 0xf9, 0x20, 0xa1, 0x63, 0xd7,
+-};
++static struct RowSetEntry *rowSetEntryMerge(
++ struct RowSetEntry *pA, /* First sorted list to be merged */
++ struct RowSetEntry *pB /* Second sorted list to be merged */
++){
++ struct RowSetEntry head;
++ struct RowSetEntry *pTail;
+
+-/*
+-** The size of the of each page record in the journal is given by
+-** the following macro.
+-*/
+-#define JOURNAL_PG_SZ(pPager) ((pPager->pageSize) + 8)
++ pTail = &head;
++ while( pA && pB ){
++ assert( pA->pRight==0 || pA->v<=pA->pRight->v );
++ assert( pB->pRight==0 || pB->v<=pB->pRight->v );
++ if( pA->v<pB->v ){
++ pTail->pRight = pA;
++ pA = pA->pRight;
++ pTail = pTail->pRight;
++ }else if( pB->v<pA->v ){
++ pTail->pRight = pB;
++ pB = pB->pRight;
++ pTail = pTail->pRight;
++ }else{
++ pA = pA->pRight;
++ }
++ }
++ if( pA ){
++ assert( pA->pRight==0 || pA->v<=pA->pRight->v );
++ pTail->pRight = pA;
++ }else{
++ assert( pB==0 || pB->pRight==0 || pB->v<=pB->pRight->v );
++ pTail->pRight = pB;
++ }
++ return head.pRight;
++}
+
+ /*
+-** The journal header size for this pager. This is usually the same
+-** size as a single disk sector. See also setSectorSize().
+-*/
+-#define JOURNAL_HDR_SZ(pPager) (pPager->sectorSize)
++** Sort all elements on the list of RowSetEntry objects into order of
++** increasing v.
++*/
++static struct RowSetEntry *rowSetEntrySort(struct RowSetEntry *pIn){
++ unsigned int i;
++ struct RowSetEntry *pNext, *aBucket[40];
+
+-/*
+-** The macro MEMDB is true if we are dealing with an in-memory database.
+-** We do this as a macro so that if the SQLITE_OMIT_MEMORYDB macro is set,
+-** the value of MEMDB will be a constant and the compiler will optimize
+-** out code that would never execute.
+-*/
+-#ifdef SQLITE_OMIT_MEMORYDB
+-# define MEMDB 0
+-#else
+-# define MEMDB pPager->memDb
+-#endif
++ memset(aBucket, 0, sizeof(aBucket));
++ while( pIn ){
++ pNext = pIn->pRight;
++ pIn->pRight = 0;
++ for(i=0; aBucket[i]; i++){
++ pIn = rowSetEntryMerge(aBucket[i], pIn);
++ aBucket[i] = 0;
++ }
++ aBucket[i] = pIn;
++ pIn = pNext;
++ }
++ pIn = 0;
++ for(i=0; i<sizeof(aBucket)/sizeof(aBucket[0]); i++){
++ pIn = rowSetEntryMerge(pIn, aBucket[i]);
++ }
++ return pIn;
++}
+
+-/*
+-** The macro USEFETCH is true if we are allowed to use the xFetch and xUnfetch
+-** interfaces to access the database using memory-mapped I/O.
+-*/
+-#if SQLITE_MAX_MMAP_SIZE>0
+-# define USEFETCH(x) ((x)->bUseFetch)
+-#else
+-# define USEFETCH(x) 0
+-#endif
+
+ /*
+-** The maximum legal page number is (2^31 - 1).
++** The input, pIn, is a binary tree (or subtree) of RowSetEntry objects.
++** Convert this tree into a linked list connected by the pRight pointers
++** and return pointers to the first and last elements of the new list.
+ */
+-#define PAGER_MAX_PGNO 2147483647
++static void rowSetTreeToList(
++ struct RowSetEntry *pIn, /* Root of the input tree */
++ struct RowSetEntry **ppFirst, /* Write head of the output list here */
++ struct RowSetEntry **ppLast /* Write tail of the output list here */
++){
++ assert( pIn!=0 );
++ if( pIn->pLeft ){
++ struct RowSetEntry *p;
++ rowSetTreeToList(pIn->pLeft, ppFirst, &p);
++ p->pRight = pIn;
++ }else{
++ *ppFirst = pIn;
++ }
++ if( pIn->pRight ){
++ rowSetTreeToList(pIn->pRight, &pIn->pRight, ppLast);
++ }else{
++ *ppLast = pIn;
++ }
++ assert( (*ppLast)->pRight==0 );
++}
++
+
+ /*
+-** The argument to this macro is a file descriptor (type sqlite3_file*).
+-** Return 0 if it is not open, or non-zero (but not 1) if it is.
+-**
+-** This is so that expressions can be written as:
+-**
+-** if( isOpen(pPager->jfd) ){ ...
++** Convert a sorted list of elements (connected by pRight) into a binary
++** tree with depth of iDepth. A depth of 1 means the tree contains a single
++** node taken from the head of *ppList. A depth of 2 means a tree with
++** three nodes. And so forth.
+ **
+-** instead of
++** Use as many entries from the input list as required and update the
++** *ppList to point to the unused elements of the list. If the input
++** list contains too few elements, then construct an incomplete tree
++** and leave *ppList set to NULL.
+ **
+-** if( pPager->jfd->pMethods ){ ...
++** Return a pointer to the root of the constructed binary tree.
+ */
+-#define isOpen(pFd) ((pFd)->pMethods)
++static struct RowSetEntry *rowSetNDeepTree(
++ struct RowSetEntry **ppList,
++ int iDepth
++){
++ struct RowSetEntry *p; /* Root of the new tree */
++ struct RowSetEntry *pLeft; /* Left subtree */
++ if( *ppList==0 ){
++ return 0;
++ }
++ if( iDepth==1 ){
++ p = *ppList;
++ *ppList = p->pRight;
++ p->pLeft = p->pRight = 0;
++ return p;
++ }
++ pLeft = rowSetNDeepTree(ppList, iDepth-1);
++ p = *ppList;
++ if( p==0 ){
++ return pLeft;
++ }
++ p->pLeft = pLeft;
++ *ppList = p->pRight;
++ p->pRight = rowSetNDeepTree(ppList, iDepth-1);
++ return p;
++}
+
+ /*
+-** Return true if this pager uses a write-ahead log instead of the usual
+-** rollback journal. Otherwise false.
++** Convert a sorted list of elements into a binary tree. Make the tree
++** as deep as it needs to be in order to contain the entire list.
+ */
+-#ifndef SQLITE_OMIT_WAL
+-static int pagerUseWal(Pager *pPager){
+- return (pPager->pWal!=0);
++static struct RowSetEntry *rowSetListToTree(struct RowSetEntry *pList){
++ int iDepth; /* Depth of the tree so far */
++ struct RowSetEntry *p; /* Current tree root */
++ struct RowSetEntry *pLeft; /* Left subtree */
++
++ assert( pList!=0 );
++ p = pList;
++ pList = p->pRight;
++ p->pLeft = p->pRight = 0;
++ for(iDepth=1; pList; iDepth++){
++ pLeft = p;
++ p = pList;
++ pList = p->pRight;
++ p->pLeft = pLeft;
++ p->pRight = rowSetNDeepTree(&pList, iDepth);
++ }
++ return p;
+ }
+-#else
+-# define pagerUseWal(x) 0
+-# define pagerRollbackWal(x) 0
+-# define pagerWalFrames(v,w,x,y) 0
+-# define pagerOpenWalIfPresent(z) SQLITE_OK
+-# define pagerBeginReadTransaction(z) SQLITE_OK
+-#endif
+
+-#ifndef NDEBUG
+ /*
+-** Usage:
+-**
+-** assert( assert_pager_state(pPager) );
++** Take all the entries on p->pEntry and on the trees in p->pForest and
++** sort them all together into one big ordered list on p->pEntry.
+ **
+-** This function runs many asserts to try to find inconsistencies in
+-** the internal state of the Pager object.
++** This routine should only be called once in the life of a RowSet.
+ */
+-static int assert_pager_state(Pager *p){
+- Pager *pPager = p;
+-
+- /* State must be valid. */
+- assert( p->eState==PAGER_OPEN
+- || p->eState==PAGER_READER
+- || p->eState==PAGER_WRITER_LOCKED
+- || p->eState==PAGER_WRITER_CACHEMOD
+- || p->eState==PAGER_WRITER_DBMOD
+- || p->eState==PAGER_WRITER_FINISHED
+- || p->eState==PAGER_ERROR
+- );
+-
+- /* Regardless of the current state, a temp-file connection always behaves
+- ** as if it has an exclusive lock on the database file. It never updates
+- ** the change-counter field, so the changeCountDone flag is always set.
+- */
+- assert( p->tempFile==0 || p->eLock==EXCLUSIVE_LOCK );
+- assert( p->tempFile==0 || pPager->changeCountDone );
++static void rowSetToList(RowSet *p){
+
+- /* If the useJournal flag is clear, the journal-mode must be "OFF".
+- ** And if the journal-mode is "OFF", the journal file must not be open.
+- */
+- assert( p->journalMode==PAGER_JOURNALMODE_OFF || p->useJournal );
+- assert( p->journalMode!=PAGER_JOURNALMODE_OFF || !isOpen(p->jfd) );
++ /* This routine is called only once */
++ assert( p!=0 && (p->rsFlags & ROWSET_NEXT)==0 );
+
+- /* Check that MEMDB implies noSync. And an in-memory journal. Since
+- ** this means an in-memory pager performs no IO at all, it cannot encounter
+- ** either SQLITE_IOERR or SQLITE_FULL during rollback or while finalizing
+- ** a journal file. (although the in-memory journal implementation may
+- ** return SQLITE_IOERR_NOMEM while the journal file is being written). It
+- ** is therefore not possible for an in-memory pager to enter the ERROR
+- ** state.
+- */
+- if( MEMDB ){
+- assert( p->noSync );
+- assert( p->journalMode==PAGER_JOURNALMODE_OFF
+- || p->journalMode==PAGER_JOURNALMODE_MEMORY
+- );
+- assert( p->eState!=PAGER_ERROR && p->eState!=PAGER_OPEN );
+- assert( pagerUseWal(p)==0 );
++ if( (p->rsFlags & ROWSET_SORTED)==0 ){
++ p->pEntry = rowSetEntrySort(p->pEntry);
+ }
+
+- /* If changeCountDone is set, a RESERVED lock or greater must be held
+- ** on the file.
+- */
+- assert( pPager->changeCountDone==0 || pPager->eLock>=RESERVED_LOCK );
+- assert( p->eLock!=PENDING_LOCK );
+-
+- switch( p->eState ){
+- case PAGER_OPEN:
+- assert( !MEMDB );
+- assert( pPager->errCode==SQLITE_OK );
+- assert( sqlite3PcacheRefCount(pPager->pPCache)==0 || pPager->tempFile );
+- break;
+-
+- case PAGER_READER:
+- assert( pPager->errCode==SQLITE_OK );
+- assert( p->eLock!=UNKNOWN_LOCK );
+- assert( p->eLock>=SHARED_LOCK );
+- break;
+-
+- case PAGER_WRITER_LOCKED:
+- assert( p->eLock!=UNKNOWN_LOCK );
+- assert( pPager->errCode==SQLITE_OK );
+- if( !pagerUseWal(pPager) ){
+- assert( p->eLock>=RESERVED_LOCK );
+- }
+- assert( pPager->dbSize==pPager->dbOrigSize );
+- assert( pPager->dbOrigSize==pPager->dbFileSize );
+- assert( pPager->dbOrigSize==pPager->dbHintSize );
+- assert( pPager->setMaster==0 );
+- break;
+-
+- case PAGER_WRITER_CACHEMOD:
+- assert( p->eLock!=UNKNOWN_LOCK );
+- assert( pPager->errCode==SQLITE_OK );
+- if( !pagerUseWal(pPager) ){
+- /* It is possible that if journal_mode=wal here that neither the
+- ** journal file nor the WAL file are open. This happens during
+- ** a rollback transaction that switches from journal_mode=off
+- ** to journal_mode=wal.
+- */
+- assert( p->eLock>=RESERVED_LOCK );
+- assert( isOpen(p->jfd)
+- || p->journalMode==PAGER_JOURNALMODE_OFF
+- || p->journalMode==PAGER_JOURNALMODE_WAL
+- );
+- }
+- assert( pPager->dbOrigSize==pPager->dbFileSize );
+- assert( pPager->dbOrigSize==pPager->dbHintSize );
+- break;
+-
+- case PAGER_WRITER_DBMOD:
+- assert( p->eLock==EXCLUSIVE_LOCK );
+- assert( pPager->errCode==SQLITE_OK );
+- assert( !pagerUseWal(pPager) );
+- assert( p->eLock>=EXCLUSIVE_LOCK );
+- assert( isOpen(p->jfd)
+- || p->journalMode==PAGER_JOURNALMODE_OFF
+- || p->journalMode==PAGER_JOURNALMODE_WAL
+- );
+- assert( pPager->dbOrigSize<=pPager->dbHintSize );
+- break;
+-
+- case PAGER_WRITER_FINISHED:
+- assert( p->eLock==EXCLUSIVE_LOCK );
+- assert( pPager->errCode==SQLITE_OK );
+- assert( !pagerUseWal(pPager) );
+- assert( isOpen(p->jfd)
+- || p->journalMode==PAGER_JOURNALMODE_OFF
+- || p->journalMode==PAGER_JOURNALMODE_WAL
+- );
+- break;
+-
+- case PAGER_ERROR:
+- /* There must be at least one outstanding reference to the pager if
+- ** in ERROR state. Otherwise the pager should have already dropped
+- ** back to OPEN state.
+- */
+- assert( pPager->errCode!=SQLITE_OK );
+- assert( sqlite3PcacheRefCount(pPager->pPCache)>0 );
+- break;
++ /* While this module could theoretically support it, sqlite3RowSetNext()
++ ** is never called after sqlite3RowSetText() for the same RowSet. So
++ ** there is never a forest to deal with. Should this change, simply
++ ** remove the assert() and the #if 0. */
++ assert( p->pForest==0 );
++#if 0
++ while( p->pForest ){
++ struct RowSetEntry *pTree = p->pForest->pLeft;
++ if( pTree ){
++ struct RowSetEntry *pHead, *pTail;
++ rowSetTreeToList(pTree, &pHead, &pTail);
++ p->pEntry = rowSetEntryMerge(p->pEntry, pHead);
++ }
++ p->pForest = p->pForest->pRight;
+ }
+-
+- return 1;
++#endif
++ p->rsFlags |= ROWSET_NEXT; /* Verify this routine is never called again */
+ }
+-#endif /* ifndef NDEBUG */
+
+-#ifdef SQLITE_DEBUG
+ /*
+-** Return a pointer to a human readable string in a static buffer
+-** containing the state of the Pager object passed as an argument. This
+-** is intended to be used within debuggers. For example, as an alternative
+-** to "print *pPager" in gdb:
++** Extract the smallest element from the RowSet.
++** Write the element into *pRowid. Return 1 on success. Return
++** 0 if the RowSet is already empty.
+ **
+-** (gdb) printf "%s", print_pager_state(pPager)
++** After this routine has been called, the sqlite3RowSetInsert()
++** routine may not be called again.
+ */
+-static char *print_pager_state(Pager *p){
+- static char zRet[1024];
++SQLITE_PRIVATE int sqlite3RowSetNext(RowSet *p, i64 *pRowid){
++ assert( p!=0 );
+
+- sqlite3_snprintf(1024, zRet,
+- "Filename: %s\n"
+- "State: %s errCode=%d\n"
+- "Lock: %s\n"
+- "Locking mode: locking_mode=%s\n"
+- "Journal mode: journal_mode=%s\n"
+- "Backing store: tempFile=%d memDb=%d useJournal=%d\n"
+- "Journal: journalOff=%lld journalHdr=%lld\n"
+- "Size: dbsize=%d dbOrigSize=%d dbFileSize=%d\n"
+- , p->zFilename
+- , p->eState==PAGER_OPEN ? "OPEN" :
+- p->eState==PAGER_READER ? "READER" :
+- p->eState==PAGER_WRITER_LOCKED ? "WRITER_LOCKED" :
+- p->eState==PAGER_WRITER_CACHEMOD ? "WRITER_CACHEMOD" :
+- p->eState==PAGER_WRITER_DBMOD ? "WRITER_DBMOD" :
+- p->eState==PAGER_WRITER_FINISHED ? "WRITER_FINISHED" :
+- p->eState==PAGER_ERROR ? "ERROR" : "?error?"
+- , (int)p->errCode
+- , p->eLock==NO_LOCK ? "NO_LOCK" :
+- p->eLock==RESERVED_LOCK ? "RESERVED" :
+- p->eLock==EXCLUSIVE_LOCK ? "EXCLUSIVE" :
+- p->eLock==SHARED_LOCK ? "SHARED" :
+- p->eLock==UNKNOWN_LOCK ? "UNKNOWN" : "?error?"
+- , p->exclusiveMode ? "exclusive" : "normal"
+- , p->journalMode==PAGER_JOURNALMODE_MEMORY ? "memory" :
+- p->journalMode==PAGER_JOURNALMODE_OFF ? "off" :
+- p->journalMode==PAGER_JOURNALMODE_DELETE ? "delete" :
+- p->journalMode==PAGER_JOURNALMODE_PERSIST ? "persist" :
+- p->journalMode==PAGER_JOURNALMODE_TRUNCATE ? "truncate" :
+- p->journalMode==PAGER_JOURNALMODE_WAL ? "wal" : "?error?"
+- , (int)p->tempFile, (int)p->memDb, (int)p->useJournal
+- , p->journalOff, p->journalHdr
+- , (int)p->dbSize, (int)p->dbOrigSize, (int)p->dbFileSize
+- );
++ /* Merge the forest into a single sorted list on first call */
++ if( (p->rsFlags & ROWSET_NEXT)==0 ) rowSetToList(p);
+
+- return zRet;
++ /* Return the next entry on the list */
++ if( p->pEntry ){
++ *pRowid = p->pEntry->v;
++ p->pEntry = p->pEntry->pRight;
++ if( p->pEntry==0 ){
++ sqlite3RowSetClear(p);
++ }
++ return 1;
++ }else{
++ return 0;
++ }
+ }
+-#endif
+
+ /*
+-** Return true if it is necessary to write page *pPg into the sub-journal.
+-** A page needs to be written into the sub-journal if there exists one
+-** or more open savepoints for which:
++** Check to see if element iRowid was inserted into the rowset as
++** part of any insert batch prior to iBatch. Return 1 or 0.
+ **
+-** * The page-number is less than or equal to PagerSavepoint.nOrig, and
+-** * The bit corresponding to the page-number is not set in
+-** PagerSavepoint.pInSavepoint.
++** If this is the first test of a new batch and if there exist entries
++** on pRowSet->pEntry, then sort those entries into the forest at
++** pRowSet->pForest so that they can be tested.
+ */
+-static int subjRequiresPage(PgHdr *pPg){
+- Pager *pPager = pPg->pPager;
+- PagerSavepoint *p;
+- Pgno pgno = pPg->pgno;
+- int i;
+- for(i=0; i<pPager->nSavepoint; i++){
+- p = &pPager->aSavepoint[i];
+- if( p->nOrig>=pgno && 0==sqlite3BitvecTest(p->pInSavepoint, pgno) ){
+- return 1;
++SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64 iRowid){
++ struct RowSetEntry *p, *pTree;
++
++ /* This routine is never called after sqlite3RowSetNext() */
++ assert( pRowSet!=0 && (pRowSet->rsFlags & ROWSET_NEXT)==0 );
++
++ /* Sort entries into the forest on the first test of a new batch
++ */
++ if( iBatch!=pRowSet->iBatch ){
++ p = pRowSet->pEntry;
++ if( p ){
++ struct RowSetEntry **ppPrevTree = &pRowSet->pForest;
++ if( (pRowSet->rsFlags & ROWSET_SORTED)==0 ){
++ p = rowSetEntrySort(p);
++ }
++ for(pTree = pRowSet->pForest; pTree; pTree=pTree->pRight){
++ ppPrevTree = &pTree->pRight;
++ if( pTree->pLeft==0 ){
++ pTree->pLeft = rowSetListToTree(p);
++ break;
++ }else{
++ struct RowSetEntry *pAux, *pTail;
++ rowSetTreeToList(pTree->pLeft, &pAux, &pTail);
++ pTree->pLeft = 0;
++ p = rowSetEntryMerge(pAux, p);
++ }
++ }
++ if( pTree==0 ){
++ *ppPrevTree = pTree = rowSetEntryAlloc(pRowSet);
++ if( pTree ){
++ pTree->v = 0;
++ pTree->pRight = 0;
++ pTree->pLeft = rowSetListToTree(p);
++ }
++ }
++ pRowSet->pEntry = 0;
++ pRowSet->pLast = 0;
++ pRowSet->rsFlags |= ROWSET_SORTED;
++ }
++ pRowSet->iBatch = iBatch;
++ }
++
++ /* Test to see if the iRowid value appears anywhere in the forest.
++ ** Return 1 if it does and 0 if not.
++ */
++ for(pTree = pRowSet->pForest; pTree; pTree=pTree->pRight){
++ p = pTree->pLeft;
++ while( p ){
++ if( p->v<iRowid ){
++ p = p->pRight;
++ }else if( p->v>iRowid ){
++ p = p->pLeft;
++ }else{
++ return 1;
++ }
+ }
+ }
+ return 0;
+ }
+
++/************** End of rowset.c **********************************************/
++/************** Begin file pager.c *******************************************/
+ /*
+-** Return true if the page is already in the journal file.
++** 2001 September 15
++**
++** The author disclaims copyright to this source code. In place of
++** a legal notice, here is a blessing:
++**
++** May you do good and not evil.
++** May you find forgiveness for yourself and forgive others.
++** May you share freely, never taking more than you give.
++**
++*************************************************************************
++** This is the implementation of the page cache subsystem or "pager".
++**
++** The pager is used to access a database disk file. It implements
++** atomic commit and rollback through the use of a journal file that
++** is separate from the database file. The pager also implements file
++** locking to prevent two processes from writing the same database
++** file simultaneously, or one process from reading the database while
++** another is writing.
+ */
+-static int pageInJournal(Pager *pPager, PgHdr *pPg){
+- return sqlite3BitvecTest(pPager->pInJournal, pPg->pgno);
+-}
+-
++#ifndef SQLITE_OMIT_DISKIO
++/************** Include wal.h in the middle of pager.c ***********************/
++/************** Begin file wal.h *********************************************/
+ /*
+-** Read a 32-bit integer from the given file descriptor. Store the integer
+-** that is read in *pRes. Return SQLITE_OK if everything worked, or an
+-** error code is something goes wrong.
++** 2010 February 1
+ **
+-** All values are stored on disk as big-endian.
++** 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 header file defines the interface to the write-ahead logging
++** system. Refer to the comments below and the header comment attached to
++** the implementation of each function in log.c for further details.
+ */
+-static int read32bits(sqlite3_file *fd, i64 offset, u32 *pRes){
+- unsigned char ac[4];
+- int rc = sqlite3OsRead(fd, ac, sizeof(ac), offset);
+- if( rc==SQLITE_OK ){
+- *pRes = sqlite3Get4byte(ac);
+- }
+- return rc;
+-}
+
+-/*
+-** Write a 32-bit integer into a string buffer in big-endian byte order.
+-*/
+-#define put32bits(A,B) sqlite3Put4byte((u8*)A,B)
++#ifndef _WAL_H_
++#define _WAL_H_
+
+
+-/*
+-** Write a 32-bit integer into the given file descriptor. Return SQLITE_OK
+-** on success or an error code is something goes wrong.
++/* Additional values that can be added to the sync_flags argument of
++** sqlite3WalFrames():
+ */
+-static int write32bits(sqlite3_file *fd, i64 offset, u32 val){
+- char ac[4];
+- put32bits(ac, val);
+- return sqlite3OsWrite(fd, ac, 4, offset);
+-}
++#define WAL_SYNC_TRANSACTIONS 0x20 /* Sync at the end of each transaction */
++#define SQLITE_SYNC_MASK 0x13 /* Mask off the SQLITE_SYNC_* values */
+
+-/*
+-** Unlock the database file to level eLock, which must be either NO_LOCK
+-** or SHARED_LOCK. Regardless of whether or not the call to xUnlock()
+-** succeeds, set the Pager.eLock variable to match the (attempted) new lock.
+-**
+-** Except, if Pager.eLock is set to UNKNOWN_LOCK when this function is
+-** called, do not modify it. See the comment above the #define of
+-** UNKNOWN_LOCK for an explanation of this.
++#ifdef SQLITE_OMIT_WAL
++# define sqlite3WalOpen(x,y,z) 0
++# define sqlite3WalLimit(x,y)
++# define sqlite3WalClose(w,x,y,z) 0
++# define sqlite3WalBeginReadTransaction(y,z) 0
++# define sqlite3WalEndReadTransaction(z)
++# define sqlite3WalDbsize(y) 0
++# define sqlite3WalBeginWriteTransaction(y) 0
++# define sqlite3WalEndWriteTransaction(x) 0
++# define sqlite3WalUndo(x,y,z) 0
++# define sqlite3WalSavepoint(y,z)
++# define sqlite3WalSavepointUndo(y,z) 0
++# define sqlite3WalFrames(u,v,w,x,y,z) 0
++# define sqlite3WalCheckpoint(r,s,t,u,v,w,x,y,z) 0
++# define sqlite3WalCallback(z) 0
++# define sqlite3WalExclusiveMode(y,z) 0
++# define sqlite3WalHeapMemory(z) 0
++# define sqlite3WalFramesize(z) 0
++# define sqlite3WalFindFrame(x,y,z) 0
++#else
++
++#define WAL_SAVEPOINT_NDATA 4
++
++/* Connection to a write-ahead log (WAL) file.
++** There is one object of this type for each pager.
+ */
+-static int pagerUnlockDb(Pager *pPager, int eLock){
+- int rc = SQLITE_OK;
++typedef struct Wal Wal;
+
+- assert( !pPager->exclusiveMode || pPager->eLock==eLock );
+- assert( eLock==NO_LOCK || eLock==SHARED_LOCK );
+- assert( eLock!=NO_LOCK || pagerUseWal(pPager)==0 );
+- if( isOpen(pPager->fd) ){
+- assert( pPager->eLock>=eLock );
+- rc = pPager->noLock ? SQLITE_OK : sqlite3OsUnlock(pPager->fd, eLock);
+- if( pPager->eLock!=UNKNOWN_LOCK ){
+- pPager->eLock = (u8)eLock;
+- }
+- IOTRACE(("UNLOCK %p %d\n", pPager, eLock))
+- }
+- return rc;
+-}
++/* Open and close a connection to a write-ahead log. */
++SQLITE_PRIVATE int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *, int, i64, Wal**);
++SQLITE_PRIVATE int sqlite3WalClose(Wal *pWal, int sync_flags, int, u8 *);
+
+-/*
+-** Lock the database file to level eLock, which must be either SHARED_LOCK,
+-** RESERVED_LOCK or EXCLUSIVE_LOCK. If the caller is successful, set the
+-** Pager.eLock variable to the new locking state.
+-**
+-** Except, if Pager.eLock is set to UNKNOWN_LOCK when this function is
+-** called, do not modify it unless the new locking state is EXCLUSIVE_LOCK.
+-** See the comment above the #define of UNKNOWN_LOCK for an explanation
+-** of this.
++/* Set the limiting size of a WAL file. */
++SQLITE_PRIVATE void sqlite3WalLimit(Wal*, i64);
++
++/* Used by readers to open (lock) and close (unlock) a snapshot. A
++** snapshot is like a read-transaction. It is the state of the database
++** at an instant in time. sqlite3WalOpenSnapshot gets a read lock and
++** preserves the current state even if the other threads or processes
++** write to or checkpoint the WAL. sqlite3WalCloseSnapshot() closes the
++** transaction and releases the lock.
+ */
+-static int pagerLockDb(Pager *pPager, int eLock){
+- int rc = SQLITE_OK;
++SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *);
++SQLITE_PRIVATE void sqlite3WalEndReadTransaction(Wal *pWal);
+
+- assert( eLock==SHARED_LOCK || eLock==RESERVED_LOCK || eLock==EXCLUSIVE_LOCK );
+- if( pPager->eLock<eLock || pPager->eLock==UNKNOWN_LOCK ){
+- rc = pPager->noLock ? SQLITE_OK : sqlite3OsLock(pPager->fd, eLock);
+- if( rc==SQLITE_OK && (pPager->eLock!=UNKNOWN_LOCK||eLock==EXCLUSIVE_LOCK) ){
+- pPager->eLock = (u8)eLock;
+- IOTRACE(("LOCK %p %d\n", pPager, eLock))
+- }
+- }
+- return rc;
+-}
++/* Read a page from the write-ahead log, if it is present. */
++SQLITE_PRIVATE int sqlite3WalFindFrame(Wal *, Pgno, u32 *);
++SQLITE_PRIVATE int sqlite3WalReadFrame(Wal *, u32, int, u8 *);
+
+-/*
+-** This function determines whether or not the atomic-write optimization
+-** can be used with this pager. The optimization can be used if:
+-**
+-** (a) the value returned by OsDeviceCharacteristics() indicates that
+-** a database page may be written atomically, and
+-** (b) the value returned by OsSectorSize() is less than or equal
+-** to the page size.
+-**
+-** The optimization is also always enabled for temporary files. It is
+-** an error to call this function if pPager is opened on an in-memory
+-** database.
+-**
+-** If the optimization cannot be used, 0 is returned. If it can be used,
+-** then the value returned is the size of the journal file when it
+-** contains rollback data for exactly one page.
++/* If the WAL is not empty, return the size of the database. */
++SQLITE_PRIVATE Pgno sqlite3WalDbsize(Wal *pWal);
++
++/* Obtain or release the WRITER lock. */
++SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal);
++SQLITE_PRIVATE int sqlite3WalEndWriteTransaction(Wal *pWal);
++
++/* Undo any frames written (but not committed) to the log */
++SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx);
++
++/* Return an integer that records the current (uncommitted) write
++** position in the WAL */
++SQLITE_PRIVATE void sqlite3WalSavepoint(Wal *pWal, u32 *aWalData);
++
++/* Move the write position of the WAL back to iFrame. Called in
++** response to a ROLLBACK TO command. */
++SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData);
++
++/* Write a frame or frames to the log. */
++SQLITE_PRIVATE int sqlite3WalFrames(Wal *pWal, int, PgHdr *, Pgno, int, int);
++
++/* Copy pages from the log to the database file */
++SQLITE_PRIVATE int sqlite3WalCheckpoint(
++ Wal *pWal, /* Write-ahead log connection */
++ int eMode, /* One of PASSIVE, FULL and RESTART */
++ int (*xBusy)(void*), /* Function to call when busy */
++ void *pBusyArg, /* Context argument for xBusyHandler */
++ int sync_flags, /* Flags to sync db file with (or 0) */
++ int nBuf, /* Size of buffer nBuf */
++ u8 *zBuf, /* Temporary buffer to use */
++ int *pnLog, /* OUT: Number of frames in WAL */
++ int *pnCkpt /* OUT: Number of backfilled frames in WAL */
++);
++
++/* Return the value to pass to a sqlite3_wal_hook callback, the
++** number of frames in the WAL at the point of the last commit since
++** sqlite3WalCallback() was called. If no commits have occurred since
++** the last call, then return 0.
+ */
+-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+-static int jrnlBufferSize(Pager *pPager){
+- assert( !MEMDB );
+- if( !pPager->tempFile ){
+- int dc; /* Device characteristics */
+- int nSector; /* Sector size */
+- int szPage; /* Page size */
++SQLITE_PRIVATE int sqlite3WalCallback(Wal *pWal);
+
+- assert( isOpen(pPager->fd) );
+- dc = sqlite3OsDeviceCharacteristics(pPager->fd);
+- nSector = pPager->sectorSize;
+- szPage = pPager->pageSize;
++/* Tell the wal layer that an EXCLUSIVE lock has been obtained (or released)
++** by the pager layer on the database file.
++*/
++SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op);
+
+- assert(SQLITE_IOCAP_ATOMIC512==(512>>8));
+- assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8));
+- if( 0==(dc&(SQLITE_IOCAP_ATOMIC|(szPage>>8)) || nSector>szPage) ){
+- return 0;
+- }
+- }
++/* Return true if the argument is non-NULL and the WAL module is using
++** heap-memory for the wal-index. Otherwise, if the argument is NULL or the
++** WAL module is using shared-memory, return false.
++*/
++SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal);
+
+- return JOURNAL_HDR_SZ(pPager) + JOURNAL_PG_SZ(pPager);
+-}
++#ifdef SQLITE_ENABLE_ZIPVFS
++/* If the WAL file is not empty, return the number of bytes of content
++** stored in each frame (i.e. the db page-size when the WAL was created).
++*/
++SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal);
+ #endif
+
++#endif /* ifndef SQLITE_OMIT_WAL */
++#endif /* _WAL_H_ */
++
++/************** End of wal.h *************************************************/
++/************** Continuing where we left off in pager.c **********************/
++
++
++/******************* NOTES ON THE DESIGN OF THE PAGER ************************
++**
++** This comment block describes invariants that hold when using a rollback
++** journal. These invariants do not apply for journal_mode=WAL,
++** journal_mode=MEMORY, or journal_mode=OFF.
++**
++** Within this comment block, a page is deemed to have been synced
++** automatically as soon as it is written when PRAGMA synchronous=OFF.
++** Otherwise, the page is not synced until the xSync method of the VFS
++** is called successfully on the file containing the page.
++**
++** Definition: A page of the database file is said to be "overwriteable" if
++** one or more of the following are true about the page:
++**
++** (a) The original content of the page as it was at the beginning of
++** the transaction has been written into the rollback journal and
++** synced.
++**
++** (b) The page was a freelist leaf page at the start of the transaction.
++**
++** (c) The page number is greater than the largest page that existed in
++** the database file at the start of the transaction.
++**
++** (1) A page of the database file is never overwritten unless one of the
++** following are true:
++**
++** (a) The page and all other pages on the same sector are overwriteable.
++**
++** (b) The atomic page write optimization is enabled, and the entire
++** transaction other than the update of the transaction sequence
++** number consists of a single page change.
++**
++** (2) The content of a page written into the rollback journal exactly matches
++** both the content in the database when the rollback journal was written
++** and the content in the database at the beginning of the current
++** transaction.
++**
++** (3) Writes to the database file are an integer multiple of the page size
++** in length and are aligned on a page boundary.
++**
++** (4) Reads from the database file are either aligned on a page boundary and
++** an integer multiple of the page size in length or are taken from the
++** first 100 bytes of the database file.
++**
++** (5) All writes to the database file are synced prior to the rollback journal
++** being deleted, truncated, or zeroed.
++**
++** (6) If a master journal file is used, then all writes to the database file
++** are synced prior to the master journal being deleted.
++**
++** Definition: Two databases (or the same database at two points it time)
++** are said to be "logically equivalent" if they give the same answer to
++** all queries. Note in particular the content of freelist leaf
++** pages can be changed arbitrarily without affecting the logical equivalence
++** of the database.
++**
++** (7) At any time, if any subset, including the empty set and the total set,
++** of the unsynced changes to a rollback journal are removed and the
++** journal is rolled back, the resulting database file will be logically
++** equivalent to the database file at the beginning of the transaction.
++**
++** (8) When a transaction is rolled back, the xTruncate method of the VFS
++** is called to restore the database file to the same size it was at
++** the beginning of the transaction. (In some VFSes, the xTruncate
++** method is a no-op, but that does not change the fact the SQLite will
++** invoke it.)
++**
++** (9) Whenever the database file is modified, at least one bit in the range
++** of bytes from 24 through 39 inclusive will be changed prior to releasing
++** the EXCLUSIVE lock, thus signaling other connections on the same
++** database to flush their caches.
++**
++** (10) The pattern of bits in bytes 24 through 39 shall not repeat in less
++** than one billion transactions.
++**
++** (11) A database file is well-formed at the beginning and at the conclusion
++** of every transaction.
++**
++** (12) An EXCLUSIVE lock is held on the database file when writing to
++** the database file.
++**
++** (13) A SHARED lock is held on the database file while reading any
++** content out of the database file.
++**
++******************************************************************************/
++
+ /*
+-** If SQLITE_CHECK_PAGES is defined then we do some sanity checking
+-** on the cache using a hash function. This is used for testing
+-** and debugging only.
+-*/
+-#ifdef SQLITE_CHECK_PAGES
+-/*
+-** Return a 32-bit hash of the page data for pPage.
++** Macros for troubleshooting. Normally turned off
+ */
+-static u32 pager_datahash(int nByte, unsigned char *pData){
+- u32 hash = 0;
+- int i;
+- for(i=0; i<nByte; i++){
+- hash = (hash*1039) + pData[i];
+- }
+- return hash;
+-}
+-static u32 pager_pagehash(PgHdr *pPage){
+- return pager_datahash(pPage->pPager->pageSize, (unsigned char *)pPage->pData);
+-}
+-static void pager_set_pagehash(PgHdr *pPage){
+- pPage->pageHash = pager_pagehash(pPage);
+-}
++#if 0
++int sqlite3PagerTrace=1; /* True to enable tracing */
++#define sqlite3DebugPrintf printf
++#define PAGERTRACE(X) if( sqlite3PagerTrace ){ sqlite3DebugPrintf X; }
++#else
++#define PAGERTRACE(X)
++#endif
+
+ /*
+-** The CHECK_PAGE macro takes a PgHdr* as an argument. If SQLITE_CHECK_PAGES
+-** is defined, and NDEBUG is not defined, an assert() statement checks
+-** that the page is either dirty or still matches the calculated page-hash.
++** The following two macros are used within the PAGERTRACE() macros above
++** to print out file-descriptors.
++**
++** PAGERID() takes a pointer to a Pager struct as its argument. The
++** associated file-descriptor is returned. FILEHANDLEID() takes an sqlite3_file
++** struct as its argument.
+ */
+-#define CHECK_PAGE(x) checkPage(x)
+-static void checkPage(PgHdr *pPg){
+- Pager *pPager = pPg->pPager;
+- assert( pPager->eState!=PAGER_ERROR );
+- assert( (pPg->flags&PGHDR_DIRTY) || pPg->pageHash==pager_pagehash(pPg) );
+-}
+-
+-#else
+-#define pager_datahash(X,Y) 0
+-#define pager_pagehash(X) 0
+-#define pager_set_pagehash(X)
+-#define CHECK_PAGE(x)
+-#endif /* SQLITE_CHECK_PAGES */
++#define PAGERID(p) ((int)(p->fd))
++#define FILEHANDLEID(fd) ((int)fd)
+
+ /*
+-** When this is called the journal file for pager pPager must be open.
+-** This function attempts to read a master journal file name from the
+-** end of the file and, if successful, copies it into memory supplied
+-** by the caller. See comments above writeMasterJournal() for the format
+-** used to store a master journal file name at the end of a journal file.
++** The Pager.eState variable stores the current 'state' of a pager. A
++** pager may be in any one of the seven states shown in the following
++** state diagram.
++**
++** OPEN <------+------+
++** | | |
++** V | |
++** +---------> READER-------+ |
++** | | |
++** | V |
++** |<-------WRITER_LOCKED------> ERROR
++** | | ^
++** | V |
++** |<------WRITER_CACHEMOD-------->|
++** | | |
++** | V |
++** |<-------WRITER_DBMOD---------->|
++** | | |
++** | V |
++** +<------WRITER_FINISHED-------->+
++**
++**
++** List of state transitions and the C [function] that performs each:
++**
++** OPEN -> READER [sqlite3PagerSharedLock]
++** READER -> OPEN [pager_unlock]
++**
++** READER -> WRITER_LOCKED [sqlite3PagerBegin]
++** WRITER_LOCKED -> WRITER_CACHEMOD [pager_open_journal]
++** WRITER_CACHEMOD -> WRITER_DBMOD [syncJournal]
++** WRITER_DBMOD -> WRITER_FINISHED [sqlite3PagerCommitPhaseOne]
++** WRITER_*** -> READER [pager_end_transaction]
++**
++** WRITER_*** -> ERROR [pager_error]
++** ERROR -> OPEN [pager_unlock]
++**
++**
++** OPEN:
++**
++** The pager starts up in this state. Nothing is guaranteed in this
++** state - the file may or may not be locked and the database size is
++** unknown. The database may not be read or written.
++**
++** * No read or write transaction is active.
++** * Any lock, or no lock at all, may be held on the database file.
++** * The dbSize, dbOrigSize and dbFileSize variables may not be trusted.
++**
++** READER:
++**
++** In this state all the requirements for reading the database in
++** rollback (non-WAL) mode are met. Unless the pager is (or recently
++** was) in exclusive-locking mode, a user-level read transaction is
++** open. The database size is known in this state.
++**
++** A connection running with locking_mode=normal enters this state when
++** it opens a read-transaction on the database and returns to state
++** OPEN after the read-transaction is completed. However a connection
++** running in locking_mode=exclusive (including temp databases) remains in
++** this state even after the read-transaction is closed. The only way
++** a locking_mode=exclusive connection can transition from READER to OPEN
++** is via the ERROR state (see below).
++**
++** * A read transaction may be active (but a write-transaction cannot).
++** * A SHARED or greater lock is held on the database file.
++** * The dbSize variable may be trusted (even if a user-level read
++** transaction is not active). The dbOrigSize and dbFileSize variables
++** may not be trusted at this point.
++** * If the database is a WAL database, then the WAL connection is open.
++** * Even if a read-transaction is not open, it is guaranteed that
++** there is no hot-journal in the file-system.
++**
++** WRITER_LOCKED:
++**
++** The pager moves to this state from READER when a write-transaction
++** is first opened on the database. In WRITER_LOCKED state, all locks
++** required to start a write-transaction are held, but no actual
++** modifications to the cache or database have taken place.
++**
++** In rollback mode, a RESERVED or (if the transaction was opened with
++** BEGIN EXCLUSIVE) EXCLUSIVE lock is obtained on the database file when
++** moving to this state, but the journal file is not written to or opened
++** to in this state. If the transaction is committed or rolled back while
++** in WRITER_LOCKED state, all that is required is to unlock the database
++** file.
++**
++** IN WAL mode, WalBeginWriteTransaction() is called to lock the log file.
++** If the connection is running with locking_mode=exclusive, an attempt
++** is made to obtain an EXCLUSIVE lock on the database file.
++**
++** * A write transaction is active.
++** * If the connection is open in rollback-mode, a RESERVED or greater
++** lock is held on the database file.
++** * If the connection is open in WAL-mode, a WAL write transaction
++** is open (i.e. sqlite3WalBeginWriteTransaction() has been successfully
++** called).
++** * The dbSize, dbOrigSize and dbFileSize variables are all valid.
++** * The contents of the pager cache have not been modified.
++** * The journal file may or may not be open.
++** * Nothing (not even the first header) has been written to the journal.
++**
++** WRITER_CACHEMOD:
++**
++** A pager moves from WRITER_LOCKED state to this state when a page is
++** first modified by the upper layer. In rollback mode the journal file
++** is opened (if it is not already open) and a header written to the
++** start of it. The database file on disk has not been modified.
++**
++** * A write transaction is active.
++** * A RESERVED or greater lock is held on the database file.
++** * The journal file is open and the first header has been written
++** to it, but the header has not been synced to disk.
++** * The contents of the page cache have been modified.
+ **
+-** zMaster must point to a buffer of at least nMaster bytes allocated by
+-** the caller. This should be sqlite3_vfs.mxPathname+1 (to ensure there is
+-** enough space to write the master journal name). If the master journal
+-** name in the journal is longer than nMaster bytes (including a
+-** nul-terminator), then this is handled as if no master journal name
+-** were present in the journal.
++** WRITER_DBMOD:
+ **
+-** If a master journal file name is present at the end of the journal
+-** file, then it is copied into the buffer pointed to by zMaster. A
+-** nul-terminator byte is appended to the buffer following the master
+-** journal file name.
++** The pager transitions from WRITER_CACHEMOD into WRITER_DBMOD state
++** when it modifies the contents of the database file. WAL connections
++** never enter this state (since they do not modify the database file,
++** just the log file).
+ **
+-** If it is determined that no master journal file name is present
+-** zMaster[0] is set to 0 and SQLITE_OK returned.
++** * A write transaction is active.
++** * An EXCLUSIVE or greater lock is held on the database file.
++** * The journal file is open and the first header has been written
++** and synced to disk.
++** * The contents of the page cache have been modified (and possibly
++** written to disk).
+ **
+-** If an error occurs while reading from the journal file, an SQLite
+-** error code is returned.
+-*/
+-static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, u32 nMaster){
+- int rc; /* Return code */
+- u32 len; /* Length in bytes of master journal name */
+- i64 szJ; /* Total size in bytes of journal file pJrnl */
+- u32 cksum; /* MJ checksum value read from journal */
+- u32 u; /* Unsigned loop counter */
+- unsigned char aMagic[8]; /* A buffer to hold the magic header */
+- zMaster[0] = '\0';
+-
+- if( SQLITE_OK!=(rc = sqlite3OsFileSize(pJrnl, &szJ))
+- || szJ<16
+- || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-16, &len))
+- || len>=nMaster
+- || len==0
+- || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-12, &cksum))
+- || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, aMagic, 8, szJ-8))
+- || memcmp(aMagic, aJournalMagic, 8)
+- || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, zMaster, len, szJ-16-len))
+- ){
+- return rc;
+- }
+-
+- /* See if the checksum matches the master journal name */
+- for(u=0; u<len; u++){
+- cksum -= zMaster[u];
+- }
+- if( cksum ){
+- /* If the checksum doesn't add up, then one or more of the disk sectors
+- ** containing the master journal filename is corrupted. This means
+- ** definitely roll back, so just return SQLITE_OK and report a (nul)
+- ** master-journal filename.
+- */
+- len = 0;
+- }
+- zMaster[len] = '\0';
+-
+- return SQLITE_OK;
+-}
+-
+-/*
+-** Return the offset of the sector boundary at or immediately
+-** following the value in pPager->journalOff, assuming a sector
+-** size of pPager->sectorSize bytes.
++** WRITER_FINISHED:
+ **
+-** i.e for a sector size of 512:
++** It is not possible for a WAL connection to enter this state.
+ **
+-** Pager.journalOff Return value
+-** ---------------------------------------
+-** 0 0
+-** 512 512
+-** 100 512
+-** 2000 2048
+-**
+-*/
+-static i64 journalHdrOffset(Pager *pPager){
+- i64 offset = 0;
+- i64 c = pPager->journalOff;
+- if( c ){
+- offset = ((c-1)/JOURNAL_HDR_SZ(pPager) + 1) * JOURNAL_HDR_SZ(pPager);
+- }
+- assert( offset%JOURNAL_HDR_SZ(pPager)==0 );
+- assert( offset>=c );
+- assert( (offset-c)<JOURNAL_HDR_SZ(pPager) );
+- return offset;
+-}
+-
+-/*
+-** The journal file must be open when this function is called.
++** A rollback-mode pager changes to WRITER_FINISHED state from WRITER_DBMOD
++** state after the entire transaction has been successfully written into the
++** database file. In this state the transaction may be committed simply
++** by finalizing the journal file. Once in WRITER_FINISHED state, it is
++** not possible to modify the database further. At this point, the upper
++** layer must either commit or rollback the transaction.
+ **
+-** This function is a no-op if the journal file has not been written to
+-** within the current transaction (i.e. if Pager.journalOff==0).
++** * A write transaction is active.
++** * An EXCLUSIVE or greater lock is held on the database file.
++** * All writing and syncing of journal and database data has finished.
++** If no error occurred, all that remains is to finalize the journal to
++** commit the transaction. If an error did occur, the caller will need
++** to rollback the transaction.
+ **
+-** If doTruncate is non-zero or the Pager.journalSizeLimit variable is
+-** set to 0, then truncate the journal file to zero bytes in size. Otherwise,
+-** zero the 28-byte header at the start of the journal file. In either case,
+-** if the pager is not in no-sync mode, sync the journal file immediately
+-** after writing or truncating it.
++** ERROR:
+ **
+-** If Pager.journalSizeLimit is set to a positive, non-zero value, and
+-** following the truncation or zeroing described above the size of the
+-** journal file in bytes is larger than this value, then truncate the
+-** journal file to Pager.journalSizeLimit bytes. The journal file does
+-** not need to be synced following this operation.
++** The ERROR state is entered when an IO or disk-full error (including
++** SQLITE_IOERR_NOMEM) occurs at a point in the code that makes it
++** difficult to be sure that the in-memory pager state (cache contents,
++** db size etc.) are consistent with the contents of the file-system.
+ **
+-** If an IO error occurs, abandon processing and return the IO error code.
+-** Otherwise, return SQLITE_OK.
+-*/
+-static int zeroJournalHdr(Pager *pPager, int doTruncate){
+- int rc = SQLITE_OK; /* Return code */
+- assert( isOpen(pPager->jfd) );
+- if( pPager->journalOff ){
+- const i64 iLimit = pPager->journalSizeLimit; /* Local cache of jsl */
+-
+- IOTRACE(("JZEROHDR %p\n", pPager))
+- if( doTruncate || iLimit==0 ){
+- rc = sqlite3OsTruncate(pPager->jfd, 0);
+- }else{
+- static const char zeroHdr[28] = {0};
+- rc = sqlite3OsWrite(pPager->jfd, zeroHdr, sizeof(zeroHdr), 0);
+- }
+- if( rc==SQLITE_OK && !pPager->noSync ){
+- rc = sqlite3OsSync(pPager->jfd, SQLITE_SYNC_DATAONLY|pPager->syncFlags);
+- }
+-
+- /* At this point the transaction is committed but the write lock
+- ** is still held on the file. If there is a size limit configured for
+- ** the persistent journal and the journal file currently consumes more
+- ** space than that limit allows for, truncate it now. There is no need
+- ** to sync the file following this operation.
+- */
+- if( rc==SQLITE_OK && iLimit>0 ){
+- i64 sz;
+- rc = sqlite3OsFileSize(pPager->jfd, &sz);
+- if( rc==SQLITE_OK && sz>iLimit ){
+- rc = sqlite3OsTruncate(pPager->jfd, iLimit);
+- }
+- }
+- }
+- return rc;
+-}
+-
+-/*
+-** The journal file must be open when this routine is called. A journal
+-** header (JOURNAL_HDR_SZ bytes) is written into the journal file at the
+-** current location.
++** Temporary pager files may enter the ERROR state, but in-memory pagers
++** cannot.
+ **
+-** The format for the journal header is as follows:
+-** - 8 bytes: Magic identifying journal format.
+-** - 4 bytes: Number of records in journal, or -1 no-sync mode is on.
+-** - 4 bytes: Random number used for page hash.
+-** - 4 bytes: Initial database page count.
+-** - 4 bytes: Sector size used by the process that wrote this journal.
+-** - 4 bytes: Database page size.
+-**
+-** Followed by (JOURNAL_HDR_SZ - 28) bytes of unused space.
+-*/
+-static int writeJournalHdr(Pager *pPager){
+- int rc = SQLITE_OK; /* Return code */
+- char *zHeader = pPager->pTmpSpace; /* Temporary space used to build header */
+- u32 nHeader = (u32)pPager->pageSize;/* Size of buffer pointed to by zHeader */
+- u32 nWrite; /* Bytes of header sector written */
+- int ii; /* Loop counter */
+-
+- assert( isOpen(pPager->jfd) ); /* Journal file must be open. */
+-
+- if( nHeader>JOURNAL_HDR_SZ(pPager) ){
+- nHeader = JOURNAL_HDR_SZ(pPager);
+- }
+-
+- /* If there are active savepoints and any of them were created
+- ** since the most recent journal header was written, update the
+- ** PagerSavepoint.iHdrOffset fields now.
+- */
+- for(ii=0; ii<pPager->nSavepoint; ii++){
+- if( pPager->aSavepoint[ii].iHdrOffset==0 ){
+- pPager->aSavepoint[ii].iHdrOffset = pPager->journalOff;
+- }
+- }
+-
+- pPager->journalHdr = pPager->journalOff = journalHdrOffset(pPager);
+-
+- /*
+- ** Write the nRec Field - the number of page records that follow this
+- ** journal header. Normally, zero is written to this value at this time.
+- ** After the records are added to the journal (and the journal synced,
+- ** if in full-sync mode), the zero is overwritten with the true number
+- ** of records (see syncJournal()).
+- **
+- ** A faster alternative is to write 0xFFFFFFFF to the nRec field. When
+- ** reading the journal this value tells SQLite to assume that the
+- ** rest of the journal file contains valid page records. This assumption
+- ** is dangerous, as if a failure occurred whilst writing to the journal
+- ** file it may contain some garbage data. There are two scenarios
+- ** where this risk can be ignored:
+- **
+- ** * When the pager is in no-sync mode. Corruption can follow a
+- ** power failure in this case anyway.
+- **
+- ** * When the SQLITE_IOCAP_SAFE_APPEND flag is set. This guarantees
+- ** that garbage data is never appended to the journal file.
+- */
+- assert( isOpen(pPager->fd) || pPager->noSync );
+- if( pPager->noSync || (pPager->journalMode==PAGER_JOURNALMODE_MEMORY)
+- || (sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND)
+- ){
+- memcpy(zHeader, aJournalMagic, sizeof(aJournalMagic));
+- put32bits(&zHeader[sizeof(aJournalMagic)], 0xffffffff);
+- }else{
+- memset(zHeader, 0, sizeof(aJournalMagic)+4);
+- }
+-
+- /* The random check-hash initializer */
+- sqlite3_randomness(sizeof(pPager->cksumInit), &pPager->cksumInit);
+- put32bits(&zHeader[sizeof(aJournalMagic)+4], pPager->cksumInit);
+- /* The initial database size */
+- put32bits(&zHeader[sizeof(aJournalMagic)+8], pPager->dbOrigSize);
+- /* The assumed sector size for this process */
+- put32bits(&zHeader[sizeof(aJournalMagic)+12], pPager->sectorSize);
+-
+- /* The page size */
+- put32bits(&zHeader[sizeof(aJournalMagic)+16], pPager->pageSize);
+-
+- /* Initializing the tail of the buffer is not necessary. Everything
+- ** works find if the following memset() is omitted. But initializing
+- ** the memory prevents valgrind from complaining, so we are willing to
+- ** take the performance hit.
+- */
+- memset(&zHeader[sizeof(aJournalMagic)+20], 0,
+- nHeader-(sizeof(aJournalMagic)+20));
+-
+- /* In theory, it is only necessary to write the 28 bytes that the
+- ** journal header consumes to the journal file here. Then increment the
+- ** Pager.journalOff variable by JOURNAL_HDR_SZ so that the next
+- ** record is written to the following sector (leaving a gap in the file
+- ** that will be implicitly filled in by the OS).
+- **
+- ** However it has been discovered that on some systems this pattern can
+- ** be significantly slower than contiguously writing data to the file,
+- ** even if that means explicitly writing data to the block of
+- ** (JOURNAL_HDR_SZ - 28) bytes that will not be used. So that is what
+- ** is done.
+- **
+- ** The loop is required here in case the sector-size is larger than the
+- ** database page size. Since the zHeader buffer is only Pager.pageSize
+- ** bytes in size, more than one call to sqlite3OsWrite() may be required
+- ** to populate the entire journal header sector.
+- */
+- for(nWrite=0; rc==SQLITE_OK&&nWrite<JOURNAL_HDR_SZ(pPager); nWrite+=nHeader){
+- IOTRACE(("JHDR %p %lld %d\n", pPager, pPager->journalHdr, nHeader))
+- rc = sqlite3OsWrite(pPager->jfd, zHeader, nHeader, pPager->journalOff);
+- assert( pPager->journalHdr <= pPager->journalOff );
+- pPager->journalOff += nHeader;
+- }
+-
+- return rc;
+-}
+-
+-/*
+-** The journal file must be open when this is called. A journal header file
+-** (JOURNAL_HDR_SZ bytes) is read from the current location in the journal
+-** file. The current location in the journal file is given by
+-** pPager->journalOff. See comments above function writeJournalHdr() for
+-** a description of the journal header format.
++** For example, if an IO error occurs while performing a rollback,
++** the contents of the page-cache may be left in an inconsistent state.
++** At this point it would be dangerous to change back to READER state
++** (as usually happens after a rollback). Any subsequent readers might
++** report database corruption (due to the inconsistent cache), and if
++** they upgrade to writers, they may inadvertently corrupt the database
++** file. To avoid this hazard, the pager switches into the ERROR state
++** instead of READER following such an error.
+ **
+-** If the header is read successfully, *pNRec is set to the number of
+-** page records following this header and *pDbSize is set to the size of the
+-** database before the transaction began, in pages. Also, pPager->cksumInit
+-** is set to the value read from the journal header. SQLITE_OK is returned
+-** in this case.
++** Once it has entered the ERROR state, any attempt to use the pager
++** to read or write data returns an error. Eventually, once all
++** outstanding transactions have been abandoned, the pager is able to
++** transition back to OPEN state, discarding the contents of the
++** page-cache and any other in-memory state at the same time. Everything
++** is reloaded from disk (and, if necessary, hot-journal rollback peformed)
++** when a read-transaction is next opened on the pager (transitioning
++** the pager into READER state). At that point the system has recovered
++** from the error.
+ **
+-** If the journal header file appears to be corrupted, SQLITE_DONE is
+-** returned and *pNRec and *PDbSize are undefined. If JOURNAL_HDR_SZ bytes
+-** cannot be read from the journal file an error code is returned.
++** Specifically, the pager jumps into the ERROR state if:
++**
++** 1. An error occurs while attempting a rollback. This happens in
++** function sqlite3PagerRollback().
++**
++** 2. An error occurs while attempting to finalize a journal file
++** following a commit in function sqlite3PagerCommitPhaseTwo().
++**
++** 3. An error occurs while attempting to write to the journal or
++** database file in function pagerStress() in order to free up
++** memory.
++**
++** In other cases, the error is returned to the b-tree layer. The b-tree
++** layer then attempts a rollback operation. If the error condition
++** persists, the pager enters the ERROR state via condition (1) above.
++**
++** Condition (3) is necessary because it can be triggered by a read-only
++** statement executed within a transaction. In this case, if the error
++** code were simply returned to the user, the b-tree layer would not
++** automatically attempt a rollback, as it assumes that an error in a
++** read-only statement cannot leave the pager in an internally inconsistent
++** state.
++**
++** * The Pager.errCode variable is set to something other than SQLITE_OK.
++** * There are one or more outstanding references to pages (after the
++** last reference is dropped the pager should move back to OPEN state).
++** * The pager is not an in-memory pager.
++**
++**
++** Notes:
++**
++** * A pager is never in WRITER_DBMOD or WRITER_FINISHED state if the
++** connection is open in WAL mode. A WAL connection is always in one
++** of the first four states.
++**
++** * Normally, a connection open in exclusive mode is never in PAGER_OPEN
++** state. There are two exceptions: immediately after exclusive-mode has
++** been turned on (and before any read or write transactions are
++** executed), and when the pager is leaving the "error state".
++**
++** * See also: assert_pager_state().
+ */
+-static int readJournalHdr(
+- Pager *pPager, /* Pager object */
+- int isHot,
+- i64 journalSize, /* Size of the open journal file in bytes */
+- u32 *pNRec, /* OUT: Value read from the nRec field */
+- u32 *pDbSize /* OUT: Value of original database size field */
+-){
+- int rc; /* Return code */
+- unsigned char aMagic[8]; /* A buffer to hold the magic header */
+- i64 iHdrOff; /* Offset of journal header being read */
+-
+- assert( isOpen(pPager->jfd) ); /* Journal file must be open. */
+-
+- /* Advance Pager.journalOff to the start of the next sector. If the
+- ** journal file is too small for there to be a header stored at this
+- ** point, return SQLITE_DONE.
+- */
+- pPager->journalOff = journalHdrOffset(pPager);
+- if( pPager->journalOff+JOURNAL_HDR_SZ(pPager) > journalSize ){
+- return SQLITE_DONE;
+- }
+- iHdrOff = pPager->journalOff;
+-
+- /* Read in the first 8 bytes of the journal header. If they do not match
+- ** the magic string found at the start of each journal header, return
+- ** SQLITE_DONE. If an IO error occurs, return an error code. Otherwise,
+- ** proceed.
+- */
+- if( isHot || iHdrOff!=pPager->journalHdr ){
+- rc = sqlite3OsRead(pPager->jfd, aMagic, sizeof(aMagic), iHdrOff);
+- if( rc ){
+- return rc;
+- }
+- if( memcmp(aMagic, aJournalMagic, sizeof(aMagic))!=0 ){
+- return SQLITE_DONE;
+- }
+- }
+-
+- /* Read the first three 32-bit fields of the journal header: The nRec
+- ** field, the checksum-initializer and the database size at the start
+- ** of the transaction. Return an error code if anything goes wrong.
+- */
+- if( SQLITE_OK!=(rc = read32bits(pPager->jfd, iHdrOff+8, pNRec))
+- || SQLITE_OK!=(rc = read32bits(pPager->jfd, iHdrOff+12, &pPager->cksumInit))
+- || SQLITE_OK!=(rc = read32bits(pPager->jfd, iHdrOff+16, pDbSize))
+- ){
+- return rc;
+- }
+-
+- if( pPager->journalOff==0 ){
+- u32 iPageSize; /* Page-size field of journal header */
+- u32 iSectorSize; /* Sector-size field of journal header */
+-
+- /* Read the page-size and sector-size journal header fields. */
+- if( SQLITE_OK!=(rc = read32bits(pPager->jfd, iHdrOff+20, &iSectorSize))
+- || SQLITE_OK!=(rc = read32bits(pPager->jfd, iHdrOff+24, &iPageSize))
+- ){
+- return rc;
+- }
+-
+- /* Versions of SQLite prior to 3.5.8 set the page-size field of the
+- ** journal header to zero. In this case, assume that the Pager.pageSize
+- ** variable is already set to the correct page size.
+- */
+- if( iPageSize==0 ){
+- iPageSize = pPager->pageSize;
+- }
+-
+- /* Check that the values read from the page-size and sector-size fields
+- ** are within range. To be 'in range', both values need to be a power
+- ** of two greater than or equal to 512 or 32, and not greater than their
+- ** respective compile time maximum limits.
+- */
+- if( iPageSize<512 || iSectorSize<32
+- || iPageSize>SQLITE_MAX_PAGE_SIZE || iSectorSize>MAX_SECTOR_SIZE
+- || ((iPageSize-1)&iPageSize)!=0 || ((iSectorSize-1)&iSectorSize)!=0
+- ){
+- /* If the either the page-size or sector-size in the journal-header is
+- ** invalid, then the process that wrote the journal-header must have
+- ** crashed before the header was synced. In this case stop reading
+- ** the journal file here.
+- */
+- return SQLITE_DONE;
+- }
+-
+- /* Update the page-size to match the value read from the journal.
+- ** Use a testcase() macro to make sure that malloc failure within
+- ** PagerSetPagesize() is tested.
+- */
+- rc = sqlite3PagerSetPagesize(pPager, &iPageSize, -1);
+- testcase( rc!=SQLITE_OK );
+-
+- /* Update the assumed sector-size to match the value used by
+- ** the process that created this journal. If this journal was
+- ** created by a process other than this one, then this routine
+- ** is being called from within pager_playback(). The local value
+- ** of Pager.sectorSize is restored at the end of that routine.
+- */
+- pPager->sectorSize = iSectorSize;
+- }
+-
+- pPager->journalOff += JOURNAL_HDR_SZ(pPager);
+- return rc;
+-}
+-
++#define PAGER_OPEN 0
++#define PAGER_READER 1
++#define PAGER_WRITER_LOCKED 2
++#define PAGER_WRITER_CACHEMOD 3
++#define PAGER_WRITER_DBMOD 4
++#define PAGER_WRITER_FINISHED 5
++#define PAGER_ERROR 6
+
+ /*
+-** Write the supplied master journal name into the journal file for pager
+-** pPager at the current location. The master journal name must be the last
+-** thing written to a journal file. If the pager is in full-sync mode, the
+-** journal file descriptor is advanced to the next sector boundary before
+-** anything is written. The format is:
++** The Pager.eLock variable is almost always set to one of the
++** following locking-states, according to the lock currently held on
++** the database file: NO_LOCK, SHARED_LOCK, RESERVED_LOCK or EXCLUSIVE_LOCK.
++** This variable is kept up to date as locks are taken and released by
++** the pagerLockDb() and pagerUnlockDb() wrappers.
+ **
+-** + 4 bytes: PAGER_MJ_PGNO.
+-** + N bytes: Master journal filename in utf-8.
+-** + 4 bytes: N (length of master journal name in bytes, no nul-terminator).
+-** + 4 bytes: Master journal name checksum.
+-** + 8 bytes: aJournalMagic[].
++** If the VFS xLock() or xUnlock() returns an error other than SQLITE_BUSY
++** (i.e. one of the SQLITE_IOERR subtypes), it is not clear whether or not
++** the operation was successful. In these circumstances pagerLockDb() and
++** pagerUnlockDb() take a conservative approach - eLock is always updated
++** when unlocking the file, and only updated when locking the file if the
++** VFS call is successful. This way, the Pager.eLock variable may be set
++** to a less exclusive (lower) value than the lock that is actually held
++** at the system level, but it is never set to a more exclusive value.
+ **
+-** The master journal page checksum is the sum of the bytes in the master
+-** journal name, where each byte is interpreted as a signed 8-bit integer.
++** This is usually safe. If an xUnlock fails or appears to fail, there may
++** be a few redundant xLock() calls or a lock may be held for longer than
++** required, but nothing really goes wrong.
++**
++** The exception is when the database file is unlocked as the pager moves
++** from ERROR to OPEN state. At this point there may be a hot-journal file
++** in the file-system that needs to be rolled back (as part of an OPEN->SHARED
++** transition, by the same pager or any other). If the call to xUnlock()
++** fails at this point and the pager is left holding an EXCLUSIVE lock, this
++** can confuse the call to xCheckReservedLock() call made later as part
++** of hot-journal detection.
++**
++** xCheckReservedLock() is defined as returning true "if there is a RESERVED
++** lock held by this process or any others". So xCheckReservedLock may
++** return true because the caller itself is holding an EXCLUSIVE lock (but
++** doesn't know it because of a previous error in xUnlock). If this happens
++** a hot-journal may be mistaken for a journal being created by an active
++** transaction in another process, causing SQLite to read from the database
++** without rolling it back.
++**
++** To work around this, if a call to xUnlock() fails when unlocking the
++** database in the ERROR state, Pager.eLock is set to UNKNOWN_LOCK. It
++** is only changed back to a real locking state after a successful call
++** to xLock(EXCLUSIVE). Also, the code to do the OPEN->SHARED state transition
++** omits the check for a hot-journal if Pager.eLock is set to UNKNOWN_LOCK
++** lock. Instead, it assumes a hot-journal exists and obtains an EXCLUSIVE
++** lock on the database file before attempting to roll it back. See function
++** PagerSharedLock() for more detail.
+ **
+-** If zMaster is a NULL pointer (occurs for a single database transaction),
+-** this call is a no-op.
++** Pager.eLock may only be set to UNKNOWN_LOCK when the pager is in
++** PAGER_OPEN state.
+ */
+-static int writeMasterJournal(Pager *pPager, const char *zMaster){
+- int rc; /* Return code */
+- int nMaster; /* Length of string zMaster */
+- i64 iHdrOff; /* Offset of header in journal file */
+- i64 jrnlSize; /* Size of journal file on disk */
+- u32 cksum = 0; /* Checksum of string zMaster */
+-
+- assert( pPager->setMaster==0 );
+- assert( !pagerUseWal(pPager) );
+-
+- if( !zMaster
+- || pPager->journalMode==PAGER_JOURNALMODE_MEMORY
+- || !isOpen(pPager->jfd)
+- ){
+- return SQLITE_OK;
+- }
+- pPager->setMaster = 1;
+- assert( pPager->journalHdr <= pPager->journalOff );
+-
+- /* Calculate the length in bytes and the checksum of zMaster */
+- for(nMaster=0; zMaster[nMaster]; nMaster++){
+- cksum += zMaster[nMaster];
+- }
+-
+- /* If in full-sync mode, advance to the next disk sector before writing
+- ** the master journal name. This is in case the previous page written to
+- ** the journal has already been synced.
+- */
+- if( pPager->fullSync ){
+- pPager->journalOff = journalHdrOffset(pPager);
+- }
+- iHdrOff = pPager->journalOff;
+-
+- /* Write the master journal data to the end of the journal file. If
+- ** an error occurs, return the error code to the caller.
+- */
+- if( (0 != (rc = write32bits(pPager->jfd, iHdrOff, PAGER_MJ_PGNO(pPager))))
+- || (0 != (rc = sqlite3OsWrite(pPager->jfd, zMaster, nMaster, iHdrOff+4)))
+- || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nMaster, nMaster)))
+- || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nMaster+4, cksum)))
+- || (0 != (rc = sqlite3OsWrite(pPager->jfd, aJournalMagic, 8, iHdrOff+4+nMaster+8)))
+- ){
+- return rc;
+- }
+- pPager->journalOff += (nMaster+20);
+-
+- /* If the pager is in peristent-journal mode, then the physical
+- ** journal-file may extend past the end of the master-journal name
+- ** and 8 bytes of magic data just written to the file. This is
+- ** dangerous because the code to rollback a hot-journal file
+- ** will not be able to find the master-journal name to determine
+- ** whether or not the journal is hot.
+- **
+- ** Easiest thing to do in this scenario is to truncate the journal
+- ** file to the required size.
+- */
+- if( SQLITE_OK==(rc = sqlite3OsFileSize(pPager->jfd, &jrnlSize))
+- && jrnlSize>pPager->journalOff
+- ){
+- rc = sqlite3OsTruncate(pPager->jfd, pPager->journalOff);
+- }
+- return rc;
+-}
++#define UNKNOWN_LOCK (EXCLUSIVE_LOCK+1)
+
+ /*
+-** Discard the entire contents of the in-memory page-cache.
++** A macro used for invoking the codec if there is one
+ */
+-static void pager_reset(Pager *pPager){
+- pPager->iDataVersion++;
+- sqlite3BackupRestart(pPager->pBackup);
+- sqlite3PcacheClear(pPager->pPCache);
+-}
+#ifdef SQLITE_HAS_CODEC
-+SQLITE_PRIVATE void sqlite3pager_get_codec(Pager *pPager, void **ctx) {
-+ *ctx = pPager->pCodec;
++# define CODEC1(P,D,N,X,E) \
++ if( P->xCodec && P->xCodec(P->pCodec,D,N,X)==0 ){ E; }
++# define CODEC2(P,D,N,X,E,O) \
++ if( P->xCodec==0 ){ O=(char*)D; }else \
++ if( (O=(char*)(P->xCodec(P->pCodec,D,N,X)))==0 ){ E; }
++#else
++# define CODEC1(P,D,N,X,E) /* NO-OP */
++# define CODEC2(P,D,N,X,E,O) O=(char*)D
++#endif
+
+ /*
+-** Return the pPager->iDataVersion value
++** The maximum allowed sector size. 64KiB. If the xSectorsize() method
++** returns a value larger than this, then MAX_SECTOR_SIZE is used instead.
++** This could conceivably cause corruption following a power failure on
++** such a system. This is currently an undocumented limit.
+ */
+-SQLITE_PRIVATE u32 sqlite3PagerDataVersion(Pager *pPager){
+- assert( pPager->eState>PAGER_OPEN );
+- return pPager->iDataVersion;
+-}
++#define MAX_SECTOR_SIZE 0x10000
+
+ /*
+-** Free all structures in the Pager.aSavepoint[] array and set both
+-** Pager.aSavepoint and Pager.nSavepoint to zero. Close the sub-journal
+-** if it is open and the pager is not in exclusive mode.
++** An instance of the following structure is allocated for each active
++** savepoint and statement transaction in the system. All such structures
++** are stored in the Pager.aSavepoint[] array, which is allocated and
++** resized using sqlite3Realloc().
++**
++** When a savepoint is created, the PagerSavepoint.iHdrOffset field is
++** set to 0. If a journal-header is written into the main journal while
++** the savepoint is active, then iHdrOffset is set to the byte offset
++** immediately following the last journal record written into the main
++** journal before the journal-header. This is required during savepoint
++** rollback (see pagerPlaybackSavepoint()).
+ */
+-static void releaseAllSavepoints(Pager *pPager){
+- int ii; /* Iterator for looping through Pager.aSavepoint */
+- for(ii=0; ii<pPager->nSavepoint; ii++){
+- sqlite3BitvecDestroy(pPager->aSavepoint[ii].pInSavepoint);
+- }
+- if( !pPager->exclusiveMode || sqlite3IsMemJournal(pPager->sjfd) ){
+- sqlite3OsClose(pPager->sjfd);
+- }
+- sqlite3_free(pPager->aSavepoint);
+- pPager->aSavepoint = 0;
+- pPager->nSavepoint = 0;
+- pPager->nSubRec = 0;
+-}
++typedef struct PagerSavepoint PagerSavepoint;
++struct PagerSavepoint {
++ i64 iOffset; /* Starting offset in main journal */
++ i64 iHdrOffset; /* See above */
++ Bitvec *pInSavepoint; /* Set of pages in this savepoint */
++ Pgno nOrig; /* Original number of pages in file */
++ Pgno iSubRec; /* Index of first record in sub-journal */
++#ifndef SQLITE_OMIT_WAL
++ u32 aWalData[WAL_SAVEPOINT_NDATA]; /* WAL savepoint context */
++#endif
++};
+
+ /*
+-** Set the bit number pgno in the PagerSavepoint.pInSavepoint
+-** bitvecs of all open savepoints. Return SQLITE_OK if successful
+-** or SQLITE_NOMEM if a malloc failure occurs.
++** Bits of the Pager.doNotSpill flag. See further description below.
+ */
+-static int addToSavepointBitvecs(Pager *pPager, Pgno pgno){
+- int ii; /* Loop counter */
+- int rc = SQLITE_OK; /* Result code */
+-
+- for(ii=0; ii<pPager->nSavepoint; ii++){
+- PagerSavepoint *p = &pPager->aSavepoint[ii];
+- if( pgno<=p->nOrig ){
+- rc |= sqlite3BitvecSet(p->pInSavepoint, pgno);
+- testcase( rc==SQLITE_NOMEM );
+- assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
+- }
+- }
+- return rc;
+-}
++#define SPILLFLAG_OFF 0x01 /* Never spill cache. Set via pragma */
++#define SPILLFLAG_ROLLBACK 0x02 /* Current rolling back, so do not spill */
++#define SPILLFLAG_NOSYNC 0x04 /* Spill is ok, but do not sync */
+
+ /*
+-** This function is a no-op if the pager is in exclusive mode and not
+-** in the ERROR state. Otherwise, it switches the pager to PAGER_OPEN
+-** state.
++** An open page cache is an instance of struct Pager. A description of
++** some of the more important member variables follows:
+ **
+-** If the pager is not in exclusive-access mode, the database file is
+-** completely unlocked. If the file is unlocked and the file-system does
+-** not exhibit the UNDELETABLE_WHEN_OPEN property, the journal file is
+-** closed (if it is open).
++** eState
+ **
+-** If the pager is in ERROR state when this function is called, the
+-** contents of the pager cache are discarded before switching back to
+-** the OPEN state. Regardless of whether the pager is in exclusive-mode
+-** or not, any journal file left in the file-system will be treated
+-** as a hot-journal and rolled back the next time a read-transaction
+-** is opened (by this or by any other connection).
+-*/
+-static void pager_unlock(Pager *pPager){
+-
+- assert( pPager->eState==PAGER_READER
+- || pPager->eState==PAGER_OPEN
+- || pPager->eState==PAGER_ERROR
+- );
+-
+- sqlite3BitvecDestroy(pPager->pInJournal);
+- pPager->pInJournal = 0;
+- releaseAllSavepoints(pPager);
+-
+- if( pagerUseWal(pPager) ){
+- assert( !isOpen(pPager->jfd) );
+- sqlite3WalEndReadTransaction(pPager->pWal);
+- pPager->eState = PAGER_OPEN;
+- }else if( !pPager->exclusiveMode ){
+- int rc; /* Error code returned by pagerUnlockDb() */
+- int iDc = isOpen(pPager->fd)?sqlite3OsDeviceCharacteristics(pPager->fd):0;
+-
+- /* If the operating system support deletion of open files, then
+- ** close the journal file when dropping the database lock. Otherwise
+- ** another connection with journal_mode=delete might delete the file
+- ** out from under us.
+- */
+- assert( (PAGER_JOURNALMODE_MEMORY & 5)!=1 );
+- assert( (PAGER_JOURNALMODE_OFF & 5)!=1 );
+- assert( (PAGER_JOURNALMODE_WAL & 5)!=1 );
+- assert( (PAGER_JOURNALMODE_DELETE & 5)!=1 );
+- assert( (PAGER_JOURNALMODE_TRUNCATE & 5)==1 );
+- assert( (PAGER_JOURNALMODE_PERSIST & 5)==1 );
+- if( 0==(iDc & SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN)
+- || 1!=(pPager->journalMode & 5)
+- ){
+- sqlite3OsClose(pPager->jfd);
+- }
+-
+- /* If the pager is in the ERROR state and the call to unlock the database
+- ** file fails, set the current lock to UNKNOWN_LOCK. See the comment
+- ** above the #define for UNKNOWN_LOCK for an explanation of why this
+- ** is necessary.
+- */
+- rc = pagerUnlockDb(pPager, NO_LOCK);
+- if( rc!=SQLITE_OK && pPager->eState==PAGER_ERROR ){
+- pPager->eLock = UNKNOWN_LOCK;
+- }
+-
+- /* The pager state may be changed from PAGER_ERROR to PAGER_OPEN here
+- ** without clearing the error code. This is intentional - the error
+- ** code is cleared and the cache reset in the block below.
+- */
+- assert( pPager->errCode || pPager->eState!=PAGER_ERROR );
+- pPager->changeCountDone = 0;
+- pPager->eState = PAGER_OPEN;
+- }
+-
+- /* If Pager.errCode is set, the contents of the pager cache cannot be
+- ** trusted. Now that there are no outstanding references to the pager,
+- ** it can safely move back to PAGER_OPEN state. This happens in both
+- ** normal and exclusive-locking mode.
+- */
+- if( pPager->errCode ){
+- assert( !MEMDB );
+- pager_reset(pPager);
+- pPager->changeCountDone = pPager->tempFile;
+- pPager->eState = PAGER_OPEN;
+- pPager->errCode = SQLITE_OK;
+- if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0);
+- }
+-
+- pPager->journalOff = 0;
+- pPager->journalHdr = 0;
+- pPager->setMaster = 0;
+-}
+-
+-/*
+-** This function is called whenever an IOERR or FULL error that requires
+-** the pager to transition into the ERROR state may ahve occurred.
+-** The first argument is a pointer to the pager structure, the second
+-** the error-code about to be returned by a pager API function. The
+-** value returned is a copy of the second argument to this function.
++** The current 'state' of the pager object. See the comment and state
++** diagram above for a description of the pager state.
+ **
+-** If the second argument is SQLITE_FULL, SQLITE_IOERR or one of the
+-** IOERR sub-codes, the pager enters the ERROR state and the error code
+-** is stored in Pager.errCode. While the pager remains in the ERROR state,
+-** all major API calls on the Pager will immediately return Pager.errCode.
++** eLock
+ **
+-** The ERROR state indicates that the contents of the pager-cache
+-** cannot be trusted. This state can be cleared by completely discarding
+-** the contents of the pager-cache. If a transaction was active when
+-** the persistent error occurred, then the rollback journal may need
+-** to be replayed to restore the contents of the database file (as if
+-** it were a hot-journal).
+-*/
+-static int pager_error(Pager *pPager, int rc){
+- int rc2 = rc & 0xff;
+- assert( rc==SQLITE_OK || !MEMDB );
+- assert(
+- pPager->errCode==SQLITE_FULL ||
+- pPager->errCode==SQLITE_OK ||
+- (pPager->errCode & 0xff)==SQLITE_IOERR
+- );
+- if( rc2==SQLITE_FULL || rc2==SQLITE_IOERR ){
+- pPager->errCode = rc;
+- pPager->eState = PAGER_ERROR;
+- }
+- return rc;
+-}
+-
+-static int pager_truncate(Pager *pPager, Pgno nPage);
+-
+-/*
+-** This routine ends a transaction. A transaction is usually ended by
+-** either a COMMIT or a ROLLBACK operation. This routine may be called
+-** after rollback of a hot-journal, or if an error occurs while opening
+-** the journal file or writing the very first journal-header of a
+-** database transaction.
+-**
+-** This routine is never called in PAGER_ERROR state. If it is called
+-** in PAGER_NONE or PAGER_SHARED state and the lock held is less
+-** exclusive than a RESERVED lock, it is a no-op.
++** For a real on-disk database, the current lock held on the database file -
++** NO_LOCK, SHARED_LOCK, RESERVED_LOCK or EXCLUSIVE_LOCK.
+ **
+-** Otherwise, any active savepoints are released.
++** For a temporary or in-memory database (neither of which require any
++** locks), this variable is always set to EXCLUSIVE_LOCK. Since such
++** databases always have Pager.exclusiveMode==1, this tricks the pager
++** logic into thinking that it already has all the locks it will ever
++** need (and no reason to release them).
+ **
+-** If the journal file is open, then it is "finalized". Once a journal
+-** file has been finalized it is not possible to use it to roll back a
+-** transaction. Nor will it be considered to be a hot-journal by this
+-** or any other database connection. Exactly how a journal is finalized
+-** depends on whether or not the pager is running in exclusive mode and
+-** the current journal-mode (Pager.journalMode value), as follows:
++** In some (obscure) circumstances, this variable may also be set to
++** UNKNOWN_LOCK. See the comment above the #define of UNKNOWN_LOCK for
++** details.
+ **
+-** journalMode==MEMORY
+-** Journal file descriptor is simply closed. This destroys an
+-** in-memory journal.
++** changeCountDone
+ **
+-** journalMode==TRUNCATE
+-** Journal file is truncated to zero bytes in size.
++** This boolean variable is used to make sure that the change-counter
++** (the 4-byte header field at byte offset 24 of the database file) is
++** not updated more often than necessary.
+ **
+-** journalMode==PERSIST
+-** The first 28 bytes of the journal file are zeroed. This invalidates
+-** the first journal header in the file, and hence the entire journal
+-** file. An invalid journal file cannot be rolled back.
++** It is set to true when the change-counter field is updated, which
++** can only happen if an exclusive lock is held on the database file.
++** It is cleared (set to false) whenever an exclusive lock is
++** relinquished on the database file. Each time a transaction is committed,
++** The changeCountDone flag is inspected. If it is true, the work of
++** updating the change-counter is omitted for the current transaction.
+ **
+-** journalMode==DELETE
+-** The journal file is closed and deleted using sqlite3OsDelete().
++** This mechanism means that when running in exclusive mode, a connection
++** need only update the change-counter once, for the first transaction
++** committed.
+ **
+-** If the pager is running in exclusive mode, this method of finalizing
+-** the journal file is never used. Instead, if the journalMode is
+-** DELETE and the pager is in exclusive mode, the method described under
+-** journalMode==PERSIST is used instead.
++** setMaster
+ **
+-** After the journal is finalized, the pager moves to PAGER_READER state.
+-** If running in non-exclusive rollback mode, the lock on the file is
+-** downgraded to a SHARED_LOCK.
++** When PagerCommitPhaseOne() is called to commit a transaction, it may
++** (or may not) specify a master-journal name to be written into the
++** journal file before it is synced to disk.
+ **
+-** SQLITE_OK is returned if no error occurs. If an error occurs during
+-** any of the IO operations to finalize the journal file or unlock the
+-** database then the IO error code is returned to the user. If the
+-** operation to finalize the journal file fails, then the code still
+-** tries to unlock the database file if not in exclusive mode. If the
+-** unlock operation fails as well, then the first error code related
+-** to the first error encountered (the journal finalization one) is
+-** returned.
+-*/
+-static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
+- int rc = SQLITE_OK; /* Error code from journal finalization operation */
+- int rc2 = SQLITE_OK; /* Error code from db file unlock operation */
+-
+- /* Do nothing if the pager does not have an open write transaction
+- ** or at least a RESERVED lock. This function may be called when there
+- ** is no write-transaction active but a RESERVED or greater lock is
+- ** held under two circumstances:
+- **
+- ** 1. After a successful hot-journal rollback, it is called with
+- ** eState==PAGER_NONE and eLock==EXCLUSIVE_LOCK.
+- **
+- ** 2. If a connection with locking_mode=exclusive holding an EXCLUSIVE
+- ** lock switches back to locking_mode=normal and then executes a
+- ** read-transaction, this function is called with eState==PAGER_READER
+- ** and eLock==EXCLUSIVE_LOCK when the read-transaction is closed.
+- */
+- assert( assert_pager_state(pPager) );
+- assert( pPager->eState!=PAGER_ERROR );
+- if( pPager->eState<PAGER_WRITER_LOCKED && pPager->eLock<RESERVED_LOCK ){
+- return SQLITE_OK;
+- }
+-
+- releaseAllSavepoints(pPager);
+- assert( isOpen(pPager->jfd) || pPager->pInJournal==0 );
+- if( isOpen(pPager->jfd) ){
+- assert( !pagerUseWal(pPager) );
+-
+- /* Finalize the journal file. */
+- if( sqlite3IsMemJournal(pPager->jfd) ){
+- assert( pPager->journalMode==PAGER_JOURNALMODE_MEMORY );
+- sqlite3OsClose(pPager->jfd);
+- }else if( pPager->journalMode==PAGER_JOURNALMODE_TRUNCATE ){
+- if( pPager->journalOff==0 ){
+- rc = SQLITE_OK;
+- }else{
+- rc = sqlite3OsTruncate(pPager->jfd, 0);
+- if( rc==SQLITE_OK && pPager->fullSync ){
+- /* Make sure the new file size is written into the inode right away.
+- ** Otherwise the journal might resurrect following a power loss and
+- ** cause the last transaction to roll back. See
+- ** https://bugzilla.mozilla.org/show_bug.cgi?id=1072773
+- */
+- rc = sqlite3OsSync(pPager->jfd, pPager->syncFlags);
+- }
+- }
+- pPager->journalOff = 0;
+- }else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST
+- || (pPager->exclusiveMode && pPager->journalMode!=PAGER_JOURNALMODE_WAL)
+- ){
+- rc = zeroJournalHdr(pPager, hasMaster);
+- pPager->journalOff = 0;
+- }else{
+- /* This branch may be executed with Pager.journalMode==MEMORY if
+- ** a hot-journal was just rolled back. In this case the journal
+- ** file should be closed and deleted. If this connection writes to
+- ** the database file, it will do so using an in-memory journal.
+- */
+- int bDelete = (!pPager->tempFile && sqlite3JournalExists(pPager->jfd));
+- assert( pPager->journalMode==PAGER_JOURNALMODE_DELETE
+- || pPager->journalMode==PAGER_JOURNALMODE_MEMORY
+- || pPager->journalMode==PAGER_JOURNALMODE_WAL
+- );
+- sqlite3OsClose(pPager->jfd);
+- if( bDelete ){
+- rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
+- }
+- }
+- }
+-
+-#ifdef SQLITE_CHECK_PAGES
+- sqlite3PcacheIterateDirty(pPager->pPCache, pager_set_pagehash);
+- if( pPager->dbSize==0 && sqlite3PcacheRefCount(pPager->pPCache)>0 ){
+- PgHdr *p = sqlite3PagerLookup(pPager, 1);
+- if( p ){
+- p->pageHash = 0;
+- sqlite3PagerUnrefNotNull(p);
+- }
+- }
+-#endif
+-
+- sqlite3BitvecDestroy(pPager->pInJournal);
+- pPager->pInJournal = 0;
+- pPager->nRec = 0;
+- sqlite3PcacheCleanAll(pPager->pPCache);
+- sqlite3PcacheTruncate(pPager->pPCache, pPager->dbSize);
+-
+- if( pagerUseWal(pPager) ){
+- /* Drop the WAL write-lock, if any. Also, if the connection was in
+- ** locking_mode=exclusive mode but is no longer, drop the EXCLUSIVE
+- ** lock held on the database file.
+- */
+- rc2 = sqlite3WalEndWriteTransaction(pPager->pWal);
+- assert( rc2==SQLITE_OK );
+- }else if( rc==SQLITE_OK && bCommit && pPager->dbFileSize>pPager->dbSize ){
+- /* This branch is taken when committing a transaction in rollback-journal
+- ** mode if the database file on disk is larger than the database image.
+- ** At this point the journal has been finalized and the transaction
+- ** successfully committed, but the EXCLUSIVE lock is still held on the
+- ** file. So it is safe to truncate the database file to its minimum
+- ** required size. */
+- assert( pPager->eLock==EXCLUSIVE_LOCK );
+- rc = pager_truncate(pPager, pPager->dbSize);
+- }
+-
+- if( rc==SQLITE_OK && bCommit && isOpen(pPager->fd) ){
+- rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_COMMIT_PHASETWO, 0);
+- if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
+- }
+-
+- if( !pPager->exclusiveMode
+- && (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0))
+- ){
+- rc2 = pagerUnlockDb(pPager, SHARED_LOCK);
+- pPager->changeCountDone = 0;
+- }
+- pPager->eState = PAGER_READER;
+- pPager->setMaster = 0;
+-
+- return (rc==SQLITE_OK?rc2:rc);
+-}
+-
+-/*
+-** Execute a rollback if a transaction is active and unlock the
+-** database file.
++** Whether or not a journal file contains a master-journal pointer affects
++** the way in which the journal file is finalized after the transaction is
++** committed or rolled back when running in "journal_mode=PERSIST" mode.
++** If a journal file does not contain a master-journal pointer, it is
++** finalized by overwriting the first journal header with zeroes. If
++** it does contain a master-journal pointer the journal file is finalized
++** by truncating it to zero bytes, just as if the connection were
++** running in "journal_mode=truncate" mode.
++**
++** Journal files that contain master journal pointers cannot be finalized
++** simply by overwriting the first journal-header with zeroes, as the
++** master journal pointer could interfere with hot-journal rollback of any
++** subsequently interrupted transaction that reuses the journal file.
++**
++** The flag is cleared as soon as the journal file is finalized (either
++** by PagerCommitPhaseTwo or PagerRollback). If an IO error prevents the
++** journal file from being successfully finalized, the setMaster flag
++** is cleared anyway (and the pager will move to ERROR state).
++**
++** doNotSpill
++**
++** This variables control the behavior of cache-spills (calls made by
++** the pcache module to the pagerStress() routine to write cached data
++** to the file-system in order to free up memory).
++**
++** When bits SPILLFLAG_OFF or SPILLFLAG_ROLLBACK of doNotSpill are set,
++** writing to the database from pagerStress() is disabled altogether.
++** The SPILLFLAG_ROLLBACK case is done in a very obscure case that
++** comes up during savepoint rollback that requires the pcache module
++** to allocate a new page to prevent the journal file from being written
++** while it is being traversed by code in pager_playback(). The SPILLFLAG_OFF
++** case is a user preference.
++**
++** If the SPILLFLAG_NOSYNC bit is set, writing to the database from pagerStress()
++** is permitted, but syncing the journal file is not. This flag is set
++** by sqlite3PagerWrite() when the file-system sector-size is larger than
++** the database page-size in order to prevent a journal sync from happening
++** in between the journalling of two pages on the same sector.
+ **
+-** If the pager has already entered the ERROR state, do not attempt
+-** the rollback at this time. Instead, pager_unlock() is called. The
+-** call to pager_unlock() will discard all in-memory pages, unlock
+-** the database file and move the pager back to OPEN state. If this
+-** means that there is a hot-journal left in the file-system, the next
+-** connection to obtain a shared lock on the pager (which may be this one)
+-** will roll it back.
++** subjInMemory
+ **
+-** If the pager has not already entered the ERROR state, but an IO or
+-** malloc error occurs during a rollback, then this will itself cause
+-** the pager to enter the ERROR state. Which will be cleared by the
+-** call to pager_unlock(), as described above.
+-*/
+-static void pagerUnlockAndRollback(Pager *pPager){
+- if( pPager->eState!=PAGER_ERROR && pPager->eState!=PAGER_OPEN ){
+- assert( assert_pager_state(pPager) );
+- if( pPager->eState>=PAGER_WRITER_LOCKED ){
+- sqlite3BeginBenignMalloc();
+- sqlite3PagerRollback(pPager);
+- sqlite3EndBenignMalloc();
+- }else if( !pPager->exclusiveMode ){
+- assert( pPager->eState==PAGER_READER );
+- pager_end_transaction(pPager, 0, 0);
+- }
+- }
+- pager_unlock(pPager);
+-}
+-
+-/*
+-** Parameter aData must point to a buffer of pPager->pageSize bytes
+-** of data. Compute and return a checksum based ont the contents of the
+-** page of data and the current value of pPager->cksumInit.
++** This is a boolean variable. If true, then any required sub-journal
++** is opened as an in-memory journal file. If false, then in-memory
++** sub-journals are only used for in-memory pager files.
+ **
+-** This is not a real checksum. It is really just the sum of the
+-** random initial value (pPager->cksumInit) and every 200th byte
+-** of the page data, starting with byte offset (pPager->pageSize%200).
+-** Each byte is interpreted as an 8-bit unsigned integer.
++** This variable is updated by the upper layer each time a new
++** write-transaction is opened.
+ **
+-** Changing the formula used to compute this checksum results in an
+-** incompatible journal file format.
++** dbSize, dbOrigSize, dbFileSize
+ **
+-** If journal corruption occurs due to a power failure, the most likely
+-** scenario is that one end or the other of the record will be changed.
+-** It is much less likely that the two ends of the journal record will be
+-** correct and the middle be corrupt. Thus, this "checksum" scheme,
+-** though fast and simple, catches the mostly likely kind of corruption.
+-*/
+-static u32 pager_cksum(Pager *pPager, const u8 *aData){
+- u32 cksum = pPager->cksumInit; /* Checksum value to return */
+- int i = pPager->pageSize-200; /* Loop counter */
+- while( i>0 ){
+- cksum += aData[i];
+- i -= 200;
+- }
+- return cksum;
+-}
+-
+-/*
+-** Report the current page size and number of reserved bytes back
+-** to the codec.
+-*/
+-#ifdef SQLITE_HAS_CODEC
+-static void pagerReportSize(Pager *pPager){
+- if( pPager->xCodecSizeChng ){
+- pPager->xCodecSizeChng(pPager->pCodec, pPager->pageSize,
+- (int)pPager->nReserve);
+- }
+-}
+-#else
+-# define pagerReportSize(X) /* No-op if we do not support a codec */
+-#endif
+-
+-/*
+-** Read a single page from either the journal file (if isMainJrnl==1) or
+-** from the sub-journal (if isMainJrnl==0) and playback that page.
+-** The page begins at offset *pOffset into the file. The *pOffset
+-** value is increased to the start of the next page in the journal.
++** Variable dbSize is set to the number of pages in the database file.
++** It is valid in PAGER_READER and higher states (all states except for
++** OPEN and ERROR).
+ **
+-** The main rollback journal uses checksums - the statement journal does
+-** not.
++** dbSize is set based on the size of the database file, which may be
++** larger than the size of the database (the value stored at offset
++** 28 of the database header by the btree). If the size of the file
++** is not an integer multiple of the page-size, the value stored in
++** dbSize is rounded down (i.e. a 5KB file with 2K page-size has dbSize==2).
++** Except, any file that is greater than 0 bytes in size is considered
++** to have at least one page. (i.e. a 1KB file with 2K page-size leads
++** to dbSize==1).
+ **
+-** If the page number of the page record read from the (sub-)journal file
+-** is greater than the current value of Pager.dbSize, then playback is
+-** skipped and SQLITE_OK is returned.
++** During a write-transaction, if pages with page-numbers greater than
++** dbSize are modified in the cache, dbSize is updated accordingly.
++** Similarly, if the database is truncated using PagerTruncateImage(),
++** dbSize is updated.
+ **
+-** If pDone is not NULL, then it is a record of pages that have already
+-** been played back. If the page at *pOffset has already been played back
+-** (if the corresponding pDone bit is set) then skip the playback.
+-** Make sure the pDone bit corresponding to the *pOffset page is set
+-** prior to returning.
++** Variables dbOrigSize and dbFileSize are valid in states
++** PAGER_WRITER_LOCKED and higher. dbOrigSize is a copy of the dbSize
++** variable at the start of the transaction. It is used during rollback,
++** and to determine whether or not pages need to be journalled before
++** being modified.
+ **
+-** If the page record is successfully read from the (sub-)journal file
+-** and played back, then SQLITE_OK is returned. If an IO error occurs
+-** while reading the record from the (sub-)journal file or while writing
+-** to the database file, then the IO error code is returned. If data
+-** is successfully read from the (sub-)journal file but appears to be
+-** corrupted, SQLITE_DONE is returned. Data is considered corrupted in
+-** two circumstances:
+-**
+-** * If the record page-number is illegal (0 or PAGER_MJ_PGNO), or
+-** * If the record is being rolled back from the main journal file
+-** and the checksum field does not match the record content.
++** Throughout a write-transaction, dbFileSize contains the size of
++** the file on disk in pages. It is set to a copy of dbSize when the
++** write-transaction is first opened, and updated when VFS calls are made
++** to write or truncate the database file on disk.
+ **
+-** Neither of these two scenarios are possible during a savepoint rollback.
++** The only reason the dbFileSize variable is required is to suppress
++** unnecessary calls to xTruncate() after committing a transaction. If,
++** when a transaction is committed, the dbFileSize variable indicates
++** that the database file is larger than the database image (Pager.dbSize),
++** pager_truncate() is called. The pager_truncate() call uses xFilesize()
++** to measure the database file on disk, and then truncates it if required.
++** dbFileSize is not used when rolling back a transaction. In this case
++** pager_truncate() is called unconditionally (which means there may be
++** a call to xFilesize() that is not strictly required). In either case,
++** pager_truncate() may cause the file to become smaller or larger.
+ **
+-** If this is a savepoint rollback, then memory may have to be dynamically
+-** allocated by this function. If this is the case and an allocation fails,
+-** SQLITE_NOMEM is returned.
++** dbHintSize
++**
++** The dbHintSize variable is used to limit the number of calls made to
++** the VFS xFileControl(FCNTL_SIZE_HINT) method.
++**
++** dbHintSize is set to a copy of the dbSize variable when a
++** write-transaction is opened (at the same time as dbFileSize and
++** dbOrigSize). If the xFileControl(FCNTL_SIZE_HINT) method is called,
++** dbHintSize is increased to the number of pages that correspond to the
++** size-hint passed to the method call. See pager_write_pagelist() for
++** details.
++**
++** errCode
++**
++** The Pager.errCode variable is only ever used in PAGER_ERROR state. It
++** is set to zero in all other states. In PAGER_ERROR state, Pager.errCode
++** is always set to SQLITE_FULL, SQLITE_IOERR or one of the SQLITE_IOERR_XXX
++** sub-codes.
+ */
+-static int pager_playback_one_page(
+- Pager *pPager, /* The pager being played back */
+- i64 *pOffset, /* Offset of record to playback */
+- Bitvec *pDone, /* Bitvec of pages already played back */
+- int isMainJrnl, /* 1 -> main journal. 0 -> sub-journal. */
+- int isSavepnt /* True for a savepoint rollback */
+-){
+- int rc;
+- PgHdr *pPg; /* An existing page in the cache */
+- Pgno pgno; /* The page number of a page in journal */
+- u32 cksum; /* Checksum used for sanity checking */
+- char *aData; /* Temporary storage for the page */
+- sqlite3_file *jfd; /* The file descriptor for the journal file */
+- int isSynced; /* True if journal page is synced */
++struct Pager {
++ sqlite3_vfs *pVfs; /* OS functions to use for IO */
++ u8 exclusiveMode; /* Boolean. True if locking_mode==EXCLUSIVE */
++ u8 journalMode; /* One of the PAGER_JOURNALMODE_* values */
++ u8 useJournal; /* Use a rollback journal on this file */
++ u8 noSync; /* Do not sync the journal if true */
++ u8 fullSync; /* Do extra syncs of the journal for robustness */
++ u8 ckptSyncFlags; /* SYNC_NORMAL or SYNC_FULL for checkpoint */
++ u8 walSyncFlags; /* SYNC_NORMAL or SYNC_FULL for wal writes */
++ u8 syncFlags; /* SYNC_NORMAL or SYNC_FULL otherwise */
++ u8 tempFile; /* zFilename is a temporary or immutable file */
++ u8 noLock; /* Do not lock (except in WAL mode) */
++ u8 readOnly; /* True for a read-only database */
++ u8 memDb; /* True to inhibit all file I/O */
+
+- assert( (isMainJrnl&~1)==0 ); /* isMainJrnl is 0 or 1 */
+- assert( (isSavepnt&~1)==0 ); /* isSavepnt is 0 or 1 */
+- assert( isMainJrnl || pDone ); /* pDone always used on sub-journals */
+- assert( isSavepnt || pDone==0 ); /* pDone never used on non-savepoint */
++ /**************************************************************************
++ ** The following block contains those class members that change during
++ ** routine operation. Class members not in this block are either fixed
++ ** when the pager is first created or else only change when there is a
++ ** significant mode change (such as changing the page_size, locking_mode,
++ ** or the journal_mode). From another view, these class members describe
++ ** the "state" of the pager, while other class members describe the
++ ** "configuration" of the pager.
++ */
++ u8 eState; /* Pager state (OPEN, READER, WRITER_LOCKED..) */
++ u8 eLock; /* Current lock held on database file */
++ u8 changeCountDone; /* Set after incrementing the change-counter */
++ u8 setMaster; /* True if a m-j name has been written to jrnl */
++ u8 doNotSpill; /* Do not spill the cache when non-zero */
++ u8 subjInMemory; /* True to use in-memory sub-journals */
++ u8 bUseFetch; /* True to use xFetch() */
++ u8 hasBeenUsed; /* True if any content previously read from this pager*/
++ Pgno dbSize; /* Number of pages in the database */
++ Pgno dbOrigSize; /* dbSize before the current transaction */
++ Pgno dbFileSize; /* Number of pages in the database file */
++ Pgno dbHintSize; /* Value passed to FCNTL_SIZE_HINT call */
++ int errCode; /* One of several kinds of errors */
++ int nRec; /* Pages journalled since last j-header written */
++ u32 cksumInit; /* Quasi-random value added to every checksum */
++ u32 nSubRec; /* Number of records written to sub-journal */
++ Bitvec *pInJournal; /* One bit for each page in the database file */
++ sqlite3_file *fd; /* File descriptor for database */
++ sqlite3_file *jfd; /* File descriptor for main journal */
++ sqlite3_file *sjfd; /* File descriptor for sub-journal */
++ i64 journalOff; /* Current write offset in the journal file */
++ i64 journalHdr; /* Byte offset to previous journal header */
++ sqlite3_backup *pBackup; /* Pointer to list of ongoing backup processes */
++ PagerSavepoint *aSavepoint; /* Array of active savepoints */
++ int nSavepoint; /* Number of elements in aSavepoint[] */
++ u32 iDataVersion; /* Changes whenever database content changes */
++ char dbFileVers[16]; /* Changes whenever database file changes */
+
+- aData = pPager->pTmpSpace;
+- assert( aData ); /* Temp storage must have already been allocated */
+- assert( pagerUseWal(pPager)==0 || (!isMainJrnl && isSavepnt) );
++ int nMmapOut; /* Number of mmap pages currently outstanding */
++ sqlite3_int64 szMmap; /* Desired maximum mmap size */
++ PgHdr *pMmapFreelist; /* List of free mmap page headers (pDirty) */
++ /*
++ ** End of the routinely-changing class members
++ ***************************************************************************/
+
+- /* Either the state is greater than PAGER_WRITER_CACHEMOD (a transaction
+- ** or savepoint rollback done at the request of the caller) or this is
+- ** a hot-journal rollback. If it is a hot-journal rollback, the pager
+- ** is in state OPEN and holds an EXCLUSIVE lock. Hot-journal rollback
+- ** only reads from the main journal, not the sub-journal.
+- */
+- assert( pPager->eState>=PAGER_WRITER_CACHEMOD
+- || (pPager->eState==PAGER_OPEN && pPager->eLock==EXCLUSIVE_LOCK)
+- );
+- assert( pPager->eState>=PAGER_WRITER_CACHEMOD || isMainJrnl );
++ u16 nExtra; /* Add this many bytes to each in-memory page */
++ i16 nReserve; /* Number of unused bytes at end of each page */
++ u32 vfsFlags; /* Flags for sqlite3_vfs.xOpen() */
++ u32 sectorSize; /* Assumed sector size during rollback */
++ int pageSize; /* Number of bytes in a page */
++ Pgno mxPgno; /* Maximum allowed size of the database */
++ i64 journalSizeLimit; /* Size limit for persistent journal files */
++ char *zFilename; /* Name of the database file */
++ char *zJournal; /* Name of the journal file */
++ int (*xBusyHandler)(void*); /* Function to call when busy */
++ void *pBusyHandlerArg; /* Context argument for xBusyHandler */
++ int aStat[3]; /* Total cache hits, misses and writes */
++#ifdef SQLITE_TEST
++ int nRead; /* Database pages read */
++#endif
++ void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */
++#ifdef SQLITE_HAS_CODEC
++ void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */
++ void (*xCodecSizeChng)(void*,int,int); /* Notify of page size changes */
++ void (*xCodecFree)(void*); /* Destructor for the codec */
++ void *pCodec; /* First argument to xCodec... methods */
++#endif
++ char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */
++ PCache *pPCache; /* Pointer to page cache object */
++#ifndef SQLITE_OMIT_WAL
++ Wal *pWal; /* Write-ahead log used by "journal_mode=wal" */
++ char *zWal; /* File name for write-ahead log */
++#endif
++};
+
+- /* Read the page number and page data from the journal or sub-journal
+- ** file. Return an error code to the caller if an IO error occurs.
+- */
+- jfd = isMainJrnl ? pPager->jfd : pPager->sjfd;
+- rc = read32bits(jfd, *pOffset, &pgno);
+- if( rc!=SQLITE_OK ) return rc;
+- rc = sqlite3OsRead(jfd, (u8*)aData, pPager->pageSize, (*pOffset)+4);
+- if( rc!=SQLITE_OK ) return rc;
+- *pOffset += pPager->pageSize + 4 + isMainJrnl*4;
++/*
++** Indexes for use with Pager.aStat[]. The Pager.aStat[] array contains
++** the values accessed by passing SQLITE_DBSTATUS_CACHE_HIT, CACHE_MISS
++** or CACHE_WRITE to sqlite3_db_status().
++*/
++#define PAGER_STAT_HIT 0
++#define PAGER_STAT_MISS 1
++#define PAGER_STAT_WRITE 2
+
+- /* Sanity checking on the page. This is more important that I originally
+- ** thought. If a power failure occurs while the journal is being written,
+- ** it could cause invalid data to be written into the journal. We need to
+- ** detect this invalid data (with high probability) and ignore it.
+- */
+- if( pgno==0 || pgno==PAGER_MJ_PGNO(pPager) ){
+- assert( !isSavepnt );
+- return SQLITE_DONE;
+- }
+- if( pgno>(Pgno)pPager->dbSize || sqlite3BitvecTest(pDone, pgno) ){
+- return SQLITE_OK;
+- }
+- if( isMainJrnl ){
+- rc = read32bits(jfd, (*pOffset)-4, &cksum);
+- if( rc ) return rc;
+- if( !isSavepnt && pager_cksum(pPager, (u8*)aData)!=cksum ){
+- return SQLITE_DONE;
+- }
+- }
++/*
++** The following global variables hold counters used for
++** testing purposes only. These variables do not exist in
++** a non-testing build. These variables are not thread-safe.
++*/
++#ifdef SQLITE_TEST
++SQLITE_API int sqlite3_pager_readdb_count = 0; /* Number of full pages read from DB */
++SQLITE_API int sqlite3_pager_writedb_count = 0; /* Number of full pages written to DB */
++SQLITE_API int sqlite3_pager_writej_count = 0; /* Number of pages written to journal */
++# define PAGER_INCR(v) v++
++#else
++# define PAGER_INCR(v)
++#endif
+
+- /* If this page has already been played by before during the current
+- ** rollback, then don't bother to play it back again.
+- */
+- if( pDone && (rc = sqlite3BitvecSet(pDone, pgno))!=SQLITE_OK ){
+- return rc;
+- }
+
+- /* When playing back page 1, restore the nReserve setting
+- */
+- if( pgno==1 && pPager->nReserve!=((u8*)aData)[20] ){
+- pPager->nReserve = ((u8*)aData)[20];
+- pagerReportSize(pPager);
+- }
+
+- /* If the pager is in CACHEMOD state, then there must be a copy of this
+- ** page in the pager cache. In this case just update the pager cache,
+- ** not the database file. The page is left marked dirty in this case.
+- **
+- ** An exception to the above rule: If the database is in no-sync mode
+- ** and a page is moved during an incremental vacuum then the page may
+- ** not be in the pager cache. Later: if a malloc() or IO error occurs
+- ** during a Movepage() call, then the page may not be in the cache
+- ** either. So the condition described in the above paragraph is not
+- ** assert()able.
+- **
+- ** If in WRITER_DBMOD, WRITER_FINISHED or OPEN state, then we update the
+- ** pager cache if it exists and the main file. The page is then marked
+- ** not dirty. Since this code is only executed in PAGER_OPEN state for
+- ** a hot-journal rollback, it is guaranteed that the page-cache is empty
+- ** if the pager is in OPEN state.
+- **
+- ** Ticket #1171: The statement journal might contain page content that is
+- ** different from the page content at the start of the transaction.
+- ** This occurs when a page is changed prior to the start of a statement
+- ** then changed again within the statement. When rolling back such a
+- ** statement we must not write to the original database unless we know
+- ** for certain that original page contents are synced into the main rollback
+- ** journal. Otherwise, a power loss might leave modified data in the
+- ** database file without an entry in the rollback journal that can
+- ** restore the database to its original form. Two conditions must be
+- ** met before writing to the database files. (1) the database must be
+- ** locked. (2) we know that the original page content is fully synced
+- ** in the main journal either because the page is not in cache or else
+- ** the page is marked as needSync==0.
+- **
+- ** 2008-04-14: When attempting to vacuum a corrupt database file, it
+- ** is possible to fail a statement on a database that does not yet exist.
+- ** Do not attempt to write if database file has never been opened.
+- */
+- if( pagerUseWal(pPager) ){
+- pPg = 0;
+- }else{
+- pPg = sqlite3PagerLookup(pPager, pgno);
+- }
+- assert( pPg || !MEMDB );
+- assert( pPager->eState!=PAGER_OPEN || pPg==0 );
+- PAGERTRACE(("PLAYBACK %d page %d hash(%08x) %s\n",
+- PAGERID(pPager), pgno, pager_datahash(pPager->pageSize, (u8*)aData),
+- (isMainJrnl?"main-journal":"sub-journal")
+- ));
+- if( isMainJrnl ){
+- isSynced = pPager->noSync || (*pOffset <= pPager->journalHdr);
+- }else{
+- isSynced = (pPg==0 || 0==(pPg->flags & PGHDR_NEED_SYNC));
+- }
+- if( isOpen(pPager->fd)
+- && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN)
+- && isSynced
+- ){
+- i64 ofst = (pgno-1)*(i64)pPager->pageSize;
+- testcase( !isSavepnt && pPg!=0 && (pPg->flags&PGHDR_NEED_SYNC)!=0 );
+- assert( !pagerUseWal(pPager) );
+- rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst);
+- if( pgno>pPager->dbFileSize ){
+- pPager->dbFileSize = pgno;
+- }
+- if( pPager->pBackup ){
+- CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM);
+- sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData);
+- CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM, aData);
+- }
+- }else if( !isMainJrnl && pPg==0 ){
+- /* If this is a rollback of a savepoint and data was not written to
+- ** the database and the page is not in-memory, there is a potential
+- ** problem. When the page is next fetched by the b-tree layer, it
+- ** will be read from the database file, which may or may not be
+- ** current.
+- **
+- ** There are a couple of different ways this can happen. All are quite
+- ** obscure. When running in synchronous mode, this can only happen
+- ** if the page is on the free-list at the start of the transaction, then
+- ** populated, then moved using sqlite3PagerMovepage().
+- **
+- ** The solution is to add an in-memory page to the cache containing
+- ** the data just read from the sub-journal. Mark the page as dirty
+- ** and if the pager requires a journal-sync, then mark the page as
+- ** requiring a journal-sync before it is written.
+- */
+- assert( isSavepnt );
+- assert( (pPager->doNotSpill & SPILLFLAG_ROLLBACK)==0 );
+- pPager->doNotSpill |= SPILLFLAG_ROLLBACK;
+- rc = sqlite3PagerAcquire(pPager, pgno, &pPg, 1);
+- assert( (pPager->doNotSpill & SPILLFLAG_ROLLBACK)!=0 );
+- pPager->doNotSpill &= ~SPILLFLAG_ROLLBACK;
+- if( rc!=SQLITE_OK ) return rc;
+- pPg->flags &= ~PGHDR_NEED_READ;
+- sqlite3PcacheMakeDirty(pPg);
+- }
+- if( pPg ){
+- /* No page should ever be explicitly rolled back that is in use, except
+- ** for page 1 which is held in use in order to keep the lock on the
+- ** database active. However such a page may be rolled back as a result
+- ** of an internal error resulting in an automatic call to
+- ** sqlite3PagerRollback().
+- */
+- void *pData;
+- pData = pPg->pData;
+- memcpy(pData, (u8*)aData, pPager->pageSize);
+- pPager->xReiniter(pPg);
+- if( isMainJrnl && (!isSavepnt || *pOffset<=pPager->journalHdr) ){
+- /* If the contents of this page were just restored from the main
+- ** journal file, then its content must be as they were when the
+- ** transaction was first opened. In this case we can mark the page
+- ** as clean, since there will be no need to write it out to the
+- ** database.
+- **
+- ** There is one exception to this rule. If the page is being rolled
+- ** back as part of a savepoint (or statement) rollback from an
+- ** unsynced portion of the main journal file, then it is not safe
+- ** to mark the page as clean. This is because marking the page as
+- ** clean will clear the PGHDR_NEED_SYNC flag. Since the page is
+- ** already in the journal file (recorded in Pager.pInJournal) and
+- ** the PGHDR_NEED_SYNC flag is cleared, if the page is written to
+- ** again within this transaction, it will be marked as dirty but
+- ** the PGHDR_NEED_SYNC flag will not be set. It could then potentially
+- ** be written out into the database file before its journal file
+- ** segment is synced. If a crash occurs during or following this,
+- ** database corruption may ensue.
+- */
+- assert( !pagerUseWal(pPager) );
+- sqlite3PcacheMakeClean(pPg);
+- }
+- pager_set_pagehash(pPg);
++/*
++** Journal files begin with the following magic string. The data
++** was obtained from /dev/random. It is used only as a sanity check.
++**
++** Since version 2.8.0, the journal format contains additional sanity
++** checking information. If the power fails while the journal is being
++** written, semi-random garbage data might appear in the journal
++** file after power is restored. If an attempt is then made
++** to roll the journal back, the database could be corrupted. The additional
++** sanity checking data is an attempt to discover the garbage in the
++** journal and ignore it.
++**
++** The sanity checking information for the new journal format consists
++** of a 32-bit checksum on each page of data. The checksum covers both
++** the page number and the pPager->pageSize bytes of data for the page.
++** This cksum is initialized to a 32-bit random value that appears in the
++** journal file right after the header. The random initializer is important,
++** because garbage data that appears at the end of a journal is likely
++** data that was once in other files that have now been deleted. If the
++** garbage data came from an obsolete journal file, the checksums might
++** be correct. But by initializing the checksum to random value which
++** is different for every journal, we minimize that risk.
++*/
++static const unsigned char aJournalMagic[] = {
++ 0xd9, 0xd5, 0x05, 0xf9, 0x20, 0xa1, 0x63, 0xd7,
++};
++
++/*
++** The size of the of each page record in the journal is given by
++** the following macro.
++*/
++#define JOURNAL_PG_SZ(pPager) ((pPager->pageSize) + 8)
++
++/*
++** The journal header size for this pager. This is usually the same
++** size as a single disk sector. See also setSectorSize().
++*/
++#define JOURNAL_HDR_SZ(pPager) (pPager->sectorSize)
++
++/*
++** The macro MEMDB is true if we are dealing with an in-memory database.
++** We do this as a macro so that if the SQLITE_OMIT_MEMORYDB macro is set,
++** the value of MEMDB will be a constant and the compiler will optimize
++** out code that would never execute.
++*/
++#ifdef SQLITE_OMIT_MEMORYDB
++# define MEMDB 0
++#else
++# define MEMDB pPager->memDb
++#endif
+
+- /* If this was page 1, then restore the value of Pager.dbFileVers.
+- ** Do this before any decoding. */
+- if( pgno==1 ){
+- memcpy(&pPager->dbFileVers, &((u8*)pData)[24],sizeof(pPager->dbFileVers));
+- }
++/*
++** The macro USEFETCH is true if we are allowed to use the xFetch and xUnfetch
++** interfaces to access the database using memory-mapped I/O.
++*/
++#if SQLITE_MAX_MMAP_SIZE>0
++# define USEFETCH(x) ((x)->bUseFetch)
++#else
++# define USEFETCH(x) 0
++#endif
+
+- /* Decode the page just read from disk */
+- CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM);
+- sqlite3PcacheRelease(pPg);
+- }
+- return rc;
+-}
++/*
++** The maximum legal page number is (2^31 - 1).
++*/
++#define PAGER_MAX_PGNO 2147483647
+
+ /*
+-** Parameter zMaster is the name of a master journal file. A single journal
+-** file that referred to the master journal file has just been rolled back.
+-** This routine checks if it is possible to delete the master journal file,
+-** and does so if it is.
+-**
+-** Argument zMaster may point to Pager.pTmpSpace. So that buffer is not
+-** available for use within this function.
+-**
+-** When a master journal file is created, it is populated with the names
+-** of all of its child journals, one after another, formatted as utf-8
+-** encoded text. The end of each child journal file is marked with a
+-** nul-terminator byte (0x00). i.e. the entire contents of a master journal
+-** file for a transaction involving two databases might be:
+-**
+-** "/home/bill/a.db-journal\x00/home/bill/b.db-journal\x00"
++** The argument to this macro is a file descriptor (type sqlite3_file*).
++** Return 0 if it is not open, or non-zero (but not 1) if it is.
+ **
+-** A master journal file may only be deleted once all of its child
+-** journals have been rolled back.
++** This is so that expressions can be written as:
+ **
+-** This function reads the contents of the master-journal file into
+-** memory and loops through each of the child journal names. For
+-** each child journal, it checks if:
++** if( isOpen(pPager->jfd) ){ ...
+ **
+-** * if the child journal exists, and if so
+-** * if the child journal contains a reference to master journal
+-** file zMaster
++** instead of
+ **
+-** If a child journal can be found that matches both of the criteria
+-** above, this function returns without doing anything. Otherwise, if
+-** no such child journal can be found, file zMaster is deleted from
+-** the file-system using sqlite3OsDelete().
++** if( pPager->jfd->pMethods ){ ...
++*/
++#define isOpen(pFd) ((pFd)->pMethods)
++
++/*
++** Return true if this pager uses a write-ahead log instead of the usual
++** rollback journal. Otherwise false.
++*/
++#ifndef SQLITE_OMIT_WAL
++static int pagerUseWal(Pager *pPager){
++ return (pPager->pWal!=0);
++}
++#else
++# define pagerUseWal(x) 0
++# define pagerRollbackWal(x) 0
++# define pagerWalFrames(v,w,x,y) 0
++# define pagerOpenWalIfPresent(z) SQLITE_OK
++# define pagerBeginReadTransaction(z) SQLITE_OK
++#endif
++
++#ifndef NDEBUG
++/*
++** Usage:
+ **
+-** If an IO error within this function, an error code is returned. This
+-** function allocates memory by calling sqlite3Malloc(). If an allocation
+-** fails, SQLITE_NOMEM is returned. Otherwise, if no IO or malloc errors
+-** occur, SQLITE_OK is returned.
++** assert( assert_pager_state(pPager) );
+ **
+-** TODO: This function allocates a single block of memory to load
+-** the entire contents of the master journal file. This could be
+-** a couple of kilobytes or so - potentially larger than the page
+-** size.
++** This function runs many asserts to try to find inconsistencies in
++** the internal state of the Pager object.
+ */
+-static int pager_delmaster(Pager *pPager, const char *zMaster){
+- sqlite3_vfs *pVfs = pPager->pVfs;
+- int rc; /* Return code */
+- sqlite3_file *pMaster; /* Malloc'd master-journal file descriptor */
+- sqlite3_file *pJournal; /* Malloc'd child-journal file descriptor */
+- char *zMasterJournal = 0; /* Contents of master journal file */
+- i64 nMasterJournal; /* Size of master journal file */
+- char *zJournal; /* Pointer to one journal within MJ file */
+- char *zMasterPtr; /* Space to hold MJ filename from a journal file */
+- int nMasterPtr; /* Amount of space allocated to zMasterPtr[] */
++static int assert_pager_state(Pager *p){
++ Pager *pPager = p;
+
+- /* Allocate space for both the pJournal and pMaster file descriptors.
+- ** If successful, open the master journal file for reading.
++ /* State must be valid. */
++ assert( p->eState==PAGER_OPEN
++ || p->eState==PAGER_READER
++ || p->eState==PAGER_WRITER_LOCKED
++ || p->eState==PAGER_WRITER_CACHEMOD
++ || p->eState==PAGER_WRITER_DBMOD
++ || p->eState==PAGER_WRITER_FINISHED
++ || p->eState==PAGER_ERROR
++ );
++
++ /* Regardless of the current state, a temp-file connection always behaves
++ ** as if it has an exclusive lock on the database file. It never updates
++ ** the change-counter field, so the changeCountDone flag is always set.
+ */
+- pMaster = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2);
+- pJournal = (sqlite3_file *)(((u8 *)pMaster) + pVfs->szOsFile);
+- if( !pMaster ){
+- rc = SQLITE_NOMEM;
+- }else{
+- const int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MASTER_JOURNAL);
+- rc = sqlite3OsOpen(pVfs, zMaster, pMaster, flags, 0);
+- }
+- if( rc!=SQLITE_OK ) goto delmaster_out;
++ assert( p->tempFile==0 || p->eLock==EXCLUSIVE_LOCK );
++ assert( p->tempFile==0 || pPager->changeCountDone );
+
+- /* Load the entire master journal file into space obtained from
+- ** sqlite3_malloc() and pointed to by zMasterJournal. Also obtain
+- ** sufficient space (in zMasterPtr) to hold the names of master
+- ** journal files extracted from regular rollback-journals.
++ /* If the useJournal flag is clear, the journal-mode must be "OFF".
++ ** And if the journal-mode is "OFF", the journal file must not be open.
+ */
+- rc = sqlite3OsFileSize(pMaster, &nMasterJournal);
+- if( rc!=SQLITE_OK ) goto delmaster_out;
+- nMasterPtr = pVfs->mxPathname+1;
+- zMasterJournal = sqlite3Malloc(nMasterJournal + nMasterPtr + 1);
+- if( !zMasterJournal ){
+- rc = SQLITE_NOMEM;
+- goto delmaster_out;
++ assert( p->journalMode==PAGER_JOURNALMODE_OFF || p->useJournal );
++ assert( p->journalMode!=PAGER_JOURNALMODE_OFF || !isOpen(p->jfd) );
++
++ /* Check that MEMDB implies noSync. And an in-memory journal. Since
++ ** this means an in-memory pager performs no IO at all, it cannot encounter
++ ** either SQLITE_IOERR or SQLITE_FULL during rollback or while finalizing
++ ** a journal file. (although the in-memory journal implementation may
++ ** return SQLITE_IOERR_NOMEM while the journal file is being written). It
++ ** is therefore not possible for an in-memory pager to enter the ERROR
++ ** state.
++ */
++ if( MEMDB ){
++ assert( p->noSync );
++ assert( p->journalMode==PAGER_JOURNALMODE_OFF
++ || p->journalMode==PAGER_JOURNALMODE_MEMORY
++ );
++ assert( p->eState!=PAGER_ERROR && p->eState!=PAGER_OPEN );
++ assert( pagerUseWal(p)==0 );
+ }
+- zMasterPtr = &zMasterJournal[nMasterJournal+1];
+- rc = sqlite3OsRead(pMaster, zMasterJournal, (int)nMasterJournal, 0);
+- if( rc!=SQLITE_OK ) goto delmaster_out;
+- zMasterJournal[nMasterJournal] = 0;
+
+- zJournal = zMasterJournal;
+- while( (zJournal-zMasterJournal)<nMasterJournal ){
+- int exists;
+- rc = sqlite3OsAccess(pVfs, zJournal, SQLITE_ACCESS_EXISTS, &exists);
+- if( rc!=SQLITE_OK ){
+- goto delmaster_out;
+- }
+- if( exists ){
+- /* 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.
+- */
+- int c;
+- int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL);
+- rc = sqlite3OsOpen(pVfs, zJournal, pJournal, flags, 0);
+- if( rc!=SQLITE_OK ){
+- goto delmaster_out;
+- }
++ /* If changeCountDone is set, a RESERVED lock or greater must be held
++ ** on the file.
++ */
++ assert( pPager->changeCountDone==0 || pPager->eLock>=RESERVED_LOCK );
++ assert( p->eLock!=PENDING_LOCK );
+
+- rc = readMasterJournal(pJournal, zMasterPtr, nMasterPtr);
+- sqlite3OsClose(pJournal);
+- if( rc!=SQLITE_OK ){
+- goto delmaster_out;
++ switch( p->eState ){
++ case PAGER_OPEN:
++ assert( !MEMDB );
++ assert( pPager->errCode==SQLITE_OK );
++ assert( sqlite3PcacheRefCount(pPager->pPCache)==0 || pPager->tempFile );
++ break;
++
++ case PAGER_READER:
++ assert( pPager->errCode==SQLITE_OK );
++ assert( p->eLock!=UNKNOWN_LOCK );
++ assert( p->eLock>=SHARED_LOCK );
++ break;
++
++ case PAGER_WRITER_LOCKED:
++ assert( p->eLock!=UNKNOWN_LOCK );
++ assert( pPager->errCode==SQLITE_OK );
++ if( !pagerUseWal(pPager) ){
++ assert( p->eLock>=RESERVED_LOCK );
+ }
++ assert( pPager->dbSize==pPager->dbOrigSize );
++ assert( pPager->dbOrigSize==pPager->dbFileSize );
++ assert( pPager->dbOrigSize==pPager->dbHintSize );
++ assert( pPager->setMaster==0 );
++ break;
+
+- c = zMasterPtr[0]!=0 && strcmp(zMasterPtr, zMaster)==0;
+- if( c ){
+- /* We have a match. Do not delete the master journal file. */
+- goto delmaster_out;
++ case PAGER_WRITER_CACHEMOD:
++ assert( p->eLock!=UNKNOWN_LOCK );
++ assert( pPager->errCode==SQLITE_OK );
++ if( !pagerUseWal(pPager) ){
++ /* It is possible that if journal_mode=wal here that neither the
++ ** journal file nor the WAL file are open. This happens during
++ ** a rollback transaction that switches from journal_mode=off
++ ** to journal_mode=wal.
++ */
++ assert( p->eLock>=RESERVED_LOCK );
++ assert( isOpen(p->jfd)
++ || p->journalMode==PAGER_JOURNALMODE_OFF
++ || p->journalMode==PAGER_JOURNALMODE_WAL
++ );
+ }
++ assert( pPager->dbOrigSize==pPager->dbFileSize );
++ assert( pPager->dbOrigSize==pPager->dbHintSize );
++ break;
++
++ case PAGER_WRITER_DBMOD:
++ assert( p->eLock==EXCLUSIVE_LOCK );
++ assert( pPager->errCode==SQLITE_OK );
++ assert( !pagerUseWal(pPager) );
++ assert( p->eLock>=EXCLUSIVE_LOCK );
++ assert( isOpen(p->jfd)
++ || p->journalMode==PAGER_JOURNALMODE_OFF
++ || p->journalMode==PAGER_JOURNALMODE_WAL
++ );
++ assert( pPager->dbOrigSize<=pPager->dbHintSize );
++ break;
++
++ case PAGER_WRITER_FINISHED:
++ assert( p->eLock==EXCLUSIVE_LOCK );
++ assert( pPager->errCode==SQLITE_OK );
++ assert( !pagerUseWal(pPager) );
++ assert( isOpen(p->jfd)
++ || p->journalMode==PAGER_JOURNALMODE_OFF
++ || p->journalMode==PAGER_JOURNALMODE_WAL
++ );
++ break;
++
++ case PAGER_ERROR:
++ /* There must be at least one outstanding reference to the pager if
++ ** in ERROR state. Otherwise the pager should have already dropped
++ ** back to OPEN state.
++ */
++ assert( pPager->errCode!=SQLITE_OK );
++ assert( sqlite3PcacheRefCount(pPager->pPCache)>0 );
++ break;
++ }
++
++ return 1;
+}
++#endif /* ifndef NDEBUG */
+
-+SQLITE_PRIVATE int sqlite3pager_is_mj_pgno(Pager *pPager, Pgno pgno) {
-+ return (PAGER_MJ_PGNO(pPager) == pgno) ? 1 : 0;
++#ifdef SQLITE_DEBUG
++/*
++** Return a pointer to a human readable string in a static buffer
++** containing the state of the Pager object passed as an argument. This
++** is intended to be used within debuggers. For example, as an alternative
++** to "print *pPager" in gdb:
++**
++** (gdb) printf "%s", print_pager_state(pPager)
++*/
++static char *print_pager_state(Pager *p){
++ static char zRet[1024];
++
++ sqlite3_snprintf(1024, zRet,
++ "Filename: %s\n"
++ "State: %s errCode=%d\n"
++ "Lock: %s\n"
++ "Locking mode: locking_mode=%s\n"
++ "Journal mode: journal_mode=%s\n"
++ "Backing store: tempFile=%d memDb=%d useJournal=%d\n"
++ "Journal: journalOff=%lld journalHdr=%lld\n"
++ "Size: dbsize=%d dbOrigSize=%d dbFileSize=%d\n"
++ , p->zFilename
++ , p->eState==PAGER_OPEN ? "OPEN" :
++ p->eState==PAGER_READER ? "READER" :
++ p->eState==PAGER_WRITER_LOCKED ? "WRITER_LOCKED" :
++ p->eState==PAGER_WRITER_CACHEMOD ? "WRITER_CACHEMOD" :
++ p->eState==PAGER_WRITER_DBMOD ? "WRITER_DBMOD" :
++ p->eState==PAGER_WRITER_FINISHED ? "WRITER_FINISHED" :
++ p->eState==PAGER_ERROR ? "ERROR" : "?error?"
++ , (int)p->errCode
++ , p->eLock==NO_LOCK ? "NO_LOCK" :
++ p->eLock==RESERVED_LOCK ? "RESERVED" :
++ p->eLock==EXCLUSIVE_LOCK ? "EXCLUSIVE" :
++ p->eLock==SHARED_LOCK ? "SHARED" :
++ p->eLock==UNKNOWN_LOCK ? "UNKNOWN" : "?error?"
++ , p->exclusiveMode ? "exclusive" : "normal"
++ , p->journalMode==PAGER_JOURNALMODE_MEMORY ? "memory" :
++ p->journalMode==PAGER_JOURNALMODE_OFF ? "off" :
++ p->journalMode==PAGER_JOURNALMODE_DELETE ? "delete" :
++ p->journalMode==PAGER_JOURNALMODE_PERSIST ? "persist" :
++ p->journalMode==PAGER_JOURNALMODE_TRUNCATE ? "truncate" :
++ p->journalMode==PAGER_JOURNALMODE_WAL ? "wal" : "?error?"
++ , (int)p->tempFile, (int)p->memDb, (int)p->useJournal
++ , p->journalOff, p->journalHdr
++ , (int)p->dbSize, (int)p->dbOrigSize, (int)p->dbFileSize
++ );
++
++ return zRet;
+}
++#endif
+
-+SQLITE_PRIVATE sqlite3_file *sqlite3Pager_get_fd(Pager *pPager) {
-+ return (isOpen(pPager->fd)) ? pPager->fd : NULL;
++/*
++** Return true if it is necessary to write page *pPg into the sub-journal.
++** A page needs to be written into the sub-journal if there exists one
++** or more open savepoints for which:
++**
++** * The page-number is less than or equal to PagerSavepoint.nOrig, and
++** * The bit corresponding to the page-number is not set in
++** PagerSavepoint.pInSavepoint.
++*/
++static int subjRequiresPage(PgHdr *pPg){
++ Pager *pPager = pPg->pPager;
++ PagerSavepoint *p;
++ Pgno pgno = pPg->pgno;
++ int i;
++ for(i=0; i<pPager->nSavepoint; i++){
++ p = &pPager->aSavepoint[i];
++ if( p->nOrig>=pgno && 0==sqlite3BitvecTest(p->pInSavepoint, pgno) ){
++ return 1;
+ }
+- zJournal += (sqlite3Strlen30(zJournal)+1);
+ }
+-
+- sqlite3OsClose(pMaster);
+- rc = sqlite3OsDelete(pVfs, zMaster, 0);
++ return 0;
++}
+
+-delmaster_out:
+- sqlite3_free(zMasterJournal);
+- if( pMaster ){
+- sqlite3OsClose(pMaster);
+- assert( !isOpen(pJournal) );
+- sqlite3_free(pMaster);
++/*
++** Return true if the page is already in the journal file.
++*/
++static int pageInJournal(Pager *pPager, PgHdr *pPg){
++ return sqlite3BitvecTest(pPager->pInJournal, pPg->pgno);
+}
+
-+SQLITE_PRIVATE void sqlite3pager_sqlite3PagerSetCodec(
-+ Pager *pPager,
-+ void *(*xCodec)(void*,void*,Pgno,int),
-+ void (*xCodecSizeChng)(void*,int,int),
-+ void (*xCodecFree)(void*),
-+ void *pCodec
++/*
++** Read a 32-bit integer from the given file descriptor. Store the integer
++** that is read in *pRes. Return SQLITE_OK if everything worked, or an
++** error code is something goes wrong.
++**
++** All values are stored on disk as big-endian.
++*/
++static int read32bits(sqlite3_file *fd, i64 offset, u32 *pRes){
++ unsigned char ac[4];
++ int rc = sqlite3OsRead(fd, ac, sizeof(ac), offset);
++ if( rc==SQLITE_OK ){
++ *pRes = sqlite3Get4byte(ac);
++ }
++ return rc;
++}
++
++/*
++** Write a 32-bit integer into a string buffer in big-endian byte order.
++*/
++#define put32bits(A,B) sqlite3Put4byte((u8*)A,B)
++
++
++/*
++** Write a 32-bit integer into the given file descriptor. Return SQLITE_OK
++** on success or an error code is something goes wrong.
++*/
++static int write32bits(sqlite3_file *fd, i64 offset, u32 val){
++ char ac[4];
++ put32bits(ac, val);
++ return sqlite3OsWrite(fd, ac, 4, offset);
++}
++
++/*
++** Unlock the database file to level eLock, which must be either NO_LOCK
++** or SHARED_LOCK. Regardless of whether or not the call to xUnlock()
++** succeeds, set the Pager.eLock variable to match the (attempted) new lock.
++**
++** Except, if Pager.eLock is set to UNKNOWN_LOCK when this function is
++** called, do not modify it. See the comment above the #define of
++** UNKNOWN_LOCK for an explanation of this.
++*/
++static int pagerUnlockDb(Pager *pPager, int eLock){
++ int rc = SQLITE_OK;
++
++ assert( !pPager->exclusiveMode || pPager->eLock==eLock );
++ assert( eLock==NO_LOCK || eLock==SHARED_LOCK );
++ assert( eLock!=NO_LOCK || pagerUseWal(pPager)==0 );
++ if( isOpen(pPager->fd) ){
++ assert( pPager->eLock>=eLock );
++ rc = pPager->noLock ? SQLITE_OK : sqlite3OsUnlock(pPager->fd, eLock);
++ if( pPager->eLock!=UNKNOWN_LOCK ){
++ pPager->eLock = (u8)eLock;
++ }
++ IOTRACE(("UNLOCK %p %d\n", pPager, eLock))
+ }
+ return rc;
+ }
+
++/*
++** Lock the database file to level eLock, which must be either SHARED_LOCK,
++** RESERVED_LOCK or EXCLUSIVE_LOCK. If the caller is successful, set the
++** Pager.eLock variable to the new locking state.
++**
++** Except, if Pager.eLock is set to UNKNOWN_LOCK when this function is
++** called, do not modify it unless the new locking state is EXCLUSIVE_LOCK.
++** See the comment above the #define of UNKNOWN_LOCK for an explanation
++** of this.
++*/
++static int pagerLockDb(Pager *pPager, int eLock){
++ int rc = SQLITE_OK;
++
++ assert( eLock==SHARED_LOCK || eLock==RESERVED_LOCK || eLock==EXCLUSIVE_LOCK );
++ if( pPager->eLock<eLock || pPager->eLock==UNKNOWN_LOCK ){
++ rc = pPager->noLock ? SQLITE_OK : sqlite3OsLock(pPager->fd, eLock);
++ if( rc==SQLITE_OK && (pPager->eLock!=UNKNOWN_LOCK||eLock==EXCLUSIVE_LOCK) ){
++ pPager->eLock = (u8)eLock;
++ IOTRACE(("LOCK %p %d\n", pPager, eLock))
++ }
++ }
++ return rc;
++}
+
+ /*
+-** This function is used to change the actual size of the database
+-** file in the file-system. This only happens when committing a transaction,
+-** or rolling back a transaction (including rolling back a hot-journal).
++** This function determines whether or not the atomic-write optimization
++** can be used with this pager. The optimization can be used if:
+ **
+-** If the main database file is not open, or the pager is not in either
+-** DBMOD or OPEN state, this function is a no-op. Otherwise, the size
+-** of the file is changed to nPage pages (nPage*pPager->pageSize bytes).
+-** If the file on disk is currently larger than nPage pages, then use the VFS
+-** xTruncate() method to truncate it.
++** (a) the value returned by OsDeviceCharacteristics() indicates that
++** a database page may be written atomically, and
++** (b) the value returned by OsSectorSize() is less than or equal
++** to the page size.
+ **
+-** Or, it might be the case that the file on disk is smaller than
+-** nPage pages. Some operating system implementations can get confused if
+-** you try to truncate a file to some size that is larger than it
+-** currently is, so detect this case and write a single zero byte to
+-** the end of the new file instead.
++** The optimization is also always enabled for temporary files. It is
++** an error to call this function if pPager is opened on an in-memory
++** database.
+ **
+-** If successful, return SQLITE_OK. If an IO error occurs while modifying
+-** the database file, return the error code to the caller.
++** If the optimization cannot be used, 0 is returned. If it can be used,
++** then the value returned is the size of the journal file when it
++** contains rollback data for exactly one page.
+ */
+-static int pager_truncate(Pager *pPager, Pgno nPage){
+- int rc = SQLITE_OK;
+- assert( pPager->eState!=PAGER_ERROR );
+- assert( pPager->eState!=PAGER_READER );
+-
+- if( isOpen(pPager->fd)
+- && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN)
+- ){
+- i64 currentSize, newSize;
+- int szPage = pPager->pageSize;
+- assert( pPager->eLock==EXCLUSIVE_LOCK );
+- /* TODO: Is it safe to use Pager.dbFileSize here? */
+- rc = sqlite3OsFileSize(pPager->fd, ¤tSize);
+- newSize = szPage*(i64)nPage;
+- if( rc==SQLITE_OK && currentSize!=newSize ){
+- if( currentSize>newSize ){
+- rc = sqlite3OsTruncate(pPager->fd, newSize);
+- }else if( (currentSize+szPage)<=newSize ){
+- char *pTmp = pPager->pTmpSpace;
+- memset(pTmp, 0, szPage);
+- testcase( (newSize-szPage) == currentSize );
+- testcase( (newSize-szPage) > currentSize );
+- rc = sqlite3OsWrite(pPager->fd, pTmp, szPage, newSize-szPage);
+- }
+- if( rc==SQLITE_OK ){
+- pPager->dbFileSize = nPage;
+- }
++#ifdef SQLITE_ENABLE_ATOMIC_WRITE
++static int jrnlBufferSize(Pager *pPager){
++ assert( !MEMDB );
++ if( !pPager->tempFile ){
++ int dc; /* Device characteristics */
++ int nSector; /* Sector size */
++ int szPage; /* Page size */
++
++ assert( isOpen(pPager->fd) );
++ dc = sqlite3OsDeviceCharacteristics(pPager->fd);
++ nSector = pPager->sectorSize;
++ szPage = pPager->pageSize;
++
++ assert(SQLITE_IOCAP_ATOMIC512==(512>>8));
++ assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8));
++ if( 0==(dc&(SQLITE_IOCAP_ATOMIC|(szPage>>8)) || nSector>szPage) ){
++ return 0;
+ }
+ }
+- return rc;
++
++ return JOURNAL_HDR_SZ(pPager) + JOURNAL_PG_SZ(pPager);
+ }
++#endif
+
+ /*
+-** Return a sanitized version of the sector-size of OS file pFile. The
+-** return value is guaranteed to lie between 32 and MAX_SECTOR_SIZE.
++** If SQLITE_CHECK_PAGES is defined then we do some sanity checking
++** on the cache using a hash function. This is used for testing
++** and debugging only.
+ */
+-SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *pFile){
+- int iRet = sqlite3OsSectorSize(pFile);
+- if( iRet<32 ){
+- iRet = 512;
+- }else if( iRet>MAX_SECTOR_SIZE ){
+- assert( MAX_SECTOR_SIZE>=512 );
+- iRet = MAX_SECTOR_SIZE;
++#ifdef SQLITE_CHECK_PAGES
++/*
++** Return a 32-bit hash of the page data for pPage.
++*/
++static u32 pager_datahash(int nByte, unsigned char *pData){
++ u32 hash = 0;
++ int i;
++ for(i=0; i<nByte; i++){
++ hash = (hash*1039) + pData[i];
+ }
+- return iRet;
++ return hash;
++}
++static u32 pager_pagehash(PgHdr *pPage){
++ return pager_datahash(pPage->pPager->pageSize, (unsigned char *)pPage->pData);
++}
++static void pager_set_pagehash(PgHdr *pPage){
++ pPage->pageHash = pager_pagehash(pPage);
+ }
+
+ /*
+-** Set the value of the Pager.sectorSize variable for the given
+-** pager based on the value returned by the xSectorSize method
+-** of the open database file. The sector size will be used
+-** to determine the size and alignment of journal header and
+-** master journal pointers within created journal files.
+-**
+-** For temporary files the effective sector size is always 512 bytes.
+-**
+-** Otherwise, for non-temporary files, the effective sector size is
+-** the value returned by the xSectorSize() method rounded up to 32 if
+-** it is less than 32, or rounded down to MAX_SECTOR_SIZE if it
+-** is greater than MAX_SECTOR_SIZE.
+-**
+-** If the file has the SQLITE_IOCAP_POWERSAFE_OVERWRITE property, then set
+-** the effective sector size to its minimum value (512). The purpose of
+-** pPager->sectorSize is to define the "blast radius" of bytes that
+-** might change if a crash occurs while writing to a single byte in
+-** that range. But with POWERSAFE_OVERWRITE, the blast radius is zero
+-** (that is what POWERSAFE_OVERWRITE means), so we minimize the sector
+-** size. For backwards compatibility of the rollback journal file format,
+-** we cannot reduce the effective sector size below 512.
++** The CHECK_PAGE macro takes a PgHdr* as an argument. If SQLITE_CHECK_PAGES
++** is defined, and NDEBUG is not defined, an assert() statement checks
++** that the page is either dirty or still matches the calculated page-hash.
+ */
+-static void setSectorSize(Pager *pPager){
+- assert( isOpen(pPager->fd) || pPager->tempFile );
+-
+- if( pPager->tempFile
+- || (sqlite3OsDeviceCharacteristics(pPager->fd) &
+- SQLITE_IOCAP_POWERSAFE_OVERWRITE)!=0
+- ){
+- /* Sector size doesn't matter for temporary files. Also, the file
+- ** may not have been opened yet, in which case the OsSectorSize()
+- ** call will segfault. */
+- pPager->sectorSize = 512;
+- }else{
+- pPager->sectorSize = sqlite3SectorSize(pPager->fd);
+- }
++#define CHECK_PAGE(x) checkPage(x)
++static void checkPage(PgHdr *pPg){
++ Pager *pPager = pPg->pPager;
++ assert( pPager->eState!=PAGER_ERROR );
++ assert( (pPg->flags&PGHDR_DIRTY) || pPg->pageHash==pager_pagehash(pPg) );
+ }
+
++#else
++#define pager_datahash(X,Y) 0
++#define pager_pagehash(X) 0
++#define pager_set_pagehash(X)
++#define CHECK_PAGE(x)
++#endif /* SQLITE_CHECK_PAGES */
++
+ /*
+-** Playback the journal and thus restore the database file to
+-** the state it was in before we started making changes.
+-**
+-** The journal file format is as follows:
+-**
+-** (1) 8 byte prefix. A copy of aJournalMagic[].
+-** (2) 4 byte big-endian integer which is the number of valid page records
+-** in the journal. If this value is 0xffffffff, then compute the
+-** number of page records from the journal size.
+-** (3) 4 byte big-endian integer which is the initial value for the
+-** sanity checksum.
+-** (4) 4 byte integer which is the number of pages to truncate the
+-** database to during a rollback.
+-** (5) 4 byte big-endian integer which is the sector size. The header
+-** is this many bytes in size.
+-** (6) 4 byte big-endian integer which is the page size.
+-** (7) zero padding out to the next sector size.
+-** (8) Zero or more pages instances, each as follows:
+-** + 4 byte page number.
+-** + pPager->pageSize bytes of data.
+-** + 4 byte checksum
+-**
+-** When we speak of the journal header, we mean the first 7 items above.
+-** Each entry in the journal is an instance of the 8th item.
+-**
+-** Call the value from the second bullet "nRec". nRec is the number of
+-** valid page entries in the journal. In most cases, you can compute the
+-** value of nRec from the size of the journal file. But if a power
+-** failure occurred while the journal was being written, it could be the
+-** case that the size of the journal file had already been increased but
+-** the extra entries had not yet made it safely to disk. In such a case,
+-** the value of nRec computed from the file size would be too large. For
+-** that reason, we always use the nRec value in the header.
++** When this is called the journal file for pager pPager must be open.
++** This function attempts to read a master journal file name from the
++** end of the file and, if successful, copies it into memory supplied
++** by the caller. See comments above writeMasterJournal() for the format
++** used to store a master journal file name at the end of a journal file.
+ **
+-** If the nRec value is 0xffffffff it means that nRec should be computed
+-** from the file size. This value is used when the user selects the
+-** no-sync option for the journal. A power failure could lead to corruption
+-** in this case. But for things like temporary table (which will be
+-** deleted when the power is restored) we don't care.
++** zMaster must point to a buffer of at least nMaster bytes allocated by
++** the caller. This should be sqlite3_vfs.mxPathname+1 (to ensure there is
++** enough space to write the master journal name). If the master journal
++** name in the journal is longer than nMaster bytes (including a
++** nul-terminator), then this is handled as if no master journal name
++** were present in the journal.
+ **
+-** If the file opened as the journal file is not a well-formed
+-** journal file then all pages up to the first corrupted page are rolled
+-** back (or no pages if the journal header is corrupted). The journal file
+-** is then deleted and SQLITE_OK returned, just as if no corruption had
+-** been encountered.
++** If a master journal file name is present at the end of the journal
++** file, then it is copied into the buffer pointed to by zMaster. A
++** nul-terminator byte is appended to the buffer following the master
++** journal file name.
+ **
+-** If an I/O or malloc() error occurs, the journal-file is not deleted
+-** and an error code is returned.
++** If it is determined that no master journal file name is present
++** zMaster[0] is set to 0 and SQLITE_OK returned.
+ **
+-** The isHot parameter indicates that we are trying to rollback a journal
+-** that might be a hot journal. Or, it could be that the journal is
+-** preserved because of JOURNALMODE_PERSIST or JOURNALMODE_TRUNCATE.
+-** If the journal really is hot, reset the pager cache prior rolling
+-** back any content. If the journal is merely persistent, no reset is
+-** needed.
++** If an error occurs while reading from the journal file, an SQLite
++** error code is returned.
+ */
+-static int pager_playback(Pager *pPager, int isHot){
+- sqlite3_vfs *pVfs = pPager->pVfs;
+- i64 szJ; /* Size of the journal file in bytes */
+- u32 nRec; /* Number of Records in the journal */
+- u32 u; /* Unsigned loop counter */
+- Pgno mxPg = 0; /* Size of the original file in pages */
+- int rc; /* Result code of a subroutine */
+- int res = 1; /* Value returned by sqlite3OsAccess() */
+- char *zMaster = 0; /* Name of master journal file if any */
+- int needPagerReset; /* True to reset page prior to first page rollback */
+- int nPlayback = 0; /* Total number of pages restored from journal */
+-
+- /* Figure out how many records are in the journal. Abort early if
+- ** the journal is empty.
+- */
+- assert( isOpen(pPager->jfd) );
+- rc = sqlite3OsFileSize(pPager->jfd, &szJ);
+- if( rc!=SQLITE_OK ){
+- goto end_playback;
+- }
+-
+- /* Read the master journal name from the journal, if it is present.
+- ** If a master journal file name is specified, but the file is not
+- ** present on disk, then the journal is not hot and does not need to be
+- ** played back.
+- **
+- ** TODO: Technically the following is an error because it assumes that
+- ** buffer Pager.pTmpSpace is (mxPathname+1) bytes or larger. i.e. that
+- ** (pPager->pageSize >= pPager->pVfs->mxPathname+1). Using os_unix.c,
+- ** mxPathname is 512, which is the same as the minimum allowable value
+- ** for pageSize.
+- */
+- zMaster = pPager->pTmpSpace;
+- rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1);
+- if( rc==SQLITE_OK && zMaster[0] ){
+- rc = sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS, &res);
+- }
+- zMaster = 0;
+- if( rc!=SQLITE_OK || !res ){
+- goto end_playback;
+- }
+- pPager->journalOff = 0;
+- needPagerReset = isHot;
+-
+- /* This loop terminates either when a readJournalHdr() or
+- ** pager_playback_one_page() call returns SQLITE_DONE or an IO error
+- ** occurs.
+- */
+- while( 1 ){
+- /* Read the next journal header from the journal file. If there are
+- ** not enough bytes left in the journal file for a complete header, or
+- ** it is corrupted, then a process must have failed while writing it.
+- ** This indicates nothing more needs to be rolled back.
+- */
+- rc = readJournalHdr(pPager, isHot, szJ, &nRec, &mxPg);
+- if( rc!=SQLITE_OK ){
+- if( rc==SQLITE_DONE ){
+- rc = SQLITE_OK;
+- }
+- goto end_playback;
+- }
+-
+- /* If nRec is 0xffffffff, then this journal was created by a process
+- ** working in no-sync mode. This means that the rest of the journal
+- ** file consists of pages, there are no more journal headers. Compute
+- ** the value of nRec based on this assumption.
+- */
+- if( nRec==0xffffffff ){
+- assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) );
+- nRec = (int)((szJ - JOURNAL_HDR_SZ(pPager))/JOURNAL_PG_SZ(pPager));
+- }
+-
+- /* If nRec is 0 and this rollback is of a transaction created by this
+- ** process and if this is the final header in the journal, then it means
+- ** that this part of the journal was being filled but has not yet been
+- ** synced to disk. Compute the number of pages based on the remaining
+- ** size of the file.
+- **
+- ** The third term of the test was added to fix ticket #2565.
+- ** When rolling back a hot journal, nRec==0 always means that the next
+- ** chunk of the journal contains zero pages to be rolled back. But
+- ** when doing a ROLLBACK and the nRec==0 chunk is the last chunk in
+- ** the journal, it means that the journal might contain additional
+- ** pages that need to be rolled back and that the number of pages
+- ** should be computed based on the journal file size.
+- */
+- if( nRec==0 && !isHot &&
+- pPager->journalHdr+JOURNAL_HDR_SZ(pPager)==pPager->journalOff ){
+- nRec = (int)((szJ - pPager->journalOff) / JOURNAL_PG_SZ(pPager));
+- }
+-
+- /* If this is the first header read from the journal, truncate the
+- ** database file back to its original size.
+- */
+- if( pPager->journalOff==JOURNAL_HDR_SZ(pPager) ){
+- rc = pager_truncate(pPager, mxPg);
+- if( rc!=SQLITE_OK ){
+- goto end_playback;
+- }
+- pPager->dbSize = mxPg;
+- }
+-
+- /* Copy original pages out of the journal and back into the
+- ** database file and/or page cache.
+- */
+- for(u=0; u<nRec; u++){
+- if( needPagerReset ){
+- pager_reset(pPager);
+- needPagerReset = 0;
+- }
+- rc = pager_playback_one_page(pPager,&pPager->journalOff,0,1,0);
+- if( rc==SQLITE_OK ){
+- nPlayback++;
+- }else{
+- if( rc==SQLITE_DONE ){
+- pPager->journalOff = szJ;
+- break;
+- }else if( rc==SQLITE_IOERR_SHORT_READ ){
+- /* If the journal has been truncated, simply stop reading and
+- ** processing the journal. This might happen if the journal was
+- ** not completely written and synced prior to a crash. In that
+- ** case, the database should have never been written in the
+- ** first place so it is OK to simply abandon the rollback. */
+- rc = SQLITE_OK;
+- goto end_playback;
+- }else{
+- /* If we are unable to rollback, quit and return the error
+- ** code. This will cause the pager to enter the error state
+- ** so that no further harm will be done. Perhaps the next
+- ** process to come along will be able to rollback the database.
+- */
+- goto end_playback;
+- }
+- }
+- }
+- }
+- /*NOTREACHED*/
+- assert( 0 );
+-
+-end_playback:
+- /* Following a rollback, the database file should be back in its original
+- ** state prior to the start of the transaction, so invoke the
+- ** SQLITE_FCNTL_DB_UNCHANGED file-control method to disable the
+- ** assertion that the transaction counter was modified.
+- */
+-#ifdef SQLITE_DEBUG
+- if( pPager->fd->pMethods ){
+- sqlite3OsFileControlHint(pPager->fd,SQLITE_FCNTL_DB_UNCHANGED,0);
+- }
+-#endif
+-
+- /* If this playback is happening automatically as a result of an IO or
+- ** malloc error that occurred after the change-counter was updated but
+- ** before the transaction was committed, then the change-counter
+- ** modification may just have been reverted. If this happens in exclusive
+- ** mode, then subsequent transactions performed by the connection will not
+- ** update the change-counter at all. This may lead to cache inconsistency
+- ** problems for other processes at some point in the future. So, just
+- ** in case this has happened, clear the changeCountDone flag now.
+- */
+- pPager->changeCountDone = pPager->tempFile;
++static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, u32 nMaster){
++ int rc; /* Return code */
++ u32 len; /* Length in bytes of master journal name */
++ i64 szJ; /* Total size in bytes of journal file pJrnl */
++ u32 cksum; /* MJ checksum value read from journal */
++ u32 u; /* Unsigned loop counter */
++ unsigned char aMagic[8]; /* A buffer to hold the magic header */
++ zMaster[0] = '\0';
+
+- if( rc==SQLITE_OK ){
+- zMaster = pPager->pTmpSpace;
+- rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1);
+- testcase( rc!=SQLITE_OK );
+- }
+- if( rc==SQLITE_OK
+- && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN)
++ if( SQLITE_OK!=(rc = sqlite3OsFileSize(pJrnl, &szJ))
++ || szJ<16
++ || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-16, &len))
++ || len>=nMaster
++ || len==0
++ || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-12, &cksum))
++ || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, aMagic, 8, szJ-8))
++ || memcmp(aMagic, aJournalMagic, 8)
++ || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, zMaster, len, szJ-16-len))
+ ){
+- rc = sqlite3PagerSync(pPager, 0);
++ return rc;
+ }
+- if( rc==SQLITE_OK ){
+- rc = pager_end_transaction(pPager, zMaster[0]!='\0', 0);
+- testcase( rc!=SQLITE_OK );
++
++ /* See if the checksum matches the master journal name */
++ for(u=0; u<len; u++){
++ cksum -= zMaster[u];
+ }
+- if( rc==SQLITE_OK && zMaster[0] && res ){
+- /* If there was a master journal and this routine will return success,
+- ** see if it is possible to delete the master journal.
++ if( cksum ){
++ /* If the checksum doesn't add up, then one or more of the disk sectors
++ ** containing the master journal filename is corrupted. This means
++ ** definitely roll back, so just return SQLITE_OK and report a (nul)
++ ** master-journal filename.
+ */
+- rc = pager_delmaster(pPager, zMaster);
+- testcase( rc!=SQLITE_OK );
+- }
+- if( isHot && nPlayback ){
+- sqlite3_log(SQLITE_NOTICE_RECOVER_ROLLBACK, "recovered %d pages from %s",
+- nPlayback, pPager->zJournal);
++ len = 0;
+ }
+-
+- /* The Pager.sectorSize variable may have been updated while rolling
+- ** back a journal created by a process with a different sector size
+- ** value. Reset it to the correct value for this process.
+- */
+- setSectorSize(pPager);
+- return rc;
++ zMaster[len] = '\0';
++
++ return SQLITE_OK;
+ }
+
+-
+ /*
+-** Read the content for page pPg out of the database file and into
+-** pPg->pData. A shared lock or greater must be held on the database
+-** file before this function is called.
++** Return the offset of the sector boundary at or immediately
++** following the value in pPager->journalOff, assuming a sector
++** size of pPager->sectorSize bytes.
+ **
+-** If page 1 is read, then the value of Pager.dbFileVers[] is set to
+-** the value read from the database file.
++** i.e for a sector size of 512:
+ **
+-** If an IO error occurs, then the IO error is returned to the caller.
+-** Otherwise, SQLITE_OK is returned.
++** Pager.journalOff Return value
++** ---------------------------------------
++** 0 0
++** 512 512
++** 100 512
++** 2000 2048
++**
+ */
+-static int readDbPage(PgHdr *pPg, u32 iFrame){
+- Pager *pPager = pPg->pPager; /* Pager object associated with page pPg */
+- Pgno pgno = pPg->pgno; /* Page number to read */
+- int rc = SQLITE_OK; /* Return code */
+- int pgsz = pPager->pageSize; /* Number of bytes to read */
+-
+- assert( pPager->eState>=PAGER_READER && !MEMDB );
+- assert( isOpen(pPager->fd) );
+-
+-#ifndef SQLITE_OMIT_WAL
+- if( iFrame ){
+- /* Try to pull the page from the write-ahead log. */
+- rc = sqlite3WalReadFrame(pPager->pWal, iFrame, pgsz, pPg->pData);
+- }else
+-#endif
+- {
+- i64 iOffset = (pgno-1)*(i64)pPager->pageSize;
+- rc = sqlite3OsRead(pPager->fd, pPg->pData, pgsz, iOffset);
+- if( rc==SQLITE_IOERR_SHORT_READ ){
+- rc = SQLITE_OK;
+- }
+- }
+-
+- if( pgno==1 ){
+- if( rc ){
+- /* If the read is unsuccessful, set the dbFileVers[] to something
+- ** that will never be a valid file version. dbFileVers[] is a copy
+- ** of bytes 24..39 of the database. Bytes 28..31 should always be
+- ** zero or the size of the database in page. Bytes 32..35 and 35..39
+- ** should be page numbers which are never 0xffffffff. So filling
+- ** pPager->dbFileVers[] with all 0xff bytes should suffice.
+- **
+- ** For an encrypted database, the situation is more complex: bytes
+- ** 24..39 of the database are white noise. But the probability of
+- ** white noise equaling 16 bytes of 0xff is vanishingly small so
+- ** we should still be ok.
+- */
+- memset(pPager->dbFileVers, 0xff, sizeof(pPager->dbFileVers));
+- }else{
+- u8 *dbFileVers = &((u8*)pPg->pData)[24];
+- memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers));
+- }
++static i64 journalHdrOffset(Pager *pPager){
++ i64 offset = 0;
++ i64 c = pPager->journalOff;
++ if( c ){
++ offset = ((c-1)/JOURNAL_HDR_SZ(pPager) + 1) * JOURNAL_HDR_SZ(pPager);
+ }
+- CODEC1(pPager, pPg->pData, pgno, 3, rc = SQLITE_NOMEM);
+-
+- PAGER_INCR(sqlite3_pager_readdb_count);
+- PAGER_INCR(pPager->nRead);
+- IOTRACE(("PGIN %p %d\n", pPager, pgno));
+- PAGERTRACE(("FETCH %d page %d hash(%08x)\n",
+- PAGERID(pPager), pgno, pager_pagehash(pPg)));
+-
+- return rc;
++ assert( offset%JOURNAL_HDR_SZ(pPager)==0 );
++ assert( offset>=c );
++ assert( (offset-c)<JOURNAL_HDR_SZ(pPager) );
++ return offset;
+ }
+
+ /*
+-** Update the value of the change-counter at offsets 24 and 92 in
+-** the header and the sqlite version number at offset 96.
++** The journal file must be open when this function is called.
+ **
+-** This is an unconditional update. See also the pager_incr_changecounter()
+-** routine which only updates the change-counter if the update is actually
+-** needed, as determined by the pPager->changeCountDone state variable.
++** This function is a no-op if the journal file has not been written to
++** within the current transaction (i.e. if Pager.journalOff==0).
++**
++** If doTruncate is non-zero or the Pager.journalSizeLimit variable is
++** set to 0, then truncate the journal file to zero bytes in size. Otherwise,
++** zero the 28-byte header at the start of the journal file. In either case,
++** if the pager is not in no-sync mode, sync the journal file immediately
++** after writing or truncating it.
++**
++** If Pager.journalSizeLimit is set to a positive, non-zero value, and
++** following the truncation or zeroing described above the size of the
++** journal file in bytes is larger than this value, then truncate the
++** journal file to Pager.journalSizeLimit bytes. The journal file does
++** not need to be synced following this operation.
++**
++** If an IO error occurs, abandon processing and return the IO error code.
++** Otherwise, return SQLITE_OK.
+ */
+-static void pager_write_changecounter(PgHdr *pPg){
+- u32 change_counter;
++static int zeroJournalHdr(Pager *pPager, int doTruncate){
++ int rc = SQLITE_OK; /* Return code */
++ assert( isOpen(pPager->jfd) );
++ if( pPager->journalOff ){
++ const i64 iLimit = pPager->journalSizeLimit; /* Local cache of jsl */
+
+- /* Increment the value just read and write it back to byte 24. */
+- change_counter = sqlite3Get4byte((u8*)pPg->pPager->dbFileVers)+1;
+- put32bits(((char*)pPg->pData)+24, change_counter);
++ IOTRACE(("JZEROHDR %p\n", pPager))
++ if( doTruncate || iLimit==0 ){
++ rc = sqlite3OsTruncate(pPager->jfd, 0);
++ }else{
++ static const char zeroHdr[28] = {0};
++ rc = sqlite3OsWrite(pPager->jfd, zeroHdr, sizeof(zeroHdr), 0);
++ }
++ if( rc==SQLITE_OK && !pPager->noSync ){
++ rc = sqlite3OsSync(pPager->jfd, SQLITE_SYNC_DATAONLY|pPager->syncFlags);
++ }
+
+- /* Also store the SQLite version number in bytes 96..99 and in
+- ** bytes 92..95 store the change counter for which the version number
+- ** is valid. */
+- put32bits(((char*)pPg->pData)+92, change_counter);
+- put32bits(((char*)pPg->pData)+96, SQLITE_VERSION_NUMBER);
++ /* At this point the transaction is committed but the write lock
++ ** is still held on the file. If there is a size limit configured for
++ ** the persistent journal and the journal file currently consumes more
++ ** space than that limit allows for, truncate it now. There is no need
++ ** to sync the file following this operation.
++ */
++ if( rc==SQLITE_OK && iLimit>0 ){
++ i64 sz;
++ rc = sqlite3OsFileSize(pPager->jfd, &sz);
++ if( rc==SQLITE_OK && sz>iLimit ){
++ rc = sqlite3OsTruncate(pPager->jfd, iLimit);
++ }
++ }
++ }
++ return rc;
+ }
+
+-#ifndef SQLITE_OMIT_WAL
+ /*
+-** This function is invoked once for each page that has already been
+-** written into the log file when a WAL transaction is rolled back.
+-** Parameter iPg is the page number of said page. The pCtx argument
+-** is actually a pointer to the Pager structure.
++** The journal file must be open when this routine is called. A journal
++** header (JOURNAL_HDR_SZ bytes) is written into the journal file at the
++** current location.
+ **
+-** If page iPg is present in the cache, and has no outstanding references,
+-** it is discarded. Otherwise, if there are one or more outstanding
+-** references, the page content is reloaded from the database. If the
+-** attempt to reload content from the database is required and fails,
+-** return an SQLite error code. Otherwise, SQLITE_OK.
++** The format for the journal header is as follows:
++** - 8 bytes: Magic identifying journal format.
++** - 4 bytes: Number of records in journal, or -1 no-sync mode is on.
++** - 4 bytes: Random number used for page hash.
++** - 4 bytes: Initial database page count.
++** - 4 bytes: Sector size used by the process that wrote this journal.
++** - 4 bytes: Database page size.
++**
++** Followed by (JOURNAL_HDR_SZ - 28) bytes of unused space.
+ */
+-static int pagerUndoCallback(void *pCtx, Pgno iPg){
+- int rc = SQLITE_OK;
+- Pager *pPager = (Pager *)pCtx;
+- PgHdr *pPg;
++static int writeJournalHdr(Pager *pPager){
++ int rc = SQLITE_OK; /* Return code */
++ char *zHeader = pPager->pTmpSpace; /* Temporary space used to build header */
++ u32 nHeader = (u32)pPager->pageSize;/* Size of buffer pointed to by zHeader */
++ u32 nWrite; /* Bytes of header sector written */
++ int ii; /* Loop counter */
+
+- assert( pagerUseWal(pPager) );
+- pPg = sqlite3PagerLookup(pPager, iPg);
+- if( pPg ){
+- if( sqlite3PcachePageRefcount(pPg)==1 ){
+- sqlite3PcacheDrop(pPg);
+- }else{
+- u32 iFrame = 0;
+- rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame);
+- if( rc==SQLITE_OK ){
+- rc = readDbPage(pPg, iFrame);
+- }
+- if( rc==SQLITE_OK ){
+- pPager->xReiniter(pPg);
+- }
+- sqlite3PagerUnrefNotNull(pPg);
++ assert( isOpen(pPager->jfd) ); /* Journal file must be open. */
++
++ if( nHeader>JOURNAL_HDR_SZ(pPager) ){
++ nHeader = JOURNAL_HDR_SZ(pPager);
++ }
++
++ /* If there are active savepoints and any of them were created
++ ** since the most recent journal header was written, update the
++ ** PagerSavepoint.iHdrOffset fields now.
++ */
++ for(ii=0; ii<pPager->nSavepoint; ii++){
++ if( pPager->aSavepoint[ii].iHdrOffset==0 ){
++ pPager->aSavepoint[ii].iHdrOffset = pPager->journalOff;
+ }
+ }
+
+- /* Normally, if a transaction is rolled back, any backup processes are
+- ** updated as data is copied out of the rollback journal and into the
+- ** database. This is not generally possible with a WAL database, as
+- ** rollback involves simply truncating the log file. Therefore, if one
+- ** or more frames have already been written to the log (and therefore
+- ** also copied into the backup databases) as part of this transaction,
+- ** the backups must be restarted.
++ pPager->journalHdr = pPager->journalOff = journalHdrOffset(pPager);
++
++ /*
++ ** Write the nRec Field - the number of page records that follow this
++ ** journal header. Normally, zero is written to this value at this time.
++ ** After the records are added to the journal (and the journal synced,
++ ** if in full-sync mode), the zero is overwritten with the true number
++ ** of records (see syncJournal()).
++ **
++ ** A faster alternative is to write 0xFFFFFFFF to the nRec field. When
++ ** reading the journal this value tells SQLite to assume that the
++ ** rest of the journal file contains valid page records. This assumption
++ ** is dangerous, as if a failure occurred whilst writing to the journal
++ ** file it may contain some garbage data. There are two scenarios
++ ** where this risk can be ignored:
++ **
++ ** * When the pager is in no-sync mode. Corruption can follow a
++ ** power failure in this case anyway.
++ **
++ ** * When the SQLITE_IOCAP_SAFE_APPEND flag is set. This guarantees
++ ** that garbage data is never appended to the journal file.
+ */
+- sqlite3BackupRestart(pPager->pBackup);
++ assert( isOpen(pPager->fd) || pPager->noSync );
++ if( pPager->noSync || (pPager->journalMode==PAGER_JOURNALMODE_MEMORY)
++ || (sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND)
++ ){
++ memcpy(zHeader, aJournalMagic, sizeof(aJournalMagic));
++ put32bits(&zHeader[sizeof(aJournalMagic)], 0xffffffff);
++ }else{
++ memset(zHeader, 0, sizeof(aJournalMagic)+4);
++ }
+
+- return rc;
+-}
++ /* The random check-hash initializer */
++ sqlite3_randomness(sizeof(pPager->cksumInit), &pPager->cksumInit);
++ put32bits(&zHeader[sizeof(aJournalMagic)+4], pPager->cksumInit);
++ /* The initial database size */
++ put32bits(&zHeader[sizeof(aJournalMagic)+8], pPager->dbOrigSize);
++ /* The assumed sector size for this process */
++ put32bits(&zHeader[sizeof(aJournalMagic)+12], pPager->sectorSize);
+
+-/*
+-** This function is called to rollback a transaction on a WAL database.
+-*/
+-static int pagerRollbackWal(Pager *pPager){
+- int rc; /* Return Code */
+- PgHdr *pList; /* List of dirty pages to revert */
++ /* The page size */
++ put32bits(&zHeader[sizeof(aJournalMagic)+16], pPager->pageSize);
+
+- /* For all pages in the cache that are currently dirty or have already
+- ** been written (but not committed) to the log file, do one of the
+- ** following:
+- **
+- ** + Discard the cached page (if refcount==0), or
+- ** + Reload page content from the database (if refcount>0).
++ /* Initializing the tail of the buffer is not necessary. Everything
++ ** works find if the following memset() is omitted. But initializing
++ ** the memory prevents valgrind from complaining, so we are willing to
++ ** take the performance hit.
+ */
+- pPager->dbSize = pPager->dbOrigSize;
+- rc = sqlite3WalUndo(pPager->pWal, pagerUndoCallback, (void *)pPager);
+- pList = sqlite3PcacheDirtyList(pPager->pPCache);
+- while( pList && rc==SQLITE_OK ){
+- PgHdr *pNext = pList->pDirty;
+- rc = pagerUndoCallback((void *)pPager, pList->pgno);
+- pList = pNext;
++ memset(&zHeader[sizeof(aJournalMagic)+20], 0,
++ nHeader-(sizeof(aJournalMagic)+20));
++
++ /* In theory, it is only necessary to write the 28 bytes that the
++ ** journal header consumes to the journal file here. Then increment the
++ ** Pager.journalOff variable by JOURNAL_HDR_SZ so that the next
++ ** record is written to the following sector (leaving a gap in the file
++ ** that will be implicitly filled in by the OS).
++ **
++ ** However it has been discovered that on some systems this pattern can
++ ** be significantly slower than contiguously writing data to the file,
++ ** even if that means explicitly writing data to the block of
++ ** (JOURNAL_HDR_SZ - 28) bytes that will not be used. So that is what
++ ** is done.
++ **
++ ** The loop is required here in case the sector-size is larger than the
++ ** database page size. Since the zHeader buffer is only Pager.pageSize
++ ** bytes in size, more than one call to sqlite3OsWrite() may be required
++ ** to populate the entire journal header sector.
++ */
++ for(nWrite=0; rc==SQLITE_OK&&nWrite<JOURNAL_HDR_SZ(pPager); nWrite+=nHeader){
++ IOTRACE(("JHDR %p %lld %d\n", pPager, pPager->journalHdr, nHeader))
++ rc = sqlite3OsWrite(pPager->jfd, zHeader, nHeader, pPager->journalOff);
++ assert( pPager->journalHdr <= pPager->journalOff );
++ pPager->journalOff += nHeader;
+ }
+
+ return rc;
+ }
+
+ /*
+-** This function is a wrapper around sqlite3WalFrames(). As well as logging
+-** the contents of the list of pages headed by pList (connected by pDirty),
+-** this function notifies any active backup processes that the pages have
+-** changed.
++** The journal file must be open when this is called. A journal header file
++** (JOURNAL_HDR_SZ bytes) is read from the current location in the journal
++** file. The current location in the journal file is given by
++** pPager->journalOff. See comments above function writeJournalHdr() for
++** a description of the journal header format.
+ **
+-** The list of pages passed into this routine is always sorted by page number.
+-** Hence, if page 1 appears anywhere on the list, it will be the first page.
+-*/
+-static int pagerWalFrames(
+- Pager *pPager, /* Pager object */
+- PgHdr *pList, /* List of frames to log */
+- Pgno nTruncate, /* Database size after this commit */
+- int isCommit /* True if this is a commit */
++** If the header is read successfully, *pNRec is set to the number of
++** page records following this header and *pDbSize is set to the size of the
++** database before the transaction began, in pages. Also, pPager->cksumInit
++** is set to the value read from the journal header. SQLITE_OK is returned
++** in this case.
++**
++** If the journal header file appears to be corrupted, SQLITE_DONE is
++** returned and *pNRec and *PDbSize are undefined. If JOURNAL_HDR_SZ bytes
++** cannot be read from the journal file an error code is returned.
++*/
++static int readJournalHdr(
++ Pager *pPager, /* Pager object */
++ int isHot,
++ i64 journalSize, /* Size of the open journal file in bytes */
++ u32 *pNRec, /* OUT: Value read from the nRec field */
++ u32 *pDbSize /* OUT: Value of original database size field */
+ ){
+- int rc; /* Return code */
+- int nList; /* Number of pages in pList */
+- PgHdr *p; /* For looping over pages */
++ int rc; /* Return code */
++ unsigned char aMagic[8]; /* A buffer to hold the magic header */
++ i64 iHdrOff; /* Offset of journal header being read */
+
+- assert( pPager->pWal );
+- assert( pList );
+-#ifdef SQLITE_DEBUG
+- /* Verify that the page list is in accending order */
+- for(p=pList; p && p->pDirty; p=p->pDirty){
+- assert( p->pgno < p->pDirty->pgno );
+- }
+-#endif
++ assert( isOpen(pPager->jfd) ); /* Journal file must be open. */
+
+- assert( pList->pDirty==0 || isCommit );
+- if( isCommit ){
+- /* If a WAL transaction is being committed, there is no point in writing
+- ** any pages with page numbers greater than nTruncate into the WAL file.
+- ** They will never be read by any client. So remove them from the pDirty
+- ** list here. */
+- PgHdr **ppNext = &pList;
+- nList = 0;
+- for(p=pList; (*ppNext = p)!=0; p=p->pDirty){
+- if( p->pgno<=nTruncate ){
+- ppNext = &p->pDirty;
+- nList++;
+- }
+- }
+- assert( pList );
+- }else{
+- nList = 1;
++ /* Advance Pager.journalOff to the start of the next sector. If the
++ ** journal file is too small for there to be a header stored at this
++ ** point, return SQLITE_DONE.
++ */
++ pPager->journalOff = journalHdrOffset(pPager);
++ if( pPager->journalOff+JOURNAL_HDR_SZ(pPager) > journalSize ){
++ return SQLITE_DONE;
+ }
+- pPager->aStat[PAGER_STAT_WRITE] += nList;
++ iHdrOff = pPager->journalOff;
+
+- if( pList->pgno==1 ) pager_write_changecounter(pList);
+- rc = sqlite3WalFrames(pPager->pWal,
+- pPager->pageSize, pList, nTruncate, isCommit, pPager->walSyncFlags
+- );
+- if( rc==SQLITE_OK && pPager->pBackup ){
+- for(p=pList; p; p=p->pDirty){
+- sqlite3BackupUpdate(pPager->pBackup, p->pgno, (u8 *)p->pData);
++ /* Read in the first 8 bytes of the journal header. If they do not match
++ ** the magic string found at the start of each journal header, return
++ ** SQLITE_DONE. If an IO error occurs, return an error code. Otherwise,
++ ** proceed.
++ */
++ if( isHot || iHdrOff!=pPager->journalHdr ){
++ rc = sqlite3OsRead(pPager->jfd, aMagic, sizeof(aMagic), iHdrOff);
++ if( rc ){
++ return rc;
++ }
++ if( memcmp(aMagic, aJournalMagic, sizeof(aMagic))!=0 ){
++ return SQLITE_DONE;
+ }
+ }
+
+-#ifdef SQLITE_CHECK_PAGES
+- pList = sqlite3PcacheDirtyList(pPager->pPCache);
+- for(p=pList; p; p=p->pDirty){
+- pager_set_pagehash(p);
++ /* Read the first three 32-bit fields of the journal header: The nRec
++ ** field, the checksum-initializer and the database size at the start
++ ** of the transaction. Return an error code if anything goes wrong.
++ */
++ if( SQLITE_OK!=(rc = read32bits(pPager->jfd, iHdrOff+8, pNRec))
++ || SQLITE_OK!=(rc = read32bits(pPager->jfd, iHdrOff+12, &pPager->cksumInit))
++ || SQLITE_OK!=(rc = read32bits(pPager->jfd, iHdrOff+16, pDbSize))
++ ){
++ return rc;
+ }
+-#endif
+
+- return rc;
+-}
++ if( pPager->journalOff==0 ){
++ u32 iPageSize; /* Page-size field of journal header */
++ u32 iSectorSize; /* Sector-size field of journal header */
+
+-/*
+-** Begin a read transaction on the WAL.
+-**
+-** This routine used to be called "pagerOpenSnapshot()" because it essentially
+-** makes a snapshot of the database at the current point in time and preserves
+-** that snapshot for use by the reader in spite of concurrently changes by
+-** other writers or checkpointers.
+-*/
+-static int pagerBeginReadTransaction(Pager *pPager){
+- int rc; /* Return code */
+- int changed = 0; /* True if cache must be reset */
++ /* Read the page-size and sector-size journal header fields. */
++ if( SQLITE_OK!=(rc = read32bits(pPager->jfd, iHdrOff+20, &iSectorSize))
++ || SQLITE_OK!=(rc = read32bits(pPager->jfd, iHdrOff+24, &iPageSize))
++ ){
++ return rc;
++ }
+
+- assert( pagerUseWal(pPager) );
+- assert( pPager->eState==PAGER_OPEN || pPager->eState==PAGER_READER );
++ /* Versions of SQLite prior to 3.5.8 set the page-size field of the
++ ** journal header to zero. In this case, assume that the Pager.pageSize
++ ** variable is already set to the correct page size.
++ */
++ if( iPageSize==0 ){
++ iPageSize = pPager->pageSize;
++ }
+
+- /* sqlite3WalEndReadTransaction() was not called for the previous
+- ** transaction in locking_mode=EXCLUSIVE. So call it now. If we
+- ** are in locking_mode=NORMAL and EndRead() was previously called,
+- ** the duplicate call is harmless.
+- */
+- sqlite3WalEndReadTransaction(pPager->pWal);
++ /* Check that the values read from the page-size and sector-size fields
++ ** are within range. To be 'in range', both values need to be a power
++ ** of two greater than or equal to 512 or 32, and not greater than their
++ ** respective compile time maximum limits.
++ */
++ if( iPageSize<512 || iSectorSize<32
++ || iPageSize>SQLITE_MAX_PAGE_SIZE || iSectorSize>MAX_SECTOR_SIZE
++ || ((iPageSize-1)&iPageSize)!=0 || ((iSectorSize-1)&iSectorSize)!=0
++ ){
++ /* If the either the page-size or sector-size in the journal-header is
++ ** invalid, then the process that wrote the journal-header must have
++ ** crashed before the header was synced. In this case stop reading
++ ** the journal file here.
++ */
++ return SQLITE_DONE;
++ }
+
+- rc = sqlite3WalBeginReadTransaction(pPager->pWal, &changed);
+- if( rc!=SQLITE_OK || changed ){
+- pager_reset(pPager);
+- if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0);
++ /* Update the page-size to match the value read from the journal.
++ ** Use a testcase() macro to make sure that malloc failure within
++ ** PagerSetPagesize() is tested.
++ */
++ rc = sqlite3PagerSetPagesize(pPager, &iPageSize, -1);
++ testcase( rc!=SQLITE_OK );
++
++ /* Update the assumed sector-size to match the value used by
++ ** the process that created this journal. If this journal was
++ ** created by a process other than this one, then this routine
++ ** is being called from within pager_playback(). The local value
++ ** of Pager.sectorSize is restored at the end of that routine.
++ */
++ pPager->sectorSize = iSectorSize;
+ }
+
++ pPager->journalOff += JOURNAL_HDR_SZ(pPager);
+ return rc;
+ }
+-#endif
++
+
+ /*
+-** This function is called as part of the transition from PAGER_OPEN
+-** to PAGER_READER state to determine the size of the database file
+-** in pages (assuming the page size currently stored in Pager.pageSize).
++** Write the supplied master journal name into the journal file for pager
++** pPager at the current location. The master journal name must be the last
++** thing written to a journal file. If the pager is in full-sync mode, the
++** journal file descriptor is advanced to the next sector boundary before
++** anything is written. The format is:
+ **
+-** If no error occurs, SQLITE_OK is returned and the size of the database
+-** in pages is stored in *pnPage. Otherwise, an error code (perhaps
+-** SQLITE_IOERR_FSTAT) is returned and *pnPage is left unmodified.
++** + 4 bytes: PAGER_MJ_PGNO.
++** + N bytes: Master journal filename in utf-8.
++** + 4 bytes: N (length of master journal name in bytes, no nul-terminator).
++** + 4 bytes: Master journal name checksum.
++** + 8 bytes: aJournalMagic[].
++**
++** The master journal page checksum is the sum of the bytes in the master
++** journal name, where each byte is interpreted as a signed 8-bit integer.
++**
++** If zMaster is a NULL pointer (occurs for a single database transaction),
++** this call is a no-op.
+ */
+-static int pagerPagecount(Pager *pPager, Pgno *pnPage){
+- Pgno nPage; /* Value to return via *pnPage */
++static int writeMasterJournal(Pager *pPager, const char *zMaster){
++ int rc; /* Return code */
++ int nMaster; /* Length of string zMaster */
++ i64 iHdrOff; /* Offset of header in journal file */
++ i64 jrnlSize; /* Size of journal file on disk */
++ u32 cksum = 0; /* Checksum of string zMaster */
+
+- /* Query the WAL sub-system for the database size. The WalDbsize()
+- ** function returns zero if the WAL is not open (i.e. Pager.pWal==0), or
+- ** if the database size is not available. The database size is not
+- ** available from the WAL sub-system if the log file is empty or
+- ** contains no valid committed transactions.
+- */
+- assert( pPager->eState==PAGER_OPEN );
+- assert( pPager->eLock>=SHARED_LOCK );
+- nPage = sqlite3WalDbsize(pPager->pWal);
++ assert( pPager->setMaster==0 );
++ assert( !pagerUseWal(pPager) );
+
+- /* If the database size was not available from the WAL sub-system,
+- ** determine it based on the size of the database file. If the size
+- ** of the database file is not an integer multiple of the page-size,
+- ** round down to the nearest page. Except, any file larger than 0
+- ** bytes in size is considered to contain at least one page.
++ if( !zMaster
++ || pPager->journalMode==PAGER_JOURNALMODE_MEMORY
++ || !isOpen(pPager->jfd)
++ ){
++ return SQLITE_OK;
++ }
++ pPager->setMaster = 1;
++ assert( pPager->journalHdr <= pPager->journalOff );
++
++ /* Calculate the length in bytes and the checksum of zMaster */
++ for(nMaster=0; zMaster[nMaster]; nMaster++){
++ cksum += zMaster[nMaster];
++ }
++
++ /* If in full-sync mode, advance to the next disk sector before writing
++ ** the master journal name. This is in case the previous page written to
++ ** the journal has already been synced.
+ */
+- if( nPage==0 ){
+- i64 n = 0; /* Size of db file in bytes */
+- assert( isOpen(pPager->fd) || pPager->tempFile );
+- if( isOpen(pPager->fd) ){
+- int rc = sqlite3OsFileSize(pPager->fd, &n);
+- if( rc!=SQLITE_OK ){
+- return rc;
+- }
+- }
+- nPage = (Pgno)((n+pPager->pageSize-1) / pPager->pageSize);
++ if( pPager->fullSync ){
++ pPager->journalOff = journalHdrOffset(pPager);
+ }
++ iHdrOff = pPager->journalOff;
+
+- /* If the current number of pages in the file is greater than the
+- ** configured maximum pager number, increase the allowed limit so
+- ** that the file can be read.
++ /* Write the master journal data to the end of the journal file. If
++ ** an error occurs, return the error code to the caller.
+ */
+- if( nPage>pPager->mxPgno ){
+- pPager->mxPgno = (Pgno)nPage;
++ if( (0 != (rc = write32bits(pPager->jfd, iHdrOff, PAGER_MJ_PGNO(pPager))))
++ || (0 != (rc = sqlite3OsWrite(pPager->jfd, zMaster, nMaster, iHdrOff+4)))
++ || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nMaster, nMaster)))
++ || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nMaster+4, cksum)))
++ || (0 != (rc = sqlite3OsWrite(pPager->jfd, aJournalMagic, 8, iHdrOff+4+nMaster+8)))
++ ){
++ return rc;
+ }
++ pPager->journalOff += (nMaster+20);
+
+- *pnPage = nPage;
+- return SQLITE_OK;
++ /* If the pager is in peristent-journal mode, then the physical
++ ** journal-file may extend past the end of the master-journal name
++ ** and 8 bytes of magic data just written to the file. This is
++ ** dangerous because the code to rollback a hot-journal file
++ ** will not be able to find the master-journal name to determine
++ ** whether or not the journal is hot.
++ **
++ ** Easiest thing to do in this scenario is to truncate the journal
++ ** file to the required size.
++ */
++ if( SQLITE_OK==(rc = sqlite3OsFileSize(pPager->jfd, &jrnlSize))
++ && jrnlSize>pPager->journalOff
++ ){
++ rc = sqlite3OsTruncate(pPager->jfd, pPager->journalOff);
++ }
++ return rc;
+ }
+
+-#ifndef SQLITE_OMIT_WAL
+ /*
+-** Check if the *-wal file that corresponds to the database opened by pPager
+-** exists if the database is not empy, or verify that the *-wal file does
+-** not exist (by deleting it) if the database file is empty.
+-**
+-** If the database is not empty and the *-wal file exists, open the pager
+-** in WAL mode. If the database is empty or if no *-wal file exists and
+-** if no error occurs, make sure Pager.journalMode is not set to
+-** PAGER_JOURNALMODE_WAL.
+-**
+-** Return SQLITE_OK or an error code.
+-**
+-** The caller must hold a SHARED lock on the database file to call this
+-** function. Because an EXCLUSIVE lock on the db file is required to delete
+-** a WAL on a none-empty database, this ensures there is no race condition
+-** between the xAccess() below and an xDelete() being executed by some
+-** other connection.
++** Discard the entire contents of the in-memory page-cache.
+ */
+-static int pagerOpenWalIfPresent(Pager *pPager){
+- int rc = SQLITE_OK;
+- assert( pPager->eState==PAGER_OPEN );
+- assert( pPager->eLock>=SHARED_LOCK );
++static void pager_reset(Pager *pPager){
++ pPager->iDataVersion++;
++ sqlite3BackupRestart(pPager->pBackup);
++ sqlite3PcacheClear(pPager->pPCache);
++}
+
+- if( !pPager->tempFile ){
+- int isWal; /* True if WAL file exists */
+- Pgno nPage; /* Size of the database file */
++/*
++** Return the pPager->iDataVersion value
++*/
++SQLITE_PRIVATE u32 sqlite3PagerDataVersion(Pager *pPager){
++ assert( pPager->eState>PAGER_OPEN );
++ return pPager->iDataVersion;
++}
++
++/*
++** Free all structures in the Pager.aSavepoint[] array and set both
++** Pager.aSavepoint and Pager.nSavepoint to zero. Close the sub-journal
++** if it is open and the pager is not in exclusive mode.
++*/
++static void releaseAllSavepoints(Pager *pPager){
++ int ii; /* Iterator for looping through Pager.aSavepoint */
++ for(ii=0; ii<pPager->nSavepoint; ii++){
++ sqlite3BitvecDestroy(pPager->aSavepoint[ii].pInSavepoint);
++ }
++ if( !pPager->exclusiveMode || sqlite3IsMemJournal(pPager->sjfd) ){
++ sqlite3OsClose(pPager->sjfd);
++ }
++ sqlite3_free(pPager->aSavepoint);
++ pPager->aSavepoint = 0;
++ pPager->nSavepoint = 0;
++ pPager->nSubRec = 0;
++}
++
++/*
++** Set the bit number pgno in the PagerSavepoint.pInSavepoint
++** bitvecs of all open savepoints. Return SQLITE_OK if successful
++** or SQLITE_NOMEM if a malloc failure occurs.
++*/
++static int addToSavepointBitvecs(Pager *pPager, Pgno pgno){
++ int ii; /* Loop counter */
++ int rc = SQLITE_OK; /* Result code */
+
+- rc = pagerPagecount(pPager, &nPage);
+- if( rc ) return rc;
+- if( nPage==0 ){
+- rc = sqlite3OsDelete(pPager->pVfs, pPager->zWal, 0);
+- if( rc==SQLITE_IOERR_DELETE_NOENT ) rc = SQLITE_OK;
+- isWal = 0;
+- }else{
+- rc = sqlite3OsAccess(
+- pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &isWal
+- );
+- }
+- if( rc==SQLITE_OK ){
+- if( isWal ){
+- testcase( sqlite3PcachePagecount(pPager->pPCache)==0 );
+- rc = sqlite3PagerOpenWal(pPager, 0);
+- }else if( pPager->journalMode==PAGER_JOURNALMODE_WAL ){
+- pPager->journalMode = PAGER_JOURNALMODE_DELETE;
+- }
++ for(ii=0; ii<pPager->nSavepoint; ii++){
++ PagerSavepoint *p = &pPager->aSavepoint[ii];
++ if( pgno<=p->nOrig ){
++ rc |= sqlite3BitvecSet(p->pInSavepoint, pgno);
++ testcase( rc==SQLITE_NOMEM );
++ assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
+ }
+ }
+ return rc;
+ }
+-#endif
+
+ /*
+-** Playback savepoint pSavepoint. Or, if pSavepoint==NULL, then playback
+-** the entire master journal file. The case pSavepoint==NULL occurs when
+-** a ROLLBACK TO command is invoked on a SAVEPOINT that is a transaction
+-** savepoint.
+-**
+-** When pSavepoint is not NULL (meaning a non-transaction savepoint is
+-** being rolled back), then the rollback consists of up to three stages,
+-** performed in the order specified:
+-**
+-** * Pages are played back from the main journal starting at byte
+-** offset PagerSavepoint.iOffset and continuing to
+-** PagerSavepoint.iHdrOffset, or to the end of the main journal
+-** file if PagerSavepoint.iHdrOffset is zero.
+-**
+-** * If PagerSavepoint.iHdrOffset is not zero, then pages are played
+-** back starting from the journal header immediately following
+-** PagerSavepoint.iHdrOffset to the end of the main journal file.
+-**
+-** * Pages are then played back from the sub-journal file, starting
+-** with the PagerSavepoint.iSubRec and continuing to the end of
+-** the journal file.
+-**
+-** Throughout the rollback process, each time a page is rolled back, the
+-** corresponding bit is set in a bitvec structure (variable pDone in the
+-** implementation below). This is used to ensure that a page is only
+-** rolled back the first time it is encountered in either journal.
++** This function is a no-op if the pager is in exclusive mode and not
++** in the ERROR state. Otherwise, it switches the pager to PAGER_OPEN
++** state.
+ **
+-** If pSavepoint is NULL, then pages are only played back from the main
+-** journal file. There is no need for a bitvec in this case.
++** If the pager is not in exclusive-access mode, the database file is
++** completely unlocked. If the file is unlocked and the file-system does
++** not exhibit the UNDELETABLE_WHEN_OPEN property, the journal file is
++** closed (if it is open).
+ **
+-** In either case, before playback commences the Pager.dbSize variable
+-** is reset to the value that it held at the start of the savepoint
+-** (or transaction). No page with a page-number greater than this value
+-** is played back. If one is encountered it is simply skipped.
++** If the pager is in ERROR state when this function is called, the
++** contents of the pager cache are discarded before switching back to
++** the OPEN state. Regardless of whether the pager is in exclusive-mode
++** or not, any journal file left in the file-system will be treated
++** as a hot-journal and rolled back the next time a read-transaction
++** is opened (by this or by any other connection).
+ */
+-static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){
+- i64 szJ; /* Effective size of the main journal */
+- i64 iHdrOff; /* End of first segment of main-journal records */
+- int rc = SQLITE_OK; /* Return code */
+- Bitvec *pDone = 0; /* Bitvec to ensure pages played back only once */
+-
+- assert( pPager->eState!=PAGER_ERROR );
+- assert( pPager->eState>=PAGER_WRITER_LOCKED );
+-
+- /* Allocate a bitvec to use to store the set of pages rolled back */
+- if( pSavepoint ){
+- pDone = sqlite3BitvecCreate(pSavepoint->nOrig);
+- if( !pDone ){
+- return SQLITE_NOMEM;
+- }
+- }
+-
+- /* Set the database size back to the value it was before the savepoint
+- ** being reverted was opened.
+- */
+- pPager->dbSize = pSavepoint ? pSavepoint->nOrig : pPager->dbOrigSize;
+- pPager->changeCountDone = pPager->tempFile;
+-
+- if( !pSavepoint && pagerUseWal(pPager) ){
+- return pagerRollbackWal(pPager);
+- }
++static void pager_unlock(Pager *pPager){
+
+- /* Use pPager->journalOff as the effective size of the main rollback
+- ** journal. The actual file might be larger than this in
+- ** PAGER_JOURNALMODE_TRUNCATE or PAGER_JOURNALMODE_PERSIST. But anything
+- ** past pPager->journalOff is off-limits to us.
+- */
+- szJ = pPager->journalOff;
+- assert( pagerUseWal(pPager)==0 || szJ==0 );
++ assert( pPager->eState==PAGER_READER
++ || pPager->eState==PAGER_OPEN
++ || pPager->eState==PAGER_ERROR
++ );
+
+- /* Begin by rolling back records from the main journal starting at
+- ** PagerSavepoint.iOffset and continuing to the next journal header.
+- ** There might be records in the main journal that have a page number
+- ** greater than the current database size (pPager->dbSize) but those
+- ** will be skipped automatically. Pages are added to pDone as they
+- ** are played back.
+- */
+- if( pSavepoint && !pagerUseWal(pPager) ){
+- iHdrOff = pSavepoint->iHdrOffset ? pSavepoint->iHdrOffset : szJ;
+- pPager->journalOff = pSavepoint->iOffset;
+- while( rc==SQLITE_OK && pPager->journalOff<iHdrOff ){
+- rc = pager_playback_one_page(pPager, &pPager->journalOff, pDone, 1, 1);
+- }
+- assert( rc!=SQLITE_DONE );
+- }else{
+- pPager->journalOff = 0;
+- }
++ sqlite3BitvecDestroy(pPager->pInJournal);
++ pPager->pInJournal = 0;
++ releaseAllSavepoints(pPager);
+
+- /* Continue rolling back records out of the main journal starting at
+- ** the first journal header seen and continuing until the effective end
+- ** of the main journal file. Continue to skip out-of-range pages and
+- ** continue adding pages rolled back to pDone.
+- */
+- while( rc==SQLITE_OK && pPager->journalOff<szJ ){
+- u32 ii; /* Loop counter */
+- u32 nJRec = 0; /* Number of Journal Records */
+- u32 dummy;
+- rc = readJournalHdr(pPager, 0, szJ, &nJRec, &dummy);
+- assert( rc!=SQLITE_DONE );
++ if( pagerUseWal(pPager) ){
++ assert( !isOpen(pPager->jfd) );
++ sqlite3WalEndReadTransaction(pPager->pWal);
++ pPager->eState = PAGER_OPEN;
++ }else if( !pPager->exclusiveMode ){
++ int rc; /* Error code returned by pagerUnlockDb() */
++ int iDc = isOpen(pPager->fd)?sqlite3OsDeviceCharacteristics(pPager->fd):0;
+
+- /*
+- ** The "pPager->journalHdr+JOURNAL_HDR_SZ(pPager)==pPager->journalOff"
+- ** test is related to ticket #2565. See the discussion in the
+- ** pager_playback() function for additional information.
++ /* If the operating system support deletion of open files, then
++ ** close the journal file when dropping the database lock. Otherwise
++ ** another connection with journal_mode=delete might delete the file
++ ** out from under us.
+ */
+- if( nJRec==0
+- && pPager->journalHdr+JOURNAL_HDR_SZ(pPager)==pPager->journalOff
++ assert( (PAGER_JOURNALMODE_MEMORY & 5)!=1 );
++ assert( (PAGER_JOURNALMODE_OFF & 5)!=1 );
++ assert( (PAGER_JOURNALMODE_WAL & 5)!=1 );
++ assert( (PAGER_JOURNALMODE_DELETE & 5)!=1 );
++ assert( (PAGER_JOURNALMODE_TRUNCATE & 5)==1 );
++ assert( (PAGER_JOURNALMODE_PERSIST & 5)==1 );
++ if( 0==(iDc & SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN)
++ || 1!=(pPager->journalMode & 5)
+ ){
+- nJRec = (u32)((szJ - pPager->journalOff)/JOURNAL_PG_SZ(pPager));
+- }
+- for(ii=0; rc==SQLITE_OK && ii<nJRec && pPager->journalOff<szJ; ii++){
+- rc = pager_playback_one_page(pPager, &pPager->journalOff, pDone, 1, 1);
++ sqlite3OsClose(pPager->jfd);
+ }
+- assert( rc!=SQLITE_DONE );
+- }
+- assert( rc!=SQLITE_OK || pPager->journalOff>=szJ );
+-
+- /* Finally, rollback pages from the sub-journal. Page that were
+- ** previously rolled back out of the main journal (and are hence in pDone)
+- ** will be skipped. Out-of-range pages are also skipped.
+- */
+- if( pSavepoint ){
+- u32 ii; /* Loop counter */
+- i64 offset = (i64)pSavepoint->iSubRec*(4+pPager->pageSize);
+
+- if( pagerUseWal(pPager) ){
+- rc = sqlite3WalSavepointUndo(pPager->pWal, pSavepoint->aWalData);
+- }
+- for(ii=pSavepoint->iSubRec; rc==SQLITE_OK && ii<pPager->nSubRec; ii++){
+- assert( offset==(i64)ii*(4+pPager->pageSize) );
+- rc = pager_playback_one_page(pPager, &offset, pDone, 0, 1);
++ /* If the pager is in the ERROR state and the call to unlock the database
++ ** file fails, set the current lock to UNKNOWN_LOCK. See the comment
++ ** above the #define for UNKNOWN_LOCK for an explanation of why this
++ ** is necessary.
++ */
++ rc = pagerUnlockDb(pPager, NO_LOCK);
++ if( rc!=SQLITE_OK && pPager->eState==PAGER_ERROR ){
++ pPager->eLock = UNKNOWN_LOCK;
+ }
+- assert( rc!=SQLITE_DONE );
+- }
+
+- sqlite3BitvecDestroy(pDone);
+- if( rc==SQLITE_OK ){
+- pPager->journalOff = szJ;
++ /* The pager state may be changed from PAGER_ERROR to PAGER_OPEN here
++ ** without clearing the error code. This is intentional - the error
++ ** code is cleared and the cache reset in the block below.
++ */
++ assert( pPager->errCode || pPager->eState!=PAGER_ERROR );
++ pPager->changeCountDone = 0;
++ pPager->eState = PAGER_OPEN;
+ }
+
+- return rc;
+-}
++ /* If Pager.errCode is set, the contents of the pager cache cannot be
++ ** trusted. Now that there are no outstanding references to the pager,
++ ** it can safely move back to PAGER_OPEN state. This happens in both
++ ** normal and exclusive-locking mode.
++ */
++ if( pPager->errCode ){
++ assert( !MEMDB );
++ pager_reset(pPager);
++ pPager->changeCountDone = pPager->tempFile;
++ pPager->eState = PAGER_OPEN;
++ pPager->errCode = SQLITE_OK;
++ if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0);
++ }
+
+-/*
+-** Change the maximum number of in-memory pages that are allowed.
+-*/
+-SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){
+- sqlite3PcacheSetCachesize(pPager->pPCache, mxPage);
++ pPager->journalOff = 0;
++ pPager->journalHdr = 0;
++ pPager->setMaster = 0;
+ }
+
+ /*
+-** Invoke SQLITE_FCNTL_MMAP_SIZE based on the current value of szMmap.
++** This function is called whenever an IOERR or FULL error that requires
++** the pager to transition into the ERROR state may ahve occurred.
++** The first argument is a pointer to the pager structure, the second
++** the error-code about to be returned by a pager API function. The
++** value returned is a copy of the second argument to this function.
++**
++** If the second argument is SQLITE_FULL, SQLITE_IOERR or one of the
++** IOERR sub-codes, the pager enters the ERROR state and the error code
++** is stored in Pager.errCode. While the pager remains in the ERROR state,
++** all major API calls on the Pager will immediately return Pager.errCode.
++**
++** The ERROR state indicates that the contents of the pager-cache
++** cannot be trusted. This state can be cleared by completely discarding
++** the contents of the pager-cache. If a transaction was active when
++** the persistent error occurred, then the rollback journal may need
++** to be replayed to restore the contents of the database file (as if
++** it were a hot-journal).
+ */
+-static void pagerFixMaplimit(Pager *pPager){
+-#if SQLITE_MAX_MMAP_SIZE>0
+- sqlite3_file *fd = pPager->fd;
+- if( isOpen(fd) && fd->pMethods->iVersion>=3 ){
+- sqlite3_int64 sz;
+- sz = pPager->szMmap;
+- pPager->bUseFetch = (sz>0);
+- sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_MMAP_SIZE, &sz);
++static int pager_error(Pager *pPager, int rc){
++ int rc2 = rc & 0xff;
++ assert( rc==SQLITE_OK || !MEMDB );
++ assert(
++ pPager->errCode==SQLITE_FULL ||
++ pPager->errCode==SQLITE_OK ||
++ (pPager->errCode & 0xff)==SQLITE_IOERR
++ );
++ if( rc2==SQLITE_FULL || rc2==SQLITE_IOERR ){
++ pPager->errCode = rc;
++ pPager->eState = PAGER_ERROR;
+ }
+-#endif
+-}
+-
+-/*
+-** Change the maximum size of any memory mapping made of the database file.
+-*/
+-SQLITE_PRIVATE void sqlite3PagerSetMmapLimit(Pager *pPager, sqlite3_int64 szMmap){
+- pPager->szMmap = szMmap;
+- pagerFixMaplimit(pPager);
++ return rc;
+ }
+
+-/*
+-** Free as much memory as possible from the pager.
+-*/
+-SQLITE_PRIVATE void sqlite3PagerShrink(Pager *pPager){
+- sqlite3PcacheShrink(pPager->pPCache);
+-}
++static int pager_truncate(Pager *pPager, Pgno nPage);
+
+ /*
+-** Adjust settings of the pager to those specified in the pgFlags parameter.
++** This routine ends a transaction. A transaction is usually ended by
++** either a COMMIT or a ROLLBACK operation. This routine may be called
++** after rollback of a hot-journal, or if an error occurs while opening
++** the journal file or writing the very first journal-header of a
++** database transaction.
++**
++** This routine is never called in PAGER_ERROR state. If it is called
++** in PAGER_NONE or PAGER_SHARED state and the lock held is less
++** exclusive than a RESERVED lock, it is a no-op.
+ **
+-** The "level" in pgFlags & PAGER_SYNCHRONOUS_MASK sets the robustness
+-** of the database to damage due to OS crashes or power failures by
+-** changing the number of syncs()s when writing the journals.
+-** There are three levels:
++** Otherwise, any active savepoints are released.
+ **
+-** OFF sqlite3OsSync() is never called. This is the default
+-** for temporary and transient files.
++** If the journal file is open, then it is "finalized". Once a journal
++** file has been finalized it is not possible to use it to roll back a
++** transaction. Nor will it be considered to be a hot-journal by this
++** or any other database connection. Exactly how a journal is finalized
++** depends on whether or not the pager is running in exclusive mode and
++** the current journal-mode (Pager.journalMode value), as follows:
+ **
+-** NORMAL The journal is synced once before writes begin on the
+-** database. This is normally adequate protection, but
+-** it is theoretically possible, though very unlikely,
+-** that an inopertune power failure could leave the journal
+-** in a state which would cause damage to the database
+-** when it is rolled back.
++** journalMode==MEMORY
++** Journal file descriptor is simply closed. This destroys an
++** in-memory journal.
+ **
+-** FULL The journal is synced twice before writes begin on the
+-** database (with some additional information - the nRec field
+-** of the journal header - being written in between the two
+-** syncs). If we assume that writing a
+-** single disk sector is atomic, then this mode provides
+-** assurance that the journal will not be corrupted to the
+-** point of causing damage to the database during rollback.
++** journalMode==TRUNCATE
++** Journal file is truncated to zero bytes in size.
+ **
+-** The above is for a rollback-journal mode. For WAL mode, OFF continues
+-** to mean that no syncs ever occur. NORMAL means that the WAL is synced
+-** prior to the start of checkpoint and that the database file is synced
+-** at the conclusion of the checkpoint if the entire content of the WAL
+-** was written back into the database. But no sync operations occur for
+-** an ordinary commit in NORMAL mode with WAL. FULL means that the WAL
+-** file is synced following each commit operation, in addition to the
+-** syncs associated with NORMAL.
++** journalMode==PERSIST
++** The first 28 bytes of the journal file are zeroed. This invalidates
++** the first journal header in the file, and hence the entire journal
++** file. An invalid journal file cannot be rolled back.
+ **
+-** Do not confuse synchronous=FULL with SQLITE_SYNC_FULL. The
+-** SQLITE_SYNC_FULL macro means to use the MacOSX-style full-fsync
+-** using fcntl(F_FULLFSYNC). SQLITE_SYNC_NORMAL means to do an
+-** ordinary fsync() call. There is no difference between SQLITE_SYNC_FULL
+-** and SQLITE_SYNC_NORMAL on platforms other than MacOSX. But the
+-** synchronous=FULL versus synchronous=NORMAL setting determines when
+-** the xSync primitive is called and is relevant to all platforms.
++** journalMode==DELETE
++** The journal file is closed and deleted using sqlite3OsDelete().
+ **
+-** Numeric values associated with these states are OFF==1, NORMAL=2,
+-** and FULL=3.
++** If the pager is running in exclusive mode, this method of finalizing
++** the journal file is never used. Instead, if the journalMode is
++** DELETE and the pager is in exclusive mode, the method described under
++** journalMode==PERSIST is used instead.
++**
++** After the journal is finalized, the pager moves to PAGER_READER state.
++** If running in non-exclusive rollback mode, the lock on the file is
++** downgraded to a SHARED_LOCK.
++**
++** SQLITE_OK is returned if no error occurs. If an error occurs during
++** any of the IO operations to finalize the journal file or unlock the
++** database then the IO error code is returned to the user. If the
++** operation to finalize the journal file fails, then the code still
++** tries to unlock the database file if not in exclusive mode. If the
++** unlock operation fails as well, then the first error code related
++** to the first error encountered (the journal finalization one) is
++** returned.
+ */
+-#ifndef SQLITE_OMIT_PAGER_PRAGMAS
+-SQLITE_PRIVATE void sqlite3PagerSetFlags(
+- Pager *pPager, /* The pager to set safety level for */
+- unsigned pgFlags /* Various flags */
+-){
+- unsigned level = pgFlags & PAGER_SYNCHRONOUS_MASK;
+- assert( level>=1 && level<=3 );
+- pPager->noSync = (level==1 || pPager->tempFile) ?1:0;
+- pPager->fullSync = (level==3 && !pPager->tempFile) ?1:0;
+- if( pPager->noSync ){
+- pPager->syncFlags = 0;
+- pPager->ckptSyncFlags = 0;
+- }else if( pgFlags & PAGER_FULLFSYNC ){
+- pPager->syncFlags = SQLITE_SYNC_FULL;
+- pPager->ckptSyncFlags = SQLITE_SYNC_FULL;
+- }else if( pgFlags & PAGER_CKPT_FULLFSYNC ){
+- pPager->syncFlags = SQLITE_SYNC_NORMAL;
+- pPager->ckptSyncFlags = SQLITE_SYNC_FULL;
+- }else{
+- pPager->syncFlags = SQLITE_SYNC_NORMAL;
+- pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL;
++static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
++ int rc = SQLITE_OK; /* Error code from journal finalization operation */
++ int rc2 = SQLITE_OK; /* Error code from db file unlock operation */
++
++ /* Do nothing if the pager does not have an open write transaction
++ ** or at least a RESERVED lock. This function may be called when there
++ ** is no write-transaction active but a RESERVED or greater lock is
++ ** held under two circumstances:
++ **
++ ** 1. After a successful hot-journal rollback, it is called with
++ ** eState==PAGER_NONE and eLock==EXCLUSIVE_LOCK.
++ **
++ ** 2. If a connection with locking_mode=exclusive holding an EXCLUSIVE
++ ** lock switches back to locking_mode=normal and then executes a
++ ** read-transaction, this function is called with eState==PAGER_READER
++ ** and eLock==EXCLUSIVE_LOCK when the read-transaction is closed.
++ */
++ assert( assert_pager_state(pPager) );
++ assert( pPager->eState!=PAGER_ERROR );
++ if( pPager->eState<PAGER_WRITER_LOCKED && pPager->eLock<RESERVED_LOCK ){
++ return SQLITE_OK;
+ }
+- pPager->walSyncFlags = pPager->syncFlags;
+- if( pPager->fullSync ){
+- pPager->walSyncFlags |= WAL_SYNC_TRANSACTIONS;
++
++ releaseAllSavepoints(pPager);
++ assert( isOpen(pPager->jfd) || pPager->pInJournal==0 );
++ if( isOpen(pPager->jfd) ){
++ assert( !pagerUseWal(pPager) );
++
++ /* Finalize the journal file. */
++ if( sqlite3IsMemJournal(pPager->jfd) ){
++ assert( pPager->journalMode==PAGER_JOURNALMODE_MEMORY );
++ sqlite3OsClose(pPager->jfd);
++ }else if( pPager->journalMode==PAGER_JOURNALMODE_TRUNCATE ){
++ if( pPager->journalOff==0 ){
++ rc = SQLITE_OK;
++ }else{
++ rc = sqlite3OsTruncate(pPager->jfd, 0);
++ if( rc==SQLITE_OK && pPager->fullSync ){
++ /* Make sure the new file size is written into the inode right away.
++ ** Otherwise the journal might resurrect following a power loss and
++ ** cause the last transaction to roll back. See
++ ** https://bugzilla.mozilla.org/show_bug.cgi?id=1072773
++ */
++ rc = sqlite3OsSync(pPager->jfd, pPager->syncFlags);
++ }
++ }
++ pPager->journalOff = 0;
++ }else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST
++ || (pPager->exclusiveMode && pPager->journalMode!=PAGER_JOURNALMODE_WAL)
++ ){
++ rc = zeroJournalHdr(pPager, hasMaster);
++ pPager->journalOff = 0;
++ }else{
++ /* This branch may be executed with Pager.journalMode==MEMORY if
++ ** a hot-journal was just rolled back. In this case the journal
++ ** file should be closed and deleted. If this connection writes to
++ ** the database file, it will do so using an in-memory journal.
++ */
++ int bDelete = (!pPager->tempFile && sqlite3JournalExists(pPager->jfd));
++ assert( pPager->journalMode==PAGER_JOURNALMODE_DELETE
++ || pPager->journalMode==PAGER_JOURNALMODE_MEMORY
++ || pPager->journalMode==PAGER_JOURNALMODE_WAL
++ );
++ sqlite3OsClose(pPager->jfd);
++ if( bDelete ){
++ rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
++ }
++ }
+ }
+- if( pgFlags & PAGER_CACHESPILL ){
+- pPager->doNotSpill &= ~SPILLFLAG_OFF;
+- }else{
+- pPager->doNotSpill |= SPILLFLAG_OFF;
++
++#ifdef SQLITE_CHECK_PAGES
++ sqlite3PcacheIterateDirty(pPager->pPCache, pager_set_pagehash);
++ if( pPager->dbSize==0 && sqlite3PcacheRefCount(pPager->pPCache)>0 ){
++ PgHdr *p = sqlite3PagerLookup(pPager, 1);
++ if( p ){
++ p->pageHash = 0;
++ sqlite3PagerUnrefNotNull(p);
++ }
++ }
++#endif
++
++ sqlite3BitvecDestroy(pPager->pInJournal);
++ pPager->pInJournal = 0;
++ pPager->nRec = 0;
++ sqlite3PcacheCleanAll(pPager->pPCache);
++ sqlite3PcacheTruncate(pPager->pPCache, pPager->dbSize);
++
++ if( pagerUseWal(pPager) ){
++ /* Drop the WAL write-lock, if any. Also, if the connection was in
++ ** locking_mode=exclusive mode but is no longer, drop the EXCLUSIVE
++ ** lock held on the database file.
++ */
++ rc2 = sqlite3WalEndWriteTransaction(pPager->pWal);
++ assert( rc2==SQLITE_OK );
++ }else if( rc==SQLITE_OK && bCommit && pPager->dbFileSize>pPager->dbSize ){
++ /* This branch is taken when committing a transaction in rollback-journal
++ ** mode if the database file on disk is larger than the database image.
++ ** At this point the journal has been finalized and the transaction
++ ** successfully committed, but the EXCLUSIVE lock is still held on the
++ ** file. So it is safe to truncate the database file to its minimum
++ ** required size. */
++ assert( pPager->eLock==EXCLUSIVE_LOCK );
++ rc = pager_truncate(pPager, pPager->dbSize);
++ }
++
++ if( rc==SQLITE_OK && bCommit && isOpen(pPager->fd) ){
++ rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_COMMIT_PHASETWO, 0);
++ if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
+ }
++
++ if( !pPager->exclusiveMode
++ && (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0))
++ ){
++ rc2 = pagerUnlockDb(pPager, SHARED_LOCK);
++ pPager->changeCountDone = 0;
++ }
++ pPager->eState = PAGER_READER;
++ pPager->setMaster = 0;
++
++ return (rc==SQLITE_OK?rc2:rc);
+ }
+-#endif
+
+ /*
+-** The following global variable is incremented whenever the library
+-** attempts to open a temporary file. This information is used for
+-** testing and analysis only.
++** Execute a rollback if a transaction is active and unlock the
++** database file.
++**
++** If the pager has already entered the ERROR state, do not attempt
++** the rollback at this time. Instead, pager_unlock() is called. The
++** call to pager_unlock() will discard all in-memory pages, unlock
++** the database file and move the pager back to OPEN state. If this
++** means that there is a hot-journal left in the file-system, the next
++** connection to obtain a shared lock on the pager (which may be this one)
++** will roll it back.
++**
++** If the pager has not already entered the ERROR state, but an IO or
++** malloc error occurs during a rollback, then this will itself cause
++** the pager to enter the ERROR state. Which will be cleared by the
++** call to pager_unlock(), as described above.
+ */
+-#ifdef SQLITE_TEST
+-SQLITE_API int sqlite3_opentemp_count = 0;
+-#endif
++static void pagerUnlockAndRollback(Pager *pPager){
++ if( pPager->eState!=PAGER_ERROR && pPager->eState!=PAGER_OPEN ){
++ assert( assert_pager_state(pPager) );
++ if( pPager->eState>=PAGER_WRITER_LOCKED ){
++ sqlite3BeginBenignMalloc();
++ sqlite3PagerRollback(pPager);
++ sqlite3EndBenignMalloc();
++ }else if( !pPager->exclusiveMode ){
++ assert( pPager->eState==PAGER_READER );
++ pager_end_transaction(pPager, 0, 0);
++ }
++ }
++ pager_unlock(pPager);
++}
+
+ /*
+-** Open a temporary file.
++** Parameter aData must point to a buffer of pPager->pageSize bytes
++** of data. Compute and return a checksum based ont the contents of the
++** page of data and the current value of pPager->cksumInit.
+ **
+-** Write the file descriptor into *pFile. Return SQLITE_OK on success
+-** or some other error code if we fail. The OS will automatically
+-** delete the temporary file when it is closed.
++** This is not a real checksum. It is really just the sum of the
++** random initial value (pPager->cksumInit) and every 200th byte
++** of the page data, starting with byte offset (pPager->pageSize%200).
++** Each byte is interpreted as an 8-bit unsigned integer.
+ **
+-** The flags passed to the VFS layer xOpen() call are those specified
+-** by parameter vfsFlags ORed with the following:
++** Changing the formula used to compute this checksum results in an
++** incompatible journal file format.
+ **
+-** SQLITE_OPEN_READWRITE
+-** SQLITE_OPEN_CREATE
+-** SQLITE_OPEN_EXCLUSIVE
+-** SQLITE_OPEN_DELETEONCLOSE
++** If journal corruption occurs due to a power failure, the most likely
++** scenario is that one end or the other of the record will be changed.
++** It is much less likely that the two ends of the journal record will be
++** correct and the middle be corrupt. Thus, this "checksum" scheme,
++** though fast and simple, catches the mostly likely kind of corruption.
+ */
+-static int pagerOpentemp(
+- Pager *pPager, /* The pager object */
+- sqlite3_file *pFile, /* Write the file descriptor here */
+- int vfsFlags /* Flags passed through to the VFS */
+-){
+- int rc; /* Return code */
+-
+-#ifdef SQLITE_TEST
+- sqlite3_opentemp_count++; /* Used for testing and analysis only */
+-#endif
++static u32 pager_cksum(Pager *pPager, const u8 *aData){
++ u32 cksum = pPager->cksumInit; /* Checksum value to return */
++ int i = pPager->pageSize-200; /* Loop counter */
++ while( i>0 ){
++ cksum += aData[i];
++ i -= 200;
++ }
++ return cksum;
++}
+
+- vfsFlags |= SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
+- SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE;
+- rc = sqlite3OsOpen(pPager->pVfs, 0, pFile, vfsFlags, 0);
+- assert( rc!=SQLITE_OK || isOpen(pFile) );
+- return rc;
++/*
++** Report the current page size and number of reserved bytes back
++** to the codec.
++*/
++#ifdef SQLITE_HAS_CODEC
++static void pagerReportSize(Pager *pPager){
++ if( pPager->xCodecSizeChng ){
++ pPager->xCodecSizeChng(pPager->pCodec, pPager->pageSize,
++ (int)pPager->nReserve);
++ }
+ }
++#else
++# define pagerReportSize(X) /* No-op if we do not support a codec */
++#endif
+
+ /*
+-** Set the busy handler function.
++** Read a single page from either the journal file (if isMainJrnl==1) or
++** from the sub-journal (if isMainJrnl==0) and playback that page.
++** The page begins at offset *pOffset into the file. The *pOffset
++** value is increased to the start of the next page in the journal.
+ **
+-** The pager invokes the busy-handler if sqlite3OsLock() returns
+-** SQLITE_BUSY when trying to upgrade from no-lock to a SHARED lock,
+-** or when trying to upgrade from a RESERVED lock to an EXCLUSIVE
+-** lock. It does *not* invoke the busy handler when upgrading from
+-** SHARED to RESERVED, or when upgrading from SHARED to EXCLUSIVE
+-** (which occurs during hot-journal rollback). Summary:
++** The main rollback journal uses checksums - the statement journal does
++** not.
+ **
+-** Transition | Invokes xBusyHandler
+-** --------------------------------------------------------
+-** NO_LOCK -> SHARED_LOCK | Yes
+-** SHARED_LOCK -> RESERVED_LOCK | No
+-** SHARED_LOCK -> EXCLUSIVE_LOCK | No
+-** RESERVED_LOCK -> EXCLUSIVE_LOCK | Yes
++** If the page number of the page record read from the (sub-)journal file
++** is greater than the current value of Pager.dbSize, then playback is
++** skipped and SQLITE_OK is returned.
+ **
+-** If the busy-handler callback returns non-zero, the lock is
+-** retried. If it returns zero, then the SQLITE_BUSY error is
+-** returned to the caller of the pager API function.
++** If pDone is not NULL, then it is a record of pages that have already
++** been played back. If the page at *pOffset has already been played back
++** (if the corresponding pDone bit is set) then skip the playback.
++** Make sure the pDone bit corresponding to the *pOffset page is set
++** prior to returning.
++**
++** If the page record is successfully read from the (sub-)journal file
++** and played back, then SQLITE_OK is returned. If an IO error occurs
++** while reading the record from the (sub-)journal file or while writing
++** to the database file, then the IO error code is returned. If data
++** is successfully read from the (sub-)journal file but appears to be
++** corrupted, SQLITE_DONE is returned. Data is considered corrupted in
++** two circumstances:
++**
++** * If the record page-number is illegal (0 or PAGER_MJ_PGNO), or
++** * If the record is being rolled back from the main journal file
++** and the checksum field does not match the record content.
++**
++** Neither of these two scenarios are possible during a savepoint rollback.
++**
++** If this is a savepoint rollback, then memory may have to be dynamically
++** allocated by this function. If this is the case and an allocation fails,
++** SQLITE_NOMEM is returned.
+ */
+-SQLITE_PRIVATE void sqlite3PagerSetBusyhandler(
+- Pager *pPager, /* Pager object */
+- int (*xBusyHandler)(void *), /* Pointer to busy-handler function */
+- void *pBusyHandlerArg /* Argument to pass to xBusyHandler */
++static int pager_playback_one_page(
++ Pager *pPager, /* The pager being played back */
++ i64 *pOffset, /* Offset of record to playback */
++ Bitvec *pDone, /* Bitvec of pages already played back */
++ int isMainJrnl, /* 1 -> main journal. 0 -> sub-journal. */
++ int isSavepnt /* True for a savepoint rollback */
+ ){
+- pPager->xBusyHandler = xBusyHandler;
+- pPager->pBusyHandlerArg = pBusyHandlerArg;
++ int rc;
++ PgHdr *pPg; /* An existing page in the cache */
++ Pgno pgno; /* The page number of a page in journal */
++ u32 cksum; /* Checksum used for sanity checking */
++ char *aData; /* Temporary storage for the page */
++ sqlite3_file *jfd; /* The file descriptor for the journal file */
++ int isSynced; /* True if journal page is synced */
+
+- if( isOpen(pPager->fd) ){
+- void **ap = (void **)&pPager->xBusyHandler;
+- assert( ((int(*)(void *))(ap[0]))==xBusyHandler );
+- assert( ap[1]==pBusyHandlerArg );
+- sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_BUSYHANDLER, (void *)ap);
++ assert( (isMainJrnl&~1)==0 ); /* isMainJrnl is 0 or 1 */
++ assert( (isSavepnt&~1)==0 ); /* isSavepnt is 0 or 1 */
++ assert( isMainJrnl || pDone ); /* pDone always used on sub-journals */
++ assert( isSavepnt || pDone==0 ); /* pDone never used on non-savepoint */
++
++ aData = pPager->pTmpSpace;
++ assert( aData ); /* Temp storage must have already been allocated */
++ assert( pagerUseWal(pPager)==0 || (!isMainJrnl && isSavepnt) );
++
++ /* Either the state is greater than PAGER_WRITER_CACHEMOD (a transaction
++ ** or savepoint rollback done at the request of the caller) or this is
++ ** a hot-journal rollback. If it is a hot-journal rollback, the pager
++ ** is in state OPEN and holds an EXCLUSIVE lock. Hot-journal rollback
++ ** only reads from the main journal, not the sub-journal.
++ */
++ assert( pPager->eState>=PAGER_WRITER_CACHEMOD
++ || (pPager->eState==PAGER_OPEN && pPager->eLock==EXCLUSIVE_LOCK)
++ );
++ assert( pPager->eState>=PAGER_WRITER_CACHEMOD || isMainJrnl );
++
++ /* Read the page number and page data from the journal or sub-journal
++ ** file. Return an error code to the caller if an IO error occurs.
++ */
++ jfd = isMainJrnl ? pPager->jfd : pPager->sjfd;
++ rc = read32bits(jfd, *pOffset, &pgno);
++ if( rc!=SQLITE_OK ) return rc;
++ rc = sqlite3OsRead(jfd, (u8*)aData, pPager->pageSize, (*pOffset)+4);
++ if( rc!=SQLITE_OK ) return rc;
++ *pOffset += pPager->pageSize + 4 + isMainJrnl*4;
++
++ /* Sanity checking on the page. This is more important that I originally
++ ** thought. If a power failure occurs while the journal is being written,
++ ** it could cause invalid data to be written into the journal. We need to
++ ** detect this invalid data (with high probability) and ignore it.
++ */
++ if( pgno==0 || pgno==PAGER_MJ_PGNO(pPager) ){
++ assert( !isSavepnt );
++ return SQLITE_DONE;
++ }
++ if( pgno>(Pgno)pPager->dbSize || sqlite3BitvecTest(pDone, pgno) ){
++ return SQLITE_OK;
++ }
++ if( isMainJrnl ){
++ rc = read32bits(jfd, (*pOffset)-4, &cksum);
++ if( rc ) return rc;
++ if( !isSavepnt && pager_cksum(pPager, (u8*)aData)!=cksum ){
++ return SQLITE_DONE;
++ }
++ }
++
++ /* If this page has already been played by before during the current
++ ** rollback, then don't bother to play it back again.
++ */
++ if( pDone && (rc = sqlite3BitvecSet(pDone, pgno))!=SQLITE_OK ){
++ return rc;
++ }
++
++ /* When playing back page 1, restore the nReserve setting
++ */
++ if( pgno==1 && pPager->nReserve!=((u8*)aData)[20] ){
++ pPager->nReserve = ((u8*)aData)[20];
++ pagerReportSize(pPager);
++ }
++
++ /* If the pager is in CACHEMOD state, then there must be a copy of this
++ ** page in the pager cache. In this case just update the pager cache,
++ ** not the database file. The page is left marked dirty in this case.
++ **
++ ** An exception to the above rule: If the database is in no-sync mode
++ ** and a page is moved during an incremental vacuum then the page may
++ ** not be in the pager cache. Later: if a malloc() or IO error occurs
++ ** during a Movepage() call, then the page may not be in the cache
++ ** either. So the condition described in the above paragraph is not
++ ** assert()able.
++ **
++ ** If in WRITER_DBMOD, WRITER_FINISHED or OPEN state, then we update the
++ ** pager cache if it exists and the main file. The page is then marked
++ ** not dirty. Since this code is only executed in PAGER_OPEN state for
++ ** a hot-journal rollback, it is guaranteed that the page-cache is empty
++ ** if the pager is in OPEN state.
++ **
++ ** Ticket #1171: The statement journal might contain page content that is
++ ** different from the page content at the start of the transaction.
++ ** This occurs when a page is changed prior to the start of a statement
++ ** then changed again within the statement. When rolling back such a
++ ** statement we must not write to the original database unless we know
++ ** for certain that original page contents are synced into the main rollback
++ ** journal. Otherwise, a power loss might leave modified data in the
++ ** database file without an entry in the rollback journal that can
++ ** restore the database to its original form. Two conditions must be
++ ** met before writing to the database files. (1) the database must be
++ ** locked. (2) we know that the original page content is fully synced
++ ** in the main journal either because the page is not in cache or else
++ ** the page is marked as needSync==0.
++ **
++ ** 2008-04-14: When attempting to vacuum a corrupt database file, it
++ ** is possible to fail a statement on a database that does not yet exist.
++ ** Do not attempt to write if database file has never been opened.
++ */
++ if( pagerUseWal(pPager) ){
++ pPg = 0;
++ }else{
++ pPg = sqlite3PagerLookup(pPager, pgno);
++ }
++ assert( pPg || !MEMDB );
++ assert( pPager->eState!=PAGER_OPEN || pPg==0 );
++ PAGERTRACE(("PLAYBACK %d page %d hash(%08x) %s\n",
++ PAGERID(pPager), pgno, pager_datahash(pPager->pageSize, (u8*)aData),
++ (isMainJrnl?"main-journal":"sub-journal")
++ ));
++ if( isMainJrnl ){
++ isSynced = pPager->noSync || (*pOffset <= pPager->journalHdr);
++ }else{
++ isSynced = (pPg==0 || 0==(pPg->flags & PGHDR_NEED_SYNC));
++ }
++ if( isOpen(pPager->fd)
++ && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN)
++ && isSynced
++ ){
++ i64 ofst = (pgno-1)*(i64)pPager->pageSize;
++ testcase( !isSavepnt && pPg!=0 && (pPg->flags&PGHDR_NEED_SYNC)!=0 );
++ assert( !pagerUseWal(pPager) );
++ rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst);
++ if( pgno>pPager->dbFileSize ){
++ pPager->dbFileSize = pgno;
++ }
++ if( pPager->pBackup ){
++ CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM);
++ sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData);
++ CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM, aData);
++ }
++ }else if( !isMainJrnl && pPg==0 ){
++ /* If this is a rollback of a savepoint and data was not written to
++ ** the database and the page is not in-memory, there is a potential
++ ** problem. When the page is next fetched by the b-tree layer, it
++ ** will be read from the database file, which may or may not be
++ ** current.
++ **
++ ** There are a couple of different ways this can happen. All are quite
++ ** obscure. When running in synchronous mode, this can only happen
++ ** if the page is on the free-list at the start of the transaction, then
++ ** populated, then moved using sqlite3PagerMovepage().
++ **
++ ** The solution is to add an in-memory page to the cache containing
++ ** the data just read from the sub-journal. Mark the page as dirty
++ ** and if the pager requires a journal-sync, then mark the page as
++ ** requiring a journal-sync before it is written.
++ */
++ assert( isSavepnt );
++ assert( (pPager->doNotSpill & SPILLFLAG_ROLLBACK)==0 );
++ pPager->doNotSpill |= SPILLFLAG_ROLLBACK;
++ rc = sqlite3PagerAcquire(pPager, pgno, &pPg, 1);
++ assert( (pPager->doNotSpill & SPILLFLAG_ROLLBACK)!=0 );
++ pPager->doNotSpill &= ~SPILLFLAG_ROLLBACK;
++ if( rc!=SQLITE_OK ) return rc;
++ pPg->flags &= ~PGHDR_NEED_READ;
++ sqlite3PcacheMakeDirty(pPg);
++ }
++ if( pPg ){
++ /* No page should ever be explicitly rolled back that is in use, except
++ ** for page 1 which is held in use in order to keep the lock on the
++ ** database active. However such a page may be rolled back as a result
++ ** of an internal error resulting in an automatic call to
++ ** sqlite3PagerRollback().
++ */
++ void *pData;
++ pData = pPg->pData;
++ memcpy(pData, (u8*)aData, pPager->pageSize);
++ pPager->xReiniter(pPg);
++ if( isMainJrnl && (!isSavepnt || *pOffset<=pPager->journalHdr) ){
++ /* If the contents of this page were just restored from the main
++ ** journal file, then its content must be as they were when the
++ ** transaction was first opened. In this case we can mark the page
++ ** as clean, since there will be no need to write it out to the
++ ** database.
++ **
++ ** There is one exception to this rule. If the page is being rolled
++ ** back as part of a savepoint (or statement) rollback from an
++ ** unsynced portion of the main journal file, then it is not safe
++ ** to mark the page as clean. This is because marking the page as
++ ** clean will clear the PGHDR_NEED_SYNC flag. Since the page is
++ ** already in the journal file (recorded in Pager.pInJournal) and
++ ** the PGHDR_NEED_SYNC flag is cleared, if the page is written to
++ ** again within this transaction, it will be marked as dirty but
++ ** the PGHDR_NEED_SYNC flag will not be set. It could then potentially
++ ** be written out into the database file before its journal file
++ ** segment is synced. If a crash occurs during or following this,
++ ** database corruption may ensue.
++ */
++ assert( !pagerUseWal(pPager) );
++ sqlite3PcacheMakeClean(pPg);
++ }
++ pager_set_pagehash(pPg);
++
++ /* If this was page 1, then restore the value of Pager.dbFileVers.
++ ** Do this before any decoding. */
++ if( pgno==1 ){
++ memcpy(&pPager->dbFileVers, &((u8*)pData)[24],sizeof(pPager->dbFileVers));
++ }
++
++ /* Decode the page just read from disk */
++ CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM);
++ sqlite3PcacheRelease(pPg);
+ }
++ return rc;
+ }
+
+ /*
+-** Change the page size used by the Pager object. The new page size
+-** is passed in *pPageSize.
++** Parameter zMaster is the name of a master journal file. A single journal
++** file that referred to the master journal file has just been rolled back.
++** This routine checks if it is possible to delete the master journal file,
++** and does so if it is.
+ **
+-** If the pager is in the error state when this function is called, it
+-** is a no-op. The value returned is the error state error code (i.e.
+-** one of SQLITE_IOERR, an SQLITE_IOERR_xxx sub-code or SQLITE_FULL).
++** Argument zMaster may point to Pager.pTmpSpace. So that buffer is not
++** available for use within this function.
+ **
+-** Otherwise, if all of the following are true:
++** When a master journal file is created, it is populated with the names
++** of all of its child journals, one after another, formatted as utf-8
++** encoded text. The end of each child journal file is marked with a
++** nul-terminator byte (0x00). i.e. the entire contents of a master journal
++** file for a transaction involving two databases might be:
+ **
+-** * the new page size (value of *pPageSize) is valid (a power
+-** of two between 512 and SQLITE_MAX_PAGE_SIZE, inclusive), and
++** "/home/bill/a.db-journal\x00/home/bill/b.db-journal\x00"
+ **
+-** * there are no outstanding page references, and
++** A master journal file may only be deleted once all of its child
++** journals have been rolled back.
+ **
+-** * the database is either not an in-memory database or it is
+-** an in-memory database that currently consists of zero pages.
++** This function reads the contents of the master-journal file into
++** memory and loops through each of the child journal names. For
++** each child journal, it checks if:
+ **
+-** then the pager object page size is set to *pPageSize.
++** * if the child journal exists, and if so
++** * if the child journal contains a reference to master journal
++** file zMaster
+ **
+-** If the page size is changed, then this function uses sqlite3PagerMalloc()
+-** to obtain a new Pager.pTmpSpace buffer. If this allocation attempt
+-** fails, SQLITE_NOMEM is returned and the page size remains unchanged.
+-** In all other cases, SQLITE_OK is returned.
++** If a child journal can be found that matches both of the criteria
++** above, this function returns without doing anything. Otherwise, if
++** no such child journal can be found, file zMaster is deleted from
++** the file-system using sqlite3OsDelete().
+ **
+-** If the page size is not changed, either because one of the enumerated
+-** conditions above is not true, the pager was in error state when this
+-** function was called, or because the memory allocation attempt failed,
+-** then *pPageSize is set to the old, retained page size before returning.
++** If an IO error within this function, an error code is returned. This
++** function allocates memory by calling sqlite3Malloc(). If an allocation
++** fails, SQLITE_NOMEM is returned. Otherwise, if no IO or malloc errors
++** occur, SQLITE_OK is returned.
++**
++** TODO: This function allocates a single block of memory to load
++** the entire contents of the master journal file. This could be
++** a couple of kilobytes or so - potentially larger than the page
++** size.
+ */
+-SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nReserve){
+- int rc = SQLITE_OK;
++static int pager_delmaster(Pager *pPager, const char *zMaster){
++ sqlite3_vfs *pVfs = pPager->pVfs;
++ int rc; /* Return code */
++ sqlite3_file *pMaster; /* Malloc'd master-journal file descriptor */
++ sqlite3_file *pJournal; /* Malloc'd child-journal file descriptor */
++ char *zMasterJournal = 0; /* Contents of master journal file */
++ i64 nMasterJournal; /* Size of master journal file */
++ char *zJournal; /* Pointer to one journal within MJ file */
++ char *zMasterPtr; /* Space to hold MJ filename from a journal file */
++ int nMasterPtr; /* Amount of space allocated to zMasterPtr[] */
+
+- /* It is not possible to do a full assert_pager_state() here, as this
+- ** function may be called from within PagerOpen(), before the state
+- ** of the Pager object is internally consistent.
+- **
+- ** At one point this function returned an error if the pager was in
+- ** PAGER_ERROR state. But since PAGER_ERROR state guarantees that
+- ** there is at least one outstanding page reference, this function
+- ** is a no-op for that case anyhow.
++ /* Allocate space for both the pJournal and pMaster file descriptors.
++ ** If successful, open the master journal file for reading.
+ */
++ pMaster = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2);
++ pJournal = (sqlite3_file *)(((u8 *)pMaster) + pVfs->szOsFile);
++ if( !pMaster ){
++ rc = SQLITE_NOMEM;
++ }else{
++ const int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MASTER_JOURNAL);
++ rc = sqlite3OsOpen(pVfs, zMaster, pMaster, flags, 0);
++ }
++ if( rc!=SQLITE_OK ) goto delmaster_out;
+
+- u32 pageSize = *pPageSize;
+- assert( pageSize==0 || (pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE) );
+- if( (pPager->memDb==0 || pPager->dbSize==0)
+- && sqlite3PcacheRefCount(pPager->pPCache)==0
+- && pageSize && pageSize!=(u32)pPager->pageSize
+- ){
+- char *pNew = NULL; /* New temp space */
+- i64 nByte = 0;
++ /* Load the entire master journal file into space obtained from
++ ** sqlite3_malloc() and pointed to by zMasterJournal. Also obtain
++ ** sufficient space (in zMasterPtr) to hold the names of master
++ ** journal files extracted from regular rollback-journals.
++ */
++ rc = sqlite3OsFileSize(pMaster, &nMasterJournal);
++ if( rc!=SQLITE_OK ) goto delmaster_out;
++ nMasterPtr = pVfs->mxPathname+1;
++ zMasterJournal = sqlite3Malloc(nMasterJournal + nMasterPtr + 1);
++ if( !zMasterJournal ){
++ rc = SQLITE_NOMEM;
++ goto delmaster_out;
++ }
++ zMasterPtr = &zMasterJournal[nMasterJournal+1];
++ rc = sqlite3OsRead(pMaster, zMasterJournal, (int)nMasterJournal, 0);
++ if( rc!=SQLITE_OK ) goto delmaster_out;
++ zMasterJournal[nMasterJournal] = 0;
+
+- if( pPager->eState>PAGER_OPEN && isOpen(pPager->fd) ){
+- rc = sqlite3OsFileSize(pPager->fd, &nByte);
+- }
+- if( rc==SQLITE_OK ){
+- pNew = (char *)sqlite3PageMalloc(pageSize);
+- if( !pNew ) rc = SQLITE_NOMEM;
++ zJournal = zMasterJournal;
++ while( (zJournal-zMasterJournal)<nMasterJournal ){
++ int exists;
++ rc = sqlite3OsAccess(pVfs, zJournal, SQLITE_ACCESS_EXISTS, &exists);
++ if( rc!=SQLITE_OK ){
++ goto delmaster_out;
+ }
++ if( exists ){
++ /* 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.
++ */
++ int c;
++ int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL);
++ rc = sqlite3OsOpen(pVfs, zJournal, pJournal, flags, 0);
++ if( rc!=SQLITE_OK ){
++ goto delmaster_out;
++ }
++
++ rc = readMasterJournal(pJournal, zMasterPtr, nMasterPtr);
++ sqlite3OsClose(pJournal);
++ if( rc!=SQLITE_OK ){
++ goto delmaster_out;
++ }
+
+- if( rc==SQLITE_OK ){
+- pager_reset(pPager);
+- rc = sqlite3PcacheSetPageSize(pPager->pPCache, pageSize);
+- }
+- if( rc==SQLITE_OK ){
+- sqlite3PageFree(pPager->pTmpSpace);
+- pPager->pTmpSpace = pNew;
+- pPager->dbSize = (Pgno)((nByte+pageSize-1)/pageSize);
+- pPager->pageSize = pageSize;
+- }else{
+- sqlite3PageFree(pNew);
++ c = zMasterPtr[0]!=0 && strcmp(zMasterPtr, zMaster)==0;
++ if( c ){
++ /* We have a match. Do not delete the master journal file. */
++ goto delmaster_out;
++ }
+ }
++ zJournal += (sqlite3Strlen30(zJournal)+1);
+ }
++
++ sqlite3OsClose(pMaster);
++ rc = sqlite3OsDelete(pVfs, zMaster, 0);
+
+- *pPageSize = pPager->pageSize;
+- if( rc==SQLITE_OK ){
+- if( nReserve<0 ) nReserve = pPager->nReserve;
+- assert( nReserve>=0 && nReserve<1000 );
+- pPager->nReserve = (i16)nReserve;
+- pagerReportSize(pPager);
+- pagerFixMaplimit(pPager);
++delmaster_out:
++ sqlite3_free(zMasterJournal);
++ if( pMaster ){
++ sqlite3OsClose(pMaster);
++ assert( !isOpen(pJournal) );
++ sqlite3_free(pMaster);
+ }
+ return rc;
+ }
+
+-/*
+-** Return a pointer to the "temporary page" buffer held internally
+-** by the pager. This is a buffer that is big enough to hold the
+-** entire content of a database page. This buffer is used internally
+-** during rollback and will be overwritten whenever a rollback
+-** occurs. But other modules are free to use it too, as long as
+-** no rollbacks are happening.
+-*/
+-SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager *pPager){
+- return pPager->pTmpSpace;
+-}
+-
+-/*
+-** Attempt to set the maximum database page count if mxPage is positive.
+-** Make no changes if mxPage is zero or negative. And never reduce the
+-** maximum page count below the current size of the database.
+-**
+-** Regardless of mxPage, return the current maximum page count.
+-*/
+-SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager *pPager, int mxPage){
+- if( mxPage>0 ){
+- pPager->mxPgno = mxPage;
+- }
+- assert( pPager->eState!=PAGER_OPEN ); /* Called only by OP_MaxPgcnt */
+- assert( pPager->mxPgno>=pPager->dbSize ); /* OP_MaxPgcnt enforces this */
+- return pPager->mxPgno;
+-}
+
+ /*
+-** The following set of routines are used to disable the simulated
+-** I/O error mechanism. These routines are used to avoid simulated
+-** errors in places where we do not care about errors.
++** This function is used to change the actual size of the database
++** file in the file-system. This only happens when committing a transaction,
++** or rolling back a transaction (including rolling back a hot-journal).
+ **
+-** Unless -DSQLITE_TEST=1 is used, these routines are all no-ops
+-** and generate no code.
+-*/
+-#ifdef SQLITE_TEST
+-SQLITE_API extern int sqlite3_io_error_pending;
+-SQLITE_API extern int sqlite3_io_error_hit;
+-static int saved_cnt;
+-void disable_simulated_io_errors(void){
+- saved_cnt = sqlite3_io_error_pending;
+- sqlite3_io_error_pending = -1;
+-}
+-void enable_simulated_io_errors(void){
+- sqlite3_io_error_pending = saved_cnt;
+-}
+-#else
+-# define disable_simulated_io_errors()
+-# define enable_simulated_io_errors()
+-#endif
+-
+-/*
+-** Read the first N bytes from the beginning of the file into memory
+-** that pDest points to.
++** If the main database file is not open, or the pager is not in either
++** DBMOD or OPEN state, this function is a no-op. Otherwise, the size
++** of the file is changed to nPage pages (nPage*pPager->pageSize bytes).
++** If the file on disk is currently larger than nPage pages, then use the VFS
++** xTruncate() method to truncate it.
+ **
+-** If the pager was opened on a transient file (zFilename==""), or
+-** opened on a file less than N bytes in size, the output buffer is
+-** zeroed and SQLITE_OK returned. The rationale for this is that this
+-** function is used to read database headers, and a new transient or
+-** zero sized database has a header than consists entirely of zeroes.
++** Or, it might be the case that the file on disk is smaller than
++** nPage pages. Some operating system implementations can get confused if
++** you try to truncate a file to some size that is larger than it
++** currently is, so detect this case and write a single zero byte to
++** the end of the new file instead.
+ **
+-** If any IO error apart from SQLITE_IOERR_SHORT_READ is encountered,
+-** the error code is returned to the caller and the contents of the
+-** output buffer undefined.
++** If successful, return SQLITE_OK. If an IO error occurs while modifying
++** the database file, return the error code to the caller.
+ */
+-SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager *pPager, int N, unsigned char *pDest){
++static int pager_truncate(Pager *pPager, Pgno nPage){
+ int rc = SQLITE_OK;
+- memset(pDest, 0, N);
+- assert( isOpen(pPager->fd) || pPager->tempFile );
+-
+- /* This routine is only called by btree immediately after creating
+- ** the Pager object. There has not been an opportunity to transition
+- ** to WAL mode yet.
+- */
+- assert( !pagerUseWal(pPager) );
+-
+- if( isOpen(pPager->fd) ){
+- IOTRACE(("DBHDR %p 0 %d\n", pPager, N))
+- rc = sqlite3OsRead(pPager->fd, pDest, N, 0);
+- if( rc==SQLITE_IOERR_SHORT_READ ){
+- rc = SQLITE_OK;
++ assert( pPager->eState!=PAGER_ERROR );
++ assert( pPager->eState!=PAGER_READER );
++
++ if( isOpen(pPager->fd)
++ && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN)
++ ){
++ i64 currentSize, newSize;
++ int szPage = pPager->pageSize;
++ assert( pPager->eLock==EXCLUSIVE_LOCK );
++ /* TODO: Is it safe to use Pager.dbFileSize here? */
++ rc = sqlite3OsFileSize(pPager->fd, ¤tSize);
++ newSize = szPage*(i64)nPage;
++ if( rc==SQLITE_OK && currentSize!=newSize ){
++ if( currentSize>newSize ){
++ rc = sqlite3OsTruncate(pPager->fd, newSize);
++ }else if( (currentSize+szPage)<=newSize ){
++ char *pTmp = pPager->pTmpSpace;
++ memset(pTmp, 0, szPage);
++ testcase( (newSize-szPage) == currentSize );
++ testcase( (newSize-szPage) > currentSize );
++ rc = sqlite3OsWrite(pPager->fd, pTmp, szPage, newSize-szPage);
++ }
++ if( rc==SQLITE_OK ){
++ pPager->dbFileSize = nPage;
++ }
+ }
+ }
+ return rc;
+ }
+
+ /*
+-** This function may only be called when a read-transaction is open on
+-** the pager. It returns the total number of pages in the database.
+-**
+-** However, if the file is between 1 and <page-size> bytes in size, then
+-** this is considered a 1 page file.
++** Return a sanitized version of the sector-size of OS file pFile. The
++** return value is guaranteed to lie between 32 and MAX_SECTOR_SIZE.
+ */
+-SQLITE_PRIVATE void sqlite3PagerPagecount(Pager *pPager, int *pnPage){
+- assert( pPager->eState>=PAGER_READER );
+- assert( pPager->eState!=PAGER_WRITER_FINISHED );
+- *pnPage = (int)pPager->dbSize;
++SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *pFile){
++ int iRet = sqlite3OsSectorSize(pFile);
++ if( iRet<32 ){
++ iRet = 512;
++ }else if( iRet>MAX_SECTOR_SIZE ){
++ assert( MAX_SECTOR_SIZE>=512 );
++ iRet = MAX_SECTOR_SIZE;
++ }
++ return iRet;
+ }
+
+-
+ /*
+-** Try to obtain a lock of type locktype on the database file. If
+-** a similar or greater lock is already held, this function is a no-op
+-** (returning SQLITE_OK immediately).
++** Set the value of the Pager.sectorSize variable for the given
++** pager based on the value returned by the xSectorSize method
++** of the open database file. The sector size will be used
++** to determine the size and alignment of journal header and
++** master journal pointers within created journal files.
+ **
+-** Otherwise, attempt to obtain the lock using sqlite3OsLock(). Invoke
+-** the busy callback if the lock is currently not available. Repeat
+-** until the busy callback returns false or until the attempt to
+-** obtain the lock succeeds.
++** For temporary files the effective sector size is always 512 bytes.
+ **
+-** Return SQLITE_OK on success and an error code if we cannot obtain
+-** the lock. If the lock is obtained successfully, set the Pager.state
+-** variable to locktype before returning.
++** Otherwise, for non-temporary files, the effective sector size is
++** the value returned by the xSectorSize() method rounded up to 32 if
++** it is less than 32, or rounded down to MAX_SECTOR_SIZE if it
++** is greater than MAX_SECTOR_SIZE.
++**
++** If the file has the SQLITE_IOCAP_POWERSAFE_OVERWRITE property, then set
++** the effective sector size to its minimum value (512). The purpose of
++** pPager->sectorSize is to define the "blast radius" of bytes that
++** might change if a crash occurs while writing to a single byte in
++** that range. But with POWERSAFE_OVERWRITE, the blast radius is zero
++** (that is what POWERSAFE_OVERWRITE means), so we minimize the sector
++** size. For backwards compatibility of the rollback journal file format,
++** we cannot reduce the effective sector size below 512.
+ */
+-static int pager_wait_on_lock(Pager *pPager, int locktype){
+- int rc; /* Return code */
+-
+- /* Check that this is either a no-op (because the requested lock is
+- ** already held), or one of the transitions that the busy-handler
+- ** may be invoked during, according to the comment above
+- ** sqlite3PagerSetBusyhandler().
+- */
+- assert( (pPager->eLock>=locktype)
+- || (pPager->eLock==NO_LOCK && locktype==SHARED_LOCK)
+- || (pPager->eLock==RESERVED_LOCK && locktype==EXCLUSIVE_LOCK)
+- );
++static void setSectorSize(Pager *pPager){
++ assert( isOpen(pPager->fd) || pPager->tempFile );
+
+- do {
+- rc = pagerLockDb(pPager, locktype);
+- }while( rc==SQLITE_BUSY && pPager->xBusyHandler(pPager->pBusyHandlerArg) );
+- return rc;
++ if( pPager->tempFile
++ || (sqlite3OsDeviceCharacteristics(pPager->fd) &
++ SQLITE_IOCAP_POWERSAFE_OVERWRITE)!=0
++ ){
++ /* Sector size doesn't matter for temporary files. Also, the file
++ ** may not have been opened yet, in which case the OsSectorSize()
++ ** call will segfault. */
++ pPager->sectorSize = 512;
++ }else{
++ pPager->sectorSize = sqlite3SectorSize(pPager->fd);
++ }
+ }
+
+ /*
+-** Function assertTruncateConstraint(pPager) checks that one of the
+-** following is true for all dirty pages currently in the page-cache:
++** Playback the journal and thus restore the database file to
++** the state it was in before we started making changes.
+ **
+-** a) The page number is less than or equal to the size of the
+-** current database image, in pages, OR
++** The journal file format is as follows:
+ **
+-** b) if the page content were written at this time, it would not
+-** be necessary to write the current content out to the sub-journal
+-** (as determined by function subjRequiresPage()).
++** (1) 8 byte prefix. A copy of aJournalMagic[].
++** (2) 4 byte big-endian integer which is the number of valid page records
++** in the journal. If this value is 0xffffffff, then compute the
++** number of page records from the journal size.
++** (3) 4 byte big-endian integer which is the initial value for the
++** sanity checksum.
++** (4) 4 byte integer which is the number of pages to truncate the
++** database to during a rollback.
++** (5) 4 byte big-endian integer which is the sector size. The header
++** is this many bytes in size.
++** (6) 4 byte big-endian integer which is the page size.
++** (7) zero padding out to the next sector size.
++** (8) Zero or more pages instances, each as follows:
++** + 4 byte page number.
++** + pPager->pageSize bytes of data.
++** + 4 byte checksum
+ **
+-** If the condition asserted by this function were not true, and the
+-** dirty page were to be discarded from the cache via the pagerStress()
+-** routine, pagerStress() would not write the current page content to
+-** the database file. If a savepoint transaction were rolled back after
+-** this happened, the correct behavior would be to restore the current
+-** content of the page. However, since this content is not present in either
+-** the database file or the portion of the rollback journal and
+-** sub-journal rolled back the content could not be restored and the
+-** database image would become corrupt. It is therefore fortunate that
+-** this circumstance cannot arise.
+-*/
+-#if defined(SQLITE_DEBUG)
+-static void assertTruncateConstraintCb(PgHdr *pPg){
+- assert( pPg->flags&PGHDR_DIRTY );
+- assert( !subjRequiresPage(pPg) || pPg->pgno<=pPg->pPager->dbSize );
+-}
+-static void assertTruncateConstraint(Pager *pPager){
+- sqlite3PcacheIterateDirty(pPager->pPCache, assertTruncateConstraintCb);
+-}
+-#else
+-# define assertTruncateConstraint(pPager)
+-#endif
+-
+-/*
+-** Truncate the in-memory database file image to nPage pages. This
+-** function does not actually modify the database file on disk. It
+-** just sets the internal state of the pager object so that the
+-** truncation will be done when the current transaction is committed.
++** When we speak of the journal header, we mean the first 7 items above.
++** Each entry in the journal is an instance of the 8th item.
+ **
+-** This function is only called right before committing a transaction.
+-** Once this function has been called, the transaction must either be
+-** rolled back or committed. It is not safe to call this function and
+-** then continue writing to the database.
+-*/
+-SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){
+- assert( pPager->dbSize>=nPage );
+- assert( pPager->eState>=PAGER_WRITER_CACHEMOD );
+- pPager->dbSize = nPage;
+-
+- /* At one point the code here called assertTruncateConstraint() to
+- ** ensure that all pages being truncated away by this operation are,
+- ** if one or more savepoints are open, present in the savepoint
+- ** journal so that they can be restored if the savepoint is rolled
+- ** back. This is no longer necessary as this function is now only
+- ** called right before committing a transaction. So although the
+- ** Pager object may still have open savepoints (Pager.nSavepoint!=0),
+- ** they cannot be rolled back. So the assertTruncateConstraint() call
+- ** is no longer correct. */
+-}
+-
+-
+-/*
+-** This function is called before attempting a hot-journal rollback. It
+-** syncs the journal file to disk, then sets pPager->journalHdr to the
+-** size of the journal file so that the pager_playback() routine knows
+-** that the entire journal file has been synced.
++** Call the value from the second bullet "nRec". nRec is the number of
++** valid page entries in the journal. In most cases, you can compute the
++** value of nRec from the size of the journal file. But if a power
++** failure occurred while the journal was being written, it could be the
++** case that the size of the journal file had already been increased but
++** the extra entries had not yet made it safely to disk. In such a case,
++** the value of nRec computed from the file size would be too large. For
++** that reason, we always use the nRec value in the header.
+ **
+-** Syncing a hot-journal to disk before attempting to roll it back ensures
+-** that if a power-failure occurs during the rollback, the process that
+-** attempts rollback following system recovery sees the same journal
+-** content as this process.
++** If the nRec value is 0xffffffff it means that nRec should be computed
++** from the file size. This value is used when the user selects the
++** no-sync option for the journal. A power failure could lead to corruption
++** in this case. But for things like temporary table (which will be
++** deleted when the power is restored) we don't care.
+ **
+-** If everything goes as planned, SQLITE_OK is returned. Otherwise,
+-** an SQLite error code.
++** If the file opened as the journal file is not a well-formed
++** journal file then all pages up to the first corrupted page are rolled
++** back (or no pages if the journal header is corrupted). The journal file
++** is then deleted and SQLITE_OK returned, just as if no corruption had
++** been encountered.
++**
++** If an I/O or malloc() error occurs, the journal-file is not deleted
++** and an error code is returned.
++**
++** The isHot parameter indicates that we are trying to rollback a journal
++** that might be a hot journal. Or, it could be that the journal is
++** preserved because of JOURNALMODE_PERSIST or JOURNALMODE_TRUNCATE.
++** If the journal really is hot, reset the pager cache prior rolling
++** back any content. If the journal is merely persistent, no reset is
++** needed.
+ */
+-static int pagerSyncHotJournal(Pager *pPager){
+- int rc = SQLITE_OK;
+- if( !pPager->noSync ){
+- rc = sqlite3OsSync(pPager->jfd, SQLITE_SYNC_NORMAL);
++static int pager_playback(Pager *pPager, int isHot){
++ sqlite3_vfs *pVfs = pPager->pVfs;
++ i64 szJ; /* Size of the journal file in bytes */
++ u32 nRec; /* Number of Records in the journal */
++ u32 u; /* Unsigned loop counter */
++ Pgno mxPg = 0; /* Size of the original file in pages */
++ int rc; /* Result code of a subroutine */
++ int res = 1; /* Value returned by sqlite3OsAccess() */
++ char *zMaster = 0; /* Name of master journal file if any */
++ int needPagerReset; /* True to reset page prior to first page rollback */
++ int nPlayback = 0; /* Total number of pages restored from journal */
++
++ /* Figure out how many records are in the journal. Abort early if
++ ** the journal is empty.
++ */
++ assert( isOpen(pPager->jfd) );
++ rc = sqlite3OsFileSize(pPager->jfd, &szJ);
++ if( rc!=SQLITE_OK ){
++ goto end_playback;
+ }
+- if( rc==SQLITE_OK ){
+- rc = sqlite3OsFileSize(pPager->jfd, &pPager->journalHdr);
++
++ /* Read the master journal name from the journal, if it is present.
++ ** If a master journal file name is specified, but the file is not
++ ** present on disk, then the journal is not hot and does not need to be
++ ** played back.
++ **
++ ** TODO: Technically the following is an error because it assumes that
++ ** buffer Pager.pTmpSpace is (mxPathname+1) bytes or larger. i.e. that
++ ** (pPager->pageSize >= pPager->pVfs->mxPathname+1). Using os_unix.c,
++ ** mxPathname is 512, which is the same as the minimum allowable value
++ ** for pageSize.
++ */
++ zMaster = pPager->pTmpSpace;
++ rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1);
++ if( rc==SQLITE_OK && zMaster[0] ){
++ rc = sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS, &res);
+ }
+- return rc;
+-}
++ zMaster = 0;
++ if( rc!=SQLITE_OK || !res ){
++ goto end_playback;
++ }
++ pPager->journalOff = 0;
++ needPagerReset = isHot;
+
+-/*
+-** Obtain a reference to a memory mapped page object for page number pgno.
+-** The new object will use the pointer pData, obtained from xFetch().
+-** If successful, set *ppPage to point to the new page reference
+-** and return SQLITE_OK. Otherwise, return an SQLite error code and set
+-** *ppPage to zero.
+-**
+-** Page references obtained by calling this function should be released
+-** by calling pagerReleaseMapPage().
+-*/
+-static int pagerAcquireMapPage(
+- Pager *pPager, /* Pager object */
+- Pgno pgno, /* Page number */
+- void *pData, /* xFetch()'d data for this page */
+- PgHdr **ppPage /* OUT: Acquired page object */
+-){
+- PgHdr *p; /* Memory mapped page to return */
+-
+- if( pPager->pMmapFreelist ){
+- *ppPage = p = pPager->pMmapFreelist;
+- pPager->pMmapFreelist = p->pDirty;
+- p->pDirty = 0;
+- memset(p->pExtra, 0, pPager->nExtra);
+- }else{
+- *ppPage = p = (PgHdr *)sqlite3MallocZero(sizeof(PgHdr) + pPager->nExtra);
+- if( p==0 ){
+- sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1) * pPager->pageSize, pData);
+- return SQLITE_NOMEM;
++ /* This loop terminates either when a readJournalHdr() or
++ ** pager_playback_one_page() call returns SQLITE_DONE or an IO error
++ ** occurs.
++ */
++ while( 1 ){
++ /* Read the next journal header from the journal file. If there are
++ ** not enough bytes left in the journal file for a complete header, or
++ ** it is corrupted, then a process must have failed while writing it.
++ ** This indicates nothing more needs to be rolled back.
++ */
++ rc = readJournalHdr(pPager, isHot, szJ, &nRec, &mxPg);
++ if( rc!=SQLITE_OK ){
++ if( rc==SQLITE_DONE ){
++ rc = SQLITE_OK;
++ }
++ goto end_playback;
++ }
++
++ /* If nRec is 0xffffffff, then this journal was created by a process
++ ** working in no-sync mode. This means that the rest of the journal
++ ** file consists of pages, there are no more journal headers. Compute
++ ** the value of nRec based on this assumption.
++ */
++ if( nRec==0xffffffff ){
++ assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) );
++ nRec = (int)((szJ - JOURNAL_HDR_SZ(pPager))/JOURNAL_PG_SZ(pPager));
++ }
++
++ /* If nRec is 0 and this rollback is of a transaction created by this
++ ** process and if this is the final header in the journal, then it means
++ ** that this part of the journal was being filled but has not yet been
++ ** synced to disk. Compute the number of pages based on the remaining
++ ** size of the file.
++ **
++ ** The third term of the test was added to fix ticket #2565.
++ ** When rolling back a hot journal, nRec==0 always means that the next
++ ** chunk of the journal contains zero pages to be rolled back. But
++ ** when doing a ROLLBACK and the nRec==0 chunk is the last chunk in
++ ** the journal, it means that the journal might contain additional
++ ** pages that need to be rolled back and that the number of pages
++ ** should be computed based on the journal file size.
++ */
++ if( nRec==0 && !isHot &&
++ pPager->journalHdr+JOURNAL_HDR_SZ(pPager)==pPager->journalOff ){
++ nRec = (int)((szJ - pPager->journalOff) / JOURNAL_PG_SZ(pPager));
++ }
++
++ /* If this is the first header read from the journal, truncate the
++ ** database file back to its original size.
++ */
++ if( pPager->journalOff==JOURNAL_HDR_SZ(pPager) ){
++ rc = pager_truncate(pPager, mxPg);
++ if( rc!=SQLITE_OK ){
++ goto end_playback;
++ }
++ pPager->dbSize = mxPg;
++ }
++
++ /* Copy original pages out of the journal and back into the
++ ** database file and/or page cache.
++ */
++ for(u=0; u<nRec; u++){
++ if( needPagerReset ){
++ pager_reset(pPager);
++ needPagerReset = 0;
++ }
++ rc = pager_playback_one_page(pPager,&pPager->journalOff,0,1,0);
++ if( rc==SQLITE_OK ){
++ nPlayback++;
++ }else{
++ if( rc==SQLITE_DONE ){
++ pPager->journalOff = szJ;
++ break;
++ }else if( rc==SQLITE_IOERR_SHORT_READ ){
++ /* If the journal has been truncated, simply stop reading and
++ ** processing the journal. This might happen if the journal was
++ ** not completely written and synced prior to a crash. In that
++ ** case, the database should have never been written in the
++ ** first place so it is OK to simply abandon the rollback. */
++ rc = SQLITE_OK;
++ goto end_playback;
++ }else{
++ /* If we are unable to rollback, quit and return the error
++ ** code. This will cause the pager to enter the error state
++ ** so that no further harm will be done. Perhaps the next
++ ** process to come along will be able to rollback the database.
++ */
++ goto end_playback;
++ }
++ }
+ }
+- p->pExtra = (void *)&p[1];
+- p->flags = PGHDR_MMAP;
+- p->nRef = 1;
+- p->pPager = pPager;
+ }
++ /*NOTREACHED*/
++ assert( 0 );
+
+- assert( p->pExtra==(void *)&p[1] );
+- assert( p->pPage==0 );
+- assert( p->flags==PGHDR_MMAP );
+- assert( p->pPager==pPager );
+- assert( p->nRef==1 );
+-
+- p->pgno = pgno;
+- p->pData = pData;
+- pPager->nMmapOut++;
+-
+- return SQLITE_OK;
+-}
+-
+-/*
+-** Release a reference to page pPg. pPg must have been returned by an
+-** earlier call to pagerAcquireMapPage().
+-*/
+-static void pagerReleaseMapPage(PgHdr *pPg){
+- Pager *pPager = pPg->pPager;
+- pPager->nMmapOut--;
+- pPg->pDirty = pPager->pMmapFreelist;
+- pPager->pMmapFreelist = pPg;
++end_playback:
++ /* Following a rollback, the database file should be back in its original
++ ** state prior to the start of the transaction, so invoke the
++ ** SQLITE_FCNTL_DB_UNCHANGED file-control method to disable the
++ ** assertion that the transaction counter was modified.
++ */
++#ifdef SQLITE_DEBUG
++ if( pPager->fd->pMethods ){
++ sqlite3OsFileControlHint(pPager->fd,SQLITE_FCNTL_DB_UNCHANGED,0);
++ }
++#endif
+
+- assert( pPager->fd->pMethods->iVersion>=3 );
+- sqlite3OsUnfetch(pPager->fd, (i64)(pPg->pgno-1)*pPager->pageSize, pPg->pData);
+-}
++ /* If this playback is happening automatically as a result of an IO or
++ ** malloc error that occurred after the change-counter was updated but
++ ** before the transaction was committed, then the change-counter
++ ** modification may just have been reverted. If this happens in exclusive
++ ** mode, then subsequent transactions performed by the connection will not
++ ** update the change-counter at all. This may lead to cache inconsistency
++ ** problems for other processes at some point in the future. So, just
++ ** in case this has happened, clear the changeCountDone flag now.
++ */
++ pPager->changeCountDone = pPager->tempFile;
+
+-/*
+-** Free all PgHdr objects stored in the Pager.pMmapFreelist list.
+-*/
+-static void pagerFreeMapHdrs(Pager *pPager){
+- PgHdr *p;
+- PgHdr *pNext;
+- for(p=pPager->pMmapFreelist; p; p=pNext){
+- pNext = p->pDirty;
+- sqlite3_free(p);
++ if( rc==SQLITE_OK ){
++ zMaster = pPager->pTmpSpace;
++ rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1);
++ testcase( rc!=SQLITE_OK );
++ }
++ if( rc==SQLITE_OK
++ && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN)
++ ){
++ rc = sqlite3PagerSync(pPager, 0);
++ }
++ if( rc==SQLITE_OK ){
++ rc = pager_end_transaction(pPager, zMaster[0]!='\0', 0);
++ testcase( rc!=SQLITE_OK );
++ }
++ if( rc==SQLITE_OK && zMaster[0] && res ){
++ /* If there was a master journal and this routine will return success,
++ ** see if it is possible to delete the master journal.
++ */
++ rc = pager_delmaster(pPager, zMaster);
++ testcase( rc!=SQLITE_OK );
++ }
++ if( isHot && nPlayback ){
++ sqlite3_log(SQLITE_NOTICE_RECOVER_ROLLBACK, "recovered %d pages from %s",
++ nPlayback, pPager->zJournal);
+ }
++
++ /* The Pager.sectorSize variable may have been updated while rolling
++ ** back a journal created by a process with a different sector size
++ ** value. Reset it to the correct value for this process.
++ */
++ setSectorSize(pPager);
++ return rc;
+ }
+
+
+ /*
+-** Shutdown the page cache. Free all memory and close all files.
++** Read the content for page pPg out of the database file and into
++** pPg->pData. A shared lock or greater must be held on the database
++** file before this function is called.
+ **
+-** If a transaction was in progress when this routine is called, that
+-** transaction is rolled back. All outstanding pages are invalidated
+-** and their memory is freed. Any attempt to use a page associated
+-** with this page cache after this function returns will likely
+-** result in a coredump.
++** If page 1 is read, then the value of Pager.dbFileVers[] is set to
++** the value read from the database file.
+ **
+-** This function always succeeds. If a transaction is active an attempt
+-** is made to roll it back. If an error occurs during the rollback
+-** a hot journal may be left in the filesystem but no error is returned
+-** to the caller.
++** If an IO error occurs, then the IO error is returned to the caller.
++** Otherwise, SQLITE_OK is returned.
+ */
+-SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager){
+- u8 *pTmp = (u8 *)pPager->pTmpSpace;
++static int readDbPage(PgHdr *pPg, u32 iFrame){
++ Pager *pPager = pPg->pPager; /* Pager object associated with page pPg */
++ Pgno pgno = pPg->pgno; /* Page number to read */
++ int rc = SQLITE_OK; /* Return code */
++ int pgsz = pPager->pageSize; /* Number of bytes to read */
++
++ assert( pPager->eState>=PAGER_READER && !MEMDB );
++ assert( isOpen(pPager->fd) );
+
+- assert( assert_pager_state(pPager) );
+- disable_simulated_io_errors();
+- sqlite3BeginBenignMalloc();
+- pagerFreeMapHdrs(pPager);
+- /* pPager->errCode = 0; */
+- pPager->exclusiveMode = 0;
+ #ifndef SQLITE_OMIT_WAL
+- sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags, pPager->pageSize, pTmp);
+- pPager->pWal = 0;
++ if( iFrame ){
++ /* Try to pull the page from the write-ahead log. */
++ rc = sqlite3WalReadFrame(pPager->pWal, iFrame, pgsz, pPg->pData);
++ }else
+ #endif
+- pager_reset(pPager);
+- if( MEMDB ){
+- pager_unlock(pPager);
+- }else{
+- /* If it is open, sync the journal file before calling UnlockAndRollback.
+- ** If this is not done, then an unsynced portion of the open journal
+- ** file may be played back into the database. If a power failure occurs
+- ** while this is happening, the database could become corrupt.
+- **
+- ** If an error occurs while trying to sync the journal, shift the pager
+- ** into the ERROR state. This causes UnlockAndRollback to unlock the
+- ** database and close the journal file without attempting to roll it
+- ** back or finalize it. The next database user will have to do hot-journal
+- ** rollback before accessing the database file.
+- */
+- if( isOpen(pPager->jfd) ){
+- pager_error(pPager, pagerSyncHotJournal(pPager));
++ {
++ i64 iOffset = (pgno-1)*(i64)pPager->pageSize;
++ rc = sqlite3OsRead(pPager->fd, pPg->pData, pgsz, iOffset);
++ if( rc==SQLITE_IOERR_SHORT_READ ){
++ rc = SQLITE_OK;
+ }
+- pagerUnlockAndRollback(pPager);
+ }
+- sqlite3EndBenignMalloc();
+- enable_simulated_io_errors();
+- PAGERTRACE(("CLOSE %d\n", PAGERID(pPager)));
+- IOTRACE(("CLOSE %p\n", pPager))
+- sqlite3OsClose(pPager->jfd);
+- sqlite3OsClose(pPager->fd);
+- sqlite3PageFree(pTmp);
+- sqlite3PcacheClose(pPager->pPCache);
+
+-#ifdef SQLITE_HAS_CODEC
+- if( pPager->xCodecFree ) pPager->xCodecFree(pPager->pCodec);
+-#endif
++ if( pgno==1 ){
++ if( rc ){
++ /* If the read is unsuccessful, set the dbFileVers[] to something
++ ** that will never be a valid file version. dbFileVers[] is a copy
++ ** of bytes 24..39 of the database. Bytes 28..31 should always be
++ ** zero or the size of the database in page. Bytes 32..35 and 35..39
++ ** should be page numbers which are never 0xffffffff. So filling
++ ** pPager->dbFileVers[] with all 0xff bytes should suffice.
++ **
++ ** For an encrypted database, the situation is more complex: bytes
++ ** 24..39 of the database are white noise. But the probability of
++ ** white noise equaling 16 bytes of 0xff is vanishingly small so
++ ** we should still be ok.
++ */
++ memset(pPager->dbFileVers, 0xff, sizeof(pPager->dbFileVers));
++ }else{
++ u8 *dbFileVers = &((u8*)pPg->pData)[24];
++ memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers));
++ }
++ }
++ CODEC1(pPager, pPg->pData, pgno, 3, rc = SQLITE_NOMEM);
+
+- assert( !pPager->aSavepoint && !pPager->pInJournal );
+- assert( !isOpen(pPager->jfd) && !isOpen(pPager->sjfd) );
++ PAGER_INCR(sqlite3_pager_readdb_count);
++ PAGER_INCR(pPager->nRead);
++ IOTRACE(("PGIN %p %d\n", pPager, pgno));
++ PAGERTRACE(("FETCH %d page %d hash(%08x)\n",
++ PAGERID(pPager), pgno, pager_pagehash(pPg)));
+
+- sqlite3_free(pPager);
+- return SQLITE_OK;
++ return rc;
+ }
+
+-#if !defined(NDEBUG) || defined(SQLITE_TEST)
+ /*
+-** Return the page number for page pPg.
++** Update the value of the change-counter at offsets 24 and 92 in
++** the header and the sqlite version number at offset 96.
++**
++** This is an unconditional update. See also the pager_incr_changecounter()
++** routine which only updates the change-counter if the update is actually
++** needed, as determined by the pPager->changeCountDone state variable.
+ */
+-SQLITE_PRIVATE Pgno sqlite3PagerPagenumber(DbPage *pPg){
+- return pPg->pgno;
+-}
+-#endif
++static void pager_write_changecounter(PgHdr *pPg){
++ u32 change_counter;
+
+-/*
+-** Increment the reference count for page pPg.
+-*/
+-SQLITE_PRIVATE void sqlite3PagerRef(DbPage *pPg){
+- sqlite3PcacheRef(pPg);
++ /* Increment the value just read and write it back to byte 24. */
++ change_counter = sqlite3Get4byte((u8*)pPg->pPager->dbFileVers)+1;
++ put32bits(((char*)pPg->pData)+24, change_counter);
++
++ /* Also store the SQLite version number in bytes 96..99 and in
++ ** bytes 92..95 store the change counter for which the version number
++ ** is valid. */
++ put32bits(((char*)pPg->pData)+92, change_counter);
++ put32bits(((char*)pPg->pData)+96, SQLITE_VERSION_NUMBER);
+ }
+
++#ifndef SQLITE_OMIT_WAL
+ /*
+-** Sync the journal. In other words, make sure all the pages that have
+-** been written to the journal have actually reached the surface of the
+-** disk and can be restored in the event of a hot-journal rollback.
+-**
+-** If the Pager.noSync flag is set, then this function is a no-op.
+-** Otherwise, the actions required depend on the journal-mode and the
+-** device characteristics of the file-system, as follows:
+-**
+-** * If the journal file is an in-memory journal file, no action need
+-** be taken.
+-**
+-** * Otherwise, if the device does not support the SAFE_APPEND property,
+-** then the nRec field of the most recently written journal header
+-** is updated to contain the number of journal records that have
+-** been written following it. If the pager is operating in full-sync
+-** mode, then the journal file is synced before this field is updated.
+-**
+-** * If the device does not support the SEQUENTIAL property, then
+-** journal file is synced.
+-**
+-** Or, in pseudo-code:
+-**
+-** if( NOT <in-memory journal> ){
+-** if( NOT SAFE_APPEND ){
+-** if( <full-sync mode> ) xSync(<journal file>);
+-** <update nRec field>
+-** }
+-** if( NOT SEQUENTIAL ) xSync(<journal file>);
+-** }
++** This function is invoked once for each page that has already been
++** written into the log file when a WAL transaction is rolled back.
++** Parameter iPg is the page number of said page. The pCtx argument
++** is actually a pointer to the Pager structure.
+ **
+-** If successful, this routine clears the PGHDR_NEED_SYNC flag of every
+-** page currently held in memory before returning SQLITE_OK. If an IO
+-** error is encountered, then the IO error code is returned to the caller.
++** If page iPg is present in the cache, and has no outstanding references,
++** it is discarded. Otherwise, if there are one or more outstanding
++** references, the page content is reloaded from the database. If the
++** attempt to reload content from the database is required and fails,
++** return an SQLite error code. Otherwise, SQLITE_OK.
+ */
+-static int syncJournal(Pager *pPager, int newHdr){
+- int rc; /* Return code */
+-
+- assert( pPager->eState==PAGER_WRITER_CACHEMOD
+- || pPager->eState==PAGER_WRITER_DBMOD
+- );
+- assert( assert_pager_state(pPager) );
+- assert( !pagerUseWal(pPager) );
+-
+- rc = sqlite3PagerExclusiveLock(pPager);
+- if( rc!=SQLITE_OK ) return rc;
+-
+- if( !pPager->noSync ){
+- assert( !pPager->tempFile );
+- if( isOpen(pPager->jfd) && pPager->journalMode!=PAGER_JOURNALMODE_MEMORY ){
+- const int iDc = sqlite3OsDeviceCharacteristics(pPager->fd);
+- assert( isOpen(pPager->jfd) );
+-
+- if( 0==(iDc&SQLITE_IOCAP_SAFE_APPEND) ){
+- /* This block deals with an obscure problem. If the last connection
+- ** that wrote to this database was operating in persistent-journal
+- ** mode, then the journal file may at this point actually be larger
+- ** than Pager.journalOff bytes. If the next thing in the journal
+- ** file happens to be a journal-header (written as part of the
+- ** previous connection's transaction), and a crash or power-failure
+- ** occurs after nRec is updated but before this connection writes
+- ** anything else to the journal file (or commits/rolls back its
+- ** transaction), then SQLite may become confused when doing the
+- ** hot-journal rollback following recovery. It may roll back all
+- ** of this connections data, then proceed to rolling back the old,
+- ** out-of-date data that follows it. Database corruption.
+- **
+- ** To work around this, if the journal file does appear to contain
+- ** a valid header following Pager.journalOff, then write a 0x00
+- ** byte to the start of it to prevent it from being recognized.
+- **
+- ** Variable iNextHdrOffset is set to the offset at which this
+- ** problematic header will occur, if it exists. aMagic is used
+- ** as a temporary buffer to inspect the first couple of bytes of
+- ** the potential journal header.
+- */
+- i64 iNextHdrOffset;
+- u8 aMagic[8];
+- u8 zHeader[sizeof(aJournalMagic)+4];
+-
+- memcpy(zHeader, aJournalMagic, sizeof(aJournalMagic));
+- put32bits(&zHeader[sizeof(aJournalMagic)], pPager->nRec);
+-
+- iNextHdrOffset = journalHdrOffset(pPager);
+- rc = sqlite3OsRead(pPager->jfd, aMagic, 8, iNextHdrOffset);
+- if( rc==SQLITE_OK && 0==memcmp(aMagic, aJournalMagic, 8) ){
+- static const u8 zerobyte = 0;
+- rc = sqlite3OsWrite(pPager->jfd, &zerobyte, 1, iNextHdrOffset);
+- }
+- if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){
+- return rc;
+- }
++static int pagerUndoCallback(void *pCtx, Pgno iPg){
++ int rc = SQLITE_OK;
++ Pager *pPager = (Pager *)pCtx;
++ PgHdr *pPg;
+
+- /* Write the nRec value into the journal file header. If in
+- ** full-synchronous mode, sync the journal first. This ensures that
+- ** all data has really hit the disk before nRec is updated to mark
+- ** it as a candidate for rollback.
+- **
+- ** This is not required if the persistent media supports the
+- ** SAFE_APPEND property. Because in this case it is not possible
+- ** for garbage data to be appended to the file, the nRec field
+- ** is populated with 0xFFFFFFFF when the journal header is written
+- ** and never needs to be updated.
+- */
+- if( pPager->fullSync && 0==(iDc&SQLITE_IOCAP_SEQUENTIAL) ){
+- PAGERTRACE(("SYNC journal of %d\n", PAGERID(pPager)));
+- IOTRACE(("JSYNC %p\n", pPager))
+- rc = sqlite3OsSync(pPager->jfd, pPager->syncFlags);
+- if( rc!=SQLITE_OK ) return rc;
+- }
+- IOTRACE(("JHDR %p %lld\n", pPager, pPager->journalHdr));
+- rc = sqlite3OsWrite(
+- pPager->jfd, zHeader, sizeof(zHeader), pPager->journalHdr
+- );
+- if( rc!=SQLITE_OK ) return rc;
+- }
+- if( 0==(iDc&SQLITE_IOCAP_SEQUENTIAL) ){
+- PAGERTRACE(("SYNC journal of %d\n", PAGERID(pPager)));
+- IOTRACE(("JSYNC %p\n", pPager))
+- rc = sqlite3OsSync(pPager->jfd, pPager->syncFlags|
+- (pPager->syncFlags==SQLITE_SYNC_FULL?SQLITE_SYNC_DATAONLY:0)
+- );
+- if( rc!=SQLITE_OK ) return rc;
++ assert( pagerUseWal(pPager) );
++ pPg = sqlite3PagerLookup(pPager, iPg);
++ if( pPg ){
++ if( sqlite3PcachePageRefcount(pPg)==1 ){
++ sqlite3PcacheDrop(pPg);
++ }else{
++ u32 iFrame = 0;
++ rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame);
++ if( rc==SQLITE_OK ){
++ rc = readDbPage(pPg, iFrame);
+ }
+-
+- pPager->journalHdr = pPager->journalOff;
+- if( newHdr && 0==(iDc&SQLITE_IOCAP_SAFE_APPEND) ){
+- pPager->nRec = 0;
+- rc = writeJournalHdr(pPager);
+- if( rc!=SQLITE_OK ) return rc;
++ if( rc==SQLITE_OK ){
++ pPager->xReiniter(pPg);
+ }
+- }else{
+- pPager->journalHdr = pPager->journalOff;
++ sqlite3PagerUnrefNotNull(pPg);
+ }
+ }
+
+- /* Unless the pager is in noSync mode, the journal file was just
+- ** successfully synced. Either way, clear the PGHDR_NEED_SYNC flag on
+- ** all pages.
++ /* Normally, if a transaction is rolled back, any backup processes are
++ ** updated as data is copied out of the rollback journal and into the
++ ** database. This is not generally possible with a WAL database, as
++ ** rollback involves simply truncating the log file. Therefore, if one
++ ** or more frames have already been written to the log (and therefore
++ ** also copied into the backup databases) as part of this transaction,
++ ** the backups must be restarted.
+ */
+- sqlite3PcacheClearSyncFlags(pPager->pPCache);
+- pPager->eState = PAGER_WRITER_DBMOD;
+- assert( assert_pager_state(pPager) );
+- return SQLITE_OK;
++ sqlite3BackupRestart(pPager->pBackup);
++
++ return rc;
+ }
+
+ /*
+-** The argument is the first in a linked list of dirty pages connected
+-** by the PgHdr.pDirty pointer. This function writes each one of the
+-** in-memory pages in the list to the database file. The argument may
+-** be NULL, representing an empty list. In this case this function is
+-** a no-op.
+-**
+-** The pager must hold at least a RESERVED lock when this function
+-** is called. Before writing anything to the database file, this lock
+-** is upgraded to an EXCLUSIVE lock. If the lock cannot be obtained,
+-** SQLITE_BUSY is returned and no data is written to the database file.
+-**
+-** If the pager is a temp-file pager and the actual file-system file
+-** is not yet open, it is created and opened before any data is
+-** written out.
+-**
+-** Once the lock has been upgraded and, if necessary, the file opened,
+-** the pages are written out to the database file in list order. Writing
+-** a page is skipped if it meets either of the following criteria:
+-**
+-** * The page number is greater than Pager.dbSize, or
+-** * The PGHDR_DONT_WRITE flag is set on the page.
+-**
+-** If writing out a page causes the database file to grow, Pager.dbFileSize
+-** is updated accordingly. If page 1 is written out, then the value cached
+-** in Pager.dbFileVers[] is updated to match the new value stored in
+-** the database file.
+-**
+-** If everything is successful, SQLITE_OK is returned. If an IO error
+-** occurs, an IO error code is returned. Or, if the EXCLUSIVE lock cannot
+-** be obtained, SQLITE_BUSY is returned.
++** This function is called to rollback a transaction on a WAL database.
+ */
+-static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
+- int rc = SQLITE_OK; /* Return code */
+-
+- /* This function is only called for rollback pagers in WRITER_DBMOD state. */
+- assert( !pagerUseWal(pPager) );
+- assert( pPager->eState==PAGER_WRITER_DBMOD );
+- assert( pPager->eLock==EXCLUSIVE_LOCK );
+-
+- /* If the file is a temp-file has not yet been opened, open it now. It
+- ** is not possible for rc to be other than SQLITE_OK if this branch
+- ** is taken, as pager_wait_on_lock() is a no-op for temp-files.
+- */
+- if( !isOpen(pPager->fd) ){
+- assert( pPager->tempFile && rc==SQLITE_OK );
+- rc = pagerOpentemp(pPager, pPager->fd, pPager->vfsFlags);
+- }
++static int pagerRollbackWal(Pager *pPager){
++ int rc; /* Return Code */
++ PgHdr *pList; /* List of dirty pages to revert */
+
+- /* Before the first write, give the VFS a hint of what the final
+- ** file size will be.
++ /* For all pages in the cache that are currently dirty or have already
++ ** been written (but not committed) to the log file, do one of the
++ ** following:
++ **
++ ** + Discard the cached page (if refcount==0), or
++ ** + Reload page content from the database (if refcount>0).
+ */
+- assert( rc!=SQLITE_OK || isOpen(pPager->fd) );
+- if( rc==SQLITE_OK
+- && pPager->dbHintSize<pPager->dbSize
+- && (pList->pDirty || pList->pgno>pPager->dbHintSize)
+- ){
+- sqlite3_int64 szFile = pPager->pageSize * (sqlite3_int64)pPager->dbSize;
+- sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_SIZE_HINT, &szFile);
+- pPager->dbHintSize = pPager->dbSize;
++ pPager->dbSize = pPager->dbOrigSize;
++ rc = sqlite3WalUndo(pPager->pWal, pagerUndoCallback, (void *)pPager);
++ pList = sqlite3PcacheDirtyList(pPager->pPCache);
++ while( pList && rc==SQLITE_OK ){
++ PgHdr *pNext = pList->pDirty;
++ rc = pagerUndoCallback((void *)pPager, pList->pgno);
++ pList = pNext;
+ }
+
+- while( rc==SQLITE_OK && pList ){
+- Pgno pgno = pList->pgno;
+-
+- /* If there are dirty pages in the page cache with page numbers greater
+- ** than Pager.dbSize, this means sqlite3PagerTruncateImage() was called to
+- ** make the file smaller (presumably by auto-vacuum code). Do not write
+- ** any such pages to the file.
+- **
+- ** Also, do not write out any page that has the PGHDR_DONT_WRITE flag
+- ** set (set by sqlite3PagerDontWrite()).
+- */
+- if( pgno<=pPager->dbSize && 0==(pList->flags&PGHDR_DONT_WRITE) ){
+- i64 offset = (pgno-1)*(i64)pPager->pageSize; /* Offset to write */
+- char *pData; /* Data to write */
+-
+- assert( (pList->flags&PGHDR_NEED_SYNC)==0 );
+- if( pList->pgno==1 ) pager_write_changecounter(pList);
+-
+- /* Encode the database */
+- CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM, pData);
++ return rc;
++}
+
+- /* Write out the page data. */
+- rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset);
++/*
++** This function is a wrapper around sqlite3WalFrames(). As well as logging
++** the contents of the list of pages headed by pList (connected by pDirty),
++** this function notifies any active backup processes that the pages have
++** changed.
++**
++** The list of pages passed into this routine is always sorted by page number.
++** Hence, if page 1 appears anywhere on the list, it will be the first page.
++*/
++static int pagerWalFrames(
++ Pager *pPager, /* Pager object */
++ PgHdr *pList, /* List of frames to log */
++ Pgno nTruncate, /* Database size after this commit */
++ int isCommit /* True if this is a commit */
+){
-+ sqlite3PagerSetCodec(pPager, xCodec, xCodecSizeChng, xCodecFree, pCodec);
++ int rc; /* Return code */
++ int nList; /* Number of pages in pList */
++ PgHdr *p; /* For looping over pages */
+
+- /* If page 1 was just written, update Pager.dbFileVers to match
+- ** the value now stored in the database file. If writing this
+- ** page caused the database file to grow, update dbFileSize.
+- */
+- if( pgno==1 ){
+- memcpy(&pPager->dbFileVers, &pData[24], sizeof(pPager->dbFileVers));
+- }
+- if( pgno>pPager->dbFileSize ){
+- pPager->dbFileSize = pgno;
+- }
+- pPager->aStat[PAGER_STAT_WRITE]++;
++ assert( pPager->pWal );
++ assert( pList );
++#ifdef SQLITE_DEBUG
++ /* Verify that the page list is in accending order */
++ for(p=pList; p && p->pDirty; p=p->pDirty){
++ assert( p->pgno < p->pDirty->pgno );
++ }
++#endif
+
+- /* Update any backup objects copying the contents of this pager. */
+- sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)pList->pData);
++ assert( pList->pDirty==0 || isCommit );
++ if( isCommit ){
++ /* If a WAL transaction is being committed, there is no point in writing
++ ** any pages with page numbers greater than nTruncate into the WAL file.
++ ** They will never be read by any client. So remove them from the pDirty
++ ** list here. */
++ PgHdr **ppNext = &pList;
++ nList = 0;
++ for(p=pList; (*ppNext = p)!=0; p=p->pDirty){
++ if( p->pgno<=nTruncate ){
++ ppNext = &p->pDirty;
++ nList++;
++ }
++ }
++ assert( pList );
++ }else{
++ nList = 1;
++ }
++ pPager->aStat[PAGER_STAT_WRITE] += nList;
+
+- PAGERTRACE(("STORE %d page %d hash(%08x)\n",
+- PAGERID(pPager), pgno, pager_pagehash(pList)));
+- IOTRACE(("PGOUT %p %d\n", pPager, pgno));
+- PAGER_INCR(sqlite3_pager_writedb_count);
+- }else{
+- PAGERTRACE(("NOSTORE %d page %d\n", PAGERID(pPager), pgno));
++ if( pList->pgno==1 ) pager_write_changecounter(pList);
++ rc = sqlite3WalFrames(pPager->pWal,
++ pPager->pageSize, pList, nTruncate, isCommit, pPager->walSyncFlags
++ );
++ if( rc==SQLITE_OK && pPager->pBackup ){
++ for(p=pList; p; p=p->pDirty){
++ sqlite3BackupUpdate(pPager->pBackup, p->pgno, (u8 *)p->pData);
+ }
+- pager_set_pagehash(pList);
+- pList = pList->pDirty;
+ }
+
++#ifdef SQLITE_CHECK_PAGES
++ pList = sqlite3PcacheDirtyList(pPager->pPCache);
++ for(p=pList; p; p=p->pDirty){
++ pager_set_pagehash(p);
++ }
++#endif
++
+ return rc;
+ }
+
+ /*
+-** Ensure that the sub-journal file is open. If it is already open, this
+-** function is a no-op.
++** Begin a read transaction on the WAL.
+ **
+-** SQLITE_OK is returned if everything goes according to plan. An
+-** SQLITE_IOERR_XXX error code is returned if a call to sqlite3OsOpen()
+-** fails.
++** This routine used to be called "pagerOpenSnapshot()" because it essentially
++** makes a snapshot of the database at the current point in time and preserves
++** that snapshot for use by the reader in spite of concurrently changes by
++** other writers or checkpointers.
+ */
+-static int openSubJournal(Pager *pPager){
+- int rc = SQLITE_OK;
+- if( !isOpen(pPager->sjfd) ){
+- if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY || pPager->subjInMemory ){
+- sqlite3MemJournalOpen(pPager->sjfd);
+- }else{
+- rc = pagerOpentemp(pPager, pPager->sjfd, SQLITE_OPEN_SUBJOURNAL);
+- }
++static int pagerBeginReadTransaction(Pager *pPager){
++ int rc; /* Return code */
++ int changed = 0; /* True if cache must be reset */
++
++ assert( pagerUseWal(pPager) );
++ assert( pPager->eState==PAGER_OPEN || pPager->eState==PAGER_READER );
++
++ /* sqlite3WalEndReadTransaction() was not called for the previous
++ ** transaction in locking_mode=EXCLUSIVE. So call it now. If we
++ ** are in locking_mode=NORMAL and EndRead() was previously called,
++ ** the duplicate call is harmless.
++ */
++ sqlite3WalEndReadTransaction(pPager->pWal);
++
++ rc = sqlite3WalBeginReadTransaction(pPager->pWal, &changed);
++ if( rc!=SQLITE_OK || changed ){
++ pager_reset(pPager);
++ if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0);
+ }
++
+ return rc;
+ }
++#endif
+
+ /*
+-** Append a record of the current state of page pPg to the sub-journal.
+-** It is the callers responsibility to use subjRequiresPage() to check
+-** that it is really required before calling this function.
+-**
+-** If successful, set the bit corresponding to pPg->pgno in the bitvecs
+-** for all open savepoints before returning.
++** This function is called as part of the transition from PAGER_OPEN
++** to PAGER_READER state to determine the size of the database file
++** in pages (assuming the page size currently stored in Pager.pageSize).
+ **
+-** This function returns SQLITE_OK if everything is successful, an IO
+-** error code if the attempt to write to the sub-journal fails, or
+-** SQLITE_NOMEM if a malloc fails while setting a bit in a savepoint
+-** bitvec.
++** If no error occurs, SQLITE_OK is returned and the size of the database
++** in pages is stored in *pnPage. Otherwise, an error code (perhaps
++** SQLITE_IOERR_FSTAT) is returned and *pnPage is left unmodified.
+ */
+-static int subjournalPage(PgHdr *pPg){
+- int rc = SQLITE_OK;
+- Pager *pPager = pPg->pPager;
+- if( pPager->journalMode!=PAGER_JOURNALMODE_OFF ){
++static int pagerPagecount(Pager *pPager, Pgno *pnPage){
++ Pgno nPage; /* Value to return via *pnPage */
+
+- /* Open the sub-journal, if it has not already been opened */
+- assert( pPager->useJournal );
+- assert( isOpen(pPager->jfd) || pagerUseWal(pPager) );
+- assert( isOpen(pPager->sjfd) || pPager->nSubRec==0 );
+- assert( pagerUseWal(pPager)
+- || pageInJournal(pPager, pPg)
+- || pPg->pgno>pPager->dbOrigSize
+- );
+- rc = openSubJournal(pPager);
++ /* Query the WAL sub-system for the database size. The WalDbsize()
++ ** function returns zero if the WAL is not open (i.e. Pager.pWal==0), or
++ ** if the database size is not available. The database size is not
++ ** available from the WAL sub-system if the log file is empty or
++ ** contains no valid committed transactions.
++ */
++ assert( pPager->eState==PAGER_OPEN );
++ assert( pPager->eLock>=SHARED_LOCK );
++ nPage = sqlite3WalDbsize(pPager->pWal);
+
+- /* If the sub-journal was opened successfully (or was already open),
+- ** write the journal record into the file. */
+- if( rc==SQLITE_OK ){
+- void *pData = pPg->pData;
+- i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize);
+- char *pData2;
+-
+- CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2);
+- PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno));
+- rc = write32bits(pPager->sjfd, offset, pPg->pgno);
+- if( rc==SQLITE_OK ){
+- rc = sqlite3OsWrite(pPager->sjfd, pData2, pPager->pageSize, offset+4);
++ /* If the database size was not available from the WAL sub-system,
++ ** determine it based on the size of the database file. If the size
++ ** of the database file is not an integer multiple of the page-size,
++ ** round down to the nearest page. Except, any file larger than 0
++ ** bytes in size is considered to contain at least one page.
++ */
++ if( nPage==0 ){
++ i64 n = 0; /* Size of db file in bytes */
++ assert( isOpen(pPager->fd) || pPager->tempFile );
++ if( isOpen(pPager->fd) ){
++ int rc = sqlite3OsFileSize(pPager->fd, &n);
++ if( rc!=SQLITE_OK ){
++ return rc;
+ }
+ }
++ nPage = (Pgno)((n+pPager->pageSize-1) / pPager->pageSize);
+ }
+- if( rc==SQLITE_OK ){
+- pPager->nSubRec++;
+- assert( pPager->nSavepoint>0 );
+- rc = addToSavepointBitvecs(pPager, pPg->pgno);
++
++ /* If the current number of pages in the file is greater than the
++ ** configured maximum pager number, increase the allowed limit so
++ ** that the file can be read.
++ */
++ if( nPage>pPager->mxPgno ){
++ pPager->mxPgno = (Pgno)nPage;
+ }
+- return rc;
++
++ *pnPage = nPage;
++ return SQLITE_OK;
+ }
+
++#ifndef SQLITE_OMIT_WAL
+ /*
+-** This function is called by the pcache layer when it has reached some
+-** soft memory limit. The first argument is a pointer to a Pager object
+-** (cast as a void*). The pager is always 'purgeable' (not an in-memory
+-** database). The second argument is a reference to a page that is
+-** currently dirty but has no outstanding references. The page
+-** is always associated with the Pager object passed as the first
+-** argument.
++** Check if the *-wal file that corresponds to the database opened by pPager
++** exists if the database is not empy, or verify that the *-wal file does
++** not exist (by deleting it) if the database file is empty.
+ **
+-** The job of this function is to make pPg clean by writing its contents
+-** out to the database file, if possible. This may involve syncing the
+-** journal file.
++** If the database is not empty and the *-wal file exists, open the pager
++** in WAL mode. If the database is empty or if no *-wal file exists and
++** if no error occurs, make sure Pager.journalMode is not set to
++** PAGER_JOURNALMODE_WAL.
+ **
+-** If successful, sqlite3PcacheMakeClean() is called on the page and
+-** SQLITE_OK returned. If an IO error occurs while trying to make the
+-** page clean, the IO error code is returned. If the page cannot be
+-** made clean for some other reason, but no error occurs, then SQLITE_OK
+-** is returned by sqlite3PcacheMakeClean() is not called.
++** Return SQLITE_OK or an error code.
++**
++** The caller must hold a SHARED lock on the database file to call this
++** function. Because an EXCLUSIVE lock on the db file is required to delete
++** a WAL on a none-empty database, this ensures there is no race condition
++** between the xAccess() below and an xDelete() being executed by some
++** other connection.
+ */
+-static int pagerStress(void *p, PgHdr *pPg){
+- Pager *pPager = (Pager *)p;
++static int pagerOpenWalIfPresent(Pager *pPager){
+ int rc = SQLITE_OK;
++ assert( pPager->eState==PAGER_OPEN );
++ assert( pPager->eLock>=SHARED_LOCK );
+
+- assert( pPg->pPager==pPager );
+- assert( pPg->flags&PGHDR_DIRTY );
+-
+- /* The doNotSpill NOSYNC bit is set during times when doing a sync of
+- ** journal (and adding a new header) is not allowed. This occurs
+- ** during calls to sqlite3PagerWrite() while trying to journal multiple
+- ** pages belonging to the same sector.
+- **
+- ** The doNotSpill ROLLBACK and OFF bits inhibits all cache spilling
+- ** regardless of whether or not a sync is required. This is set during
+- ** a rollback or by user request, respectively.
+- **
+- ** Spilling is also prohibited when in an error state since that could
+- ** lead to database corruption. In the current implementation it
+- ** is impossible for sqlite3PcacheFetch() to be called with createFlag==3
+- ** while in the error state, hence it is impossible for this routine to
+- ** be called in the error state. Nevertheless, we include a NEVER()
+- ** test for the error state as a safeguard against future changes.
+- */
+- if( NEVER(pPager->errCode) ) return SQLITE_OK;
+- testcase( pPager->doNotSpill & SPILLFLAG_ROLLBACK );
+- testcase( pPager->doNotSpill & SPILLFLAG_OFF );
+- testcase( pPager->doNotSpill & SPILLFLAG_NOSYNC );
+- if( pPager->doNotSpill
+- && ((pPager->doNotSpill & (SPILLFLAG_ROLLBACK|SPILLFLAG_OFF))!=0
+- || (pPg->flags & PGHDR_NEED_SYNC)!=0)
+- ){
+- return SQLITE_OK;
+- }
++ if( !pPager->tempFile ){
++ int isWal; /* True if WAL file exists */
++ Pgno nPage; /* Size of the database file */
+
+- pPg->pDirty = 0;
+- if( pagerUseWal(pPager) ){
+- /* Write a single frame for this page to the log. */
+- if( subjRequiresPage(pPg) ){
+- rc = subjournalPage(pPg);
+- }
+- if( rc==SQLITE_OK ){
+- rc = pagerWalFrames(pPager, pPg, 0, 0);
+- }
+- }else{
+-
+- /* Sync the journal file if required. */
+- if( pPg->flags&PGHDR_NEED_SYNC
+- || pPager->eState==PAGER_WRITER_CACHEMOD
+- ){
+- rc = syncJournal(pPager, 1);
+- }
+-
+- /* If the page number of this page is larger than the current size of
+- ** the database image, it may need to be written to the sub-journal.
+- ** This is because the call to pager_write_pagelist() below will not
+- ** actually write data to the file in this case.
+- **
+- ** Consider the following sequence of events:
+- **
+- ** BEGIN;
+- ** <journal page X>
+- ** <modify page X>
+- ** SAVEPOINT sp;
+- ** <shrink database file to Y pages>
+- ** pagerStress(page X)
+- ** ROLLBACK TO sp;
+- **
+- ** If (X>Y), then when pagerStress is called page X will not be written
+- ** out to the database file, but will be dropped from the cache. Then,
+- ** following the "ROLLBACK TO sp" statement, reading page X will read
+- ** data from the database file. This will be the copy of page X as it
+- ** was when the transaction started, not as it was when "SAVEPOINT sp"
+- ** was executed.
+- **
+- ** The solution is to write the current data for page X into the
+- ** sub-journal file now (if it is not already there), so that it will
+- ** be restored to its current value when the "ROLLBACK TO sp" is
+- ** executed.
+- */
+- if( NEVER(
+- rc==SQLITE_OK && pPg->pgno>pPager->dbSize && subjRequiresPage(pPg)
+- ) ){
+- rc = subjournalPage(pPg);
++ rc = pagerPagecount(pPager, &nPage);
++ if( rc ) return rc;
++ if( nPage==0 ){
++ rc = sqlite3OsDelete(pPager->pVfs, pPager->zWal, 0);
++ if( rc==SQLITE_IOERR_DELETE_NOENT ) rc = SQLITE_OK;
++ isWal = 0;
++ }else{
++ rc = sqlite3OsAccess(
++ pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &isWal
++ );
+ }
+-
+- /* Write the contents of the page out to the database file. */
+ if( rc==SQLITE_OK ){
+- assert( (pPg->flags&PGHDR_NEED_SYNC)==0 );
+- rc = pager_write_pagelist(pPager, pPg);
++ if( isWal ){
++ testcase( sqlite3PcachePagecount(pPager->pPCache)==0 );
++ rc = sqlite3PagerOpenWal(pPager, 0);
++ }else if( pPager->journalMode==PAGER_JOURNALMODE_WAL ){
++ pPager->journalMode = PAGER_JOURNALMODE_DELETE;
++ }
+ }
+ }
+-
+- /* Mark the page as clean. */
+- if( rc==SQLITE_OK ){
+- PAGERTRACE(("STRESS %d page %d\n", PAGERID(pPager), pPg->pgno));
+- sqlite3PcacheMakeClean(pPg);
+- }
+-
+- return pager_error(pPager, rc);
++ return rc;
+ }
+-
++#endif
+
+ /*
+-** Allocate and initialize a new Pager object and put a pointer to it
+-** in *ppPager. The pager should eventually be freed by passing it
+-** to sqlite3PagerClose().
++** Playback savepoint pSavepoint. Or, if pSavepoint==NULL, then playback
++** the entire master journal file. The case pSavepoint==NULL occurs when
++** a ROLLBACK TO command is invoked on a SAVEPOINT that is a transaction
++** savepoint.
+ **
+-** The zFilename argument is the path to the database file to open.
+-** If zFilename is NULL then a randomly-named temporary file is created
+-** and used as the file to be cached. Temporary files are be deleted
+-** automatically when they are closed. If zFilename is ":memory:" then
+-** all information is held in cache. It is never written to disk.
+-** This can be used to implement an in-memory database.
++** When pSavepoint is not NULL (meaning a non-transaction savepoint is
++** being rolled back), then the rollback consists of up to three stages,
++** performed in the order specified:
+ **
+-** The nExtra parameter specifies the number of bytes of space allocated
+-** along with each page reference. This space is available to the user
+-** via the sqlite3PagerGetExtra() API.
++** * Pages are played back from the main journal starting at byte
++** offset PagerSavepoint.iOffset and continuing to
++** PagerSavepoint.iHdrOffset, or to the end of the main journal
++** file if PagerSavepoint.iHdrOffset is zero.
+ **
+-** The flags argument is used to specify properties that affect the
+-** operation of the pager. It should be passed some bitwise combination
+-** of the PAGER_* flags.
++** * If PagerSavepoint.iHdrOffset is not zero, then pages are played
++** back starting from the journal header immediately following
++** PagerSavepoint.iHdrOffset to the end of the main journal file.
+ **
+-** The vfsFlags parameter is a bitmask to pass to the flags parameter
+-** of the xOpen() method of the supplied VFS when opening files.
++** * Pages are then played back from the sub-journal file, starting
++** with the PagerSavepoint.iSubRec and continuing to the end of
++** the journal file.
+ **
+-** If the pager object is allocated and the specified file opened
+-** successfully, SQLITE_OK is returned and *ppPager set to point to
+-** the new pager object. If an error occurs, *ppPager is set to NULL
+-** and error code returned. This function may return SQLITE_NOMEM
+-** (sqlite3Malloc() is used to allocate memory), SQLITE_CANTOPEN or
+-** various SQLITE_IO_XXX errors.
++** Throughout the rollback process, each time a page is rolled back, the
++** corresponding bit is set in a bitvec structure (variable pDone in the
++** implementation below). This is used to ensure that a page is only
++** rolled back the first time it is encountered in either journal.
++**
++** If pSavepoint is NULL, then pages are only played back from the main
++** journal file. There is no need for a bitvec in this case.
++**
++** In either case, before playback commences the Pager.dbSize variable
++** is reset to the value that it held at the start of the savepoint
++** (or transaction). No page with a page-number greater than this value
++** is played back. If one is encountered it is simply skipped.
+ */
+-SQLITE_PRIVATE int sqlite3PagerOpen(
+- sqlite3_vfs *pVfs, /* The virtual file system to use */
+- Pager **ppPager, /* OUT: Return the Pager structure here */
+- const char *zFilename, /* Name of the database file to open */
+- int nExtra, /* Extra bytes append to each in-memory page */
+- int flags, /* flags controlling this file */
+- int vfsFlags, /* flags passed through to sqlite3_vfs.xOpen() */
+- void (*xReinit)(DbPage*) /* Function to reinitialize pages */
+-){
+- u8 *pPtr;
+- Pager *pPager = 0; /* Pager object to allocate and return */
++static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){
++ i64 szJ; /* Effective size of the main journal */
++ i64 iHdrOff; /* End of first segment of main-journal records */
+ int rc = SQLITE_OK; /* Return code */
+- int tempFile = 0; /* True for temp files (incl. in-memory files) */
+- int memDb = 0; /* True if this is an in-memory file */
+- int readOnly = 0; /* True if this is a read-only file */
+- int journalFileSize; /* Bytes to allocate for each journal fd */
+- char *zPathname = 0; /* Full path to database file */
+- int nPathname = 0; /* Number of bytes in zPathname */
+- int useJournal = (flags & PAGER_OMIT_JOURNAL)==0; /* False to omit journal */
+- int pcacheSize = sqlite3PcacheSize(); /* Bytes to allocate for PCache */
+- u32 szPageDflt = SQLITE_DEFAULT_PAGE_SIZE; /* Default page size */
+- const char *zUri = 0; /* URI args to copy */
+- int nUri = 0; /* Number of bytes of URI args at *zUri */
+-
+- /* Figure out how much space is required for each journal file-handle
+- ** (there are two of them, the main journal and the sub-journal). This
+- ** is the maximum space required for an in-memory journal file handle
+- ** and a regular journal file-handle. Note that a "regular journal-handle"
+- ** may be a wrapper capable of caching the first portion of the journal
+- ** file in memory to implement the atomic-write optimization (see
+- ** source file journal.c).
+- */
+- if( sqlite3JournalSize(pVfs)>sqlite3MemJournalSize() ){
+- journalFileSize = ROUND8(sqlite3JournalSize(pVfs));
+- }else{
+- journalFileSize = ROUND8(sqlite3MemJournalSize());
+- }
+-
+- /* Set the output variable to NULL in case an error occurs. */
+- *ppPager = 0;
++ Bitvec *pDone = 0; /* Bitvec to ensure pages played back only once */
+
+-#ifndef SQLITE_OMIT_MEMORYDB
+- if( flags & PAGER_MEMORY ){
+- memDb = 1;
+- if( zFilename && zFilename[0] ){
+- zPathname = sqlite3DbStrDup(0, zFilename);
+- if( zPathname==0 ) return SQLITE_NOMEM;
+- nPathname = sqlite3Strlen30(zPathname);
+- zFilename = 0;
+- }
+- }
+-#endif
++ assert( pPager->eState!=PAGER_ERROR );
++ assert( pPager->eState>=PAGER_WRITER_LOCKED );
+
+- /* Compute and store the full pathname in an allocated buffer pointed
+- ** to by zPathname, length nPathname. Or, if this is a temporary file,
+- ** leave both nPathname and zPathname set to 0.
+- */
+- if( zFilename && zFilename[0] ){
+- const char *z;
+- nPathname = pVfs->mxPathname+1;
+- zPathname = sqlite3DbMallocRaw(0, nPathname*2);
+- if( zPathname==0 ){
++ /* Allocate a bitvec to use to store the set of pages rolled back */
++ if( pSavepoint ){
++ pDone = sqlite3BitvecCreate(pSavepoint->nOrig);
++ if( !pDone ){
+ return SQLITE_NOMEM;
+ }
+- zPathname[0] = 0; /* Make sure initialized even if FullPathname() fails */
+- rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname);
+- nPathname = sqlite3Strlen30(zPathname);
+- z = zUri = &zFilename[sqlite3Strlen30(zFilename)+1];
+- while( *z ){
+- z += sqlite3Strlen30(z)+1;
+- z += sqlite3Strlen30(z)+1;
+- }
+- nUri = (int)(&z[1] - zUri);
+- assert( nUri>=0 );
+- if( rc==SQLITE_OK && nPathname+8>pVfs->mxPathname ){
+- /* This branch is taken when the journal path required by
+- ** the database being opened will be more than pVfs->mxPathname
+- ** bytes in length. This means the database cannot be opened,
+- ** as it will not be possible to open the journal file or even
+- ** check for a hot-journal before reading.
+- */
+- rc = SQLITE_CANTOPEN_BKPT;
+- }
+- if( rc!=SQLITE_OK ){
+- sqlite3DbFree(0, zPathname);
+- return rc;
+- }
+ }
+
+- /* Allocate memory for the Pager structure, PCache object, the
+- ** three file descriptors, the database file name and the journal
+- ** file name. The layout in memory is as follows:
+- **
+- ** Pager object (sizeof(Pager) bytes)
+- ** PCache object (sqlite3PcacheSize() bytes)
+- ** Database file handle (pVfs->szOsFile bytes)
+- ** Sub-journal file handle (journalFileSize bytes)
+- ** Main journal file handle (journalFileSize bytes)
+- ** Database file name (nPathname+1 bytes)
+- ** Journal file name (nPathname+8+1 bytes)
++ /* Set the database size back to the value it was before the savepoint
++ ** being reverted was opened.
+ */
+- pPtr = (u8 *)sqlite3MallocZero(
+- ROUND8(sizeof(*pPager)) + /* Pager structure */
+- ROUND8(pcacheSize) + /* PCache object */
+- ROUND8(pVfs->szOsFile) + /* The main db file */
+- journalFileSize * 2 + /* The two journal files */
+- nPathname + 1 + nUri + /* zFilename */
+- nPathname + 8 + 2 /* zJournal */
+-#ifndef SQLITE_OMIT_WAL
+- + nPathname + 4 + 2 /* zWal */
+-#endif
+- );
+- assert( EIGHT_BYTE_ALIGNMENT(SQLITE_INT_TO_PTR(journalFileSize)) );
+- if( !pPtr ){
+- sqlite3DbFree(0, zPathname);
+- return SQLITE_NOMEM;
+- }
+- pPager = (Pager*)(pPtr);
+- pPager->pPCache = (PCache*)(pPtr += ROUND8(sizeof(*pPager)));
+- pPager->fd = (sqlite3_file*)(pPtr += ROUND8(pcacheSize));
+- pPager->sjfd = (sqlite3_file*)(pPtr += ROUND8(pVfs->szOsFile));
+- pPager->jfd = (sqlite3_file*)(pPtr += journalFileSize);
+- pPager->zFilename = (char*)(pPtr += journalFileSize);
+- assert( EIGHT_BYTE_ALIGNMENT(pPager->jfd) );
++ pPager->dbSize = pSavepoint ? pSavepoint->nOrig : pPager->dbOrigSize;
++ pPager->changeCountDone = pPager->tempFile;
++
++ if( !pSavepoint && pagerUseWal(pPager) ){
++ return pagerRollbackWal(pPager);
++ }
+
+- /* Fill in the Pager.zFilename and Pager.zJournal buffers, if required. */
+- if( zPathname ){
+- assert( nPathname>0 );
+- pPager->zJournal = (char*)(pPtr += nPathname + 1 + nUri);
+- memcpy(pPager->zFilename, zPathname, nPathname);
+- if( nUri ) memcpy(&pPager->zFilename[nPathname+1], zUri, nUri);
+- memcpy(pPager->zJournal, zPathname, nPathname);
+- memcpy(&pPager->zJournal[nPathname], "-journal\000", 8+2);
+- sqlite3FileSuffix3(pPager->zFilename, pPager->zJournal);
+-#ifndef SQLITE_OMIT_WAL
+- pPager->zWal = &pPager->zJournal[nPathname+8+1];
+- memcpy(pPager->zWal, zPathname, nPathname);
+- memcpy(&pPager->zWal[nPathname], "-wal\000", 4+1);
+- sqlite3FileSuffix3(pPager->zFilename, pPager->zWal);
+-#endif
+- sqlite3DbFree(0, zPathname);
++ /* Use pPager->journalOff as the effective size of the main rollback
++ ** journal. The actual file might be larger than this in
++ ** PAGER_JOURNALMODE_TRUNCATE or PAGER_JOURNALMODE_PERSIST. But anything
++ ** past pPager->journalOff is off-limits to us.
++ */
++ szJ = pPager->journalOff;
++ assert( pagerUseWal(pPager)==0 || szJ==0 );
++
++ /* Begin by rolling back records from the main journal starting at
++ ** PagerSavepoint.iOffset and continuing to the next journal header.
++ ** There might be records in the main journal that have a page number
++ ** greater than the current database size (pPager->dbSize) but those
++ ** will be skipped automatically. Pages are added to pDone as they
++ ** are played back.
++ */
++ if( pSavepoint && !pagerUseWal(pPager) ){
++ iHdrOff = pSavepoint->iHdrOffset ? pSavepoint->iHdrOffset : szJ;
++ pPager->journalOff = pSavepoint->iOffset;
++ while( rc==SQLITE_OK && pPager->journalOff<iHdrOff ){
++ rc = pager_playback_one_page(pPager, &pPager->journalOff, pDone, 1, 1);
++ }
++ assert( rc!=SQLITE_DONE );
++ }else{
++ pPager->journalOff = 0;
+ }
+- pPager->pVfs = pVfs;
+- pPager->vfsFlags = vfsFlags;
+
+- /* Open the pager file.
++ /* Continue rolling back records out of the main journal starting at
++ ** the first journal header seen and continuing until the effective end
++ ** of the main journal file. Continue to skip out-of-range pages and
++ ** continue adding pages rolled back to pDone.
+ */
+- if( zFilename && zFilename[0] ){
+- int fout = 0; /* VFS flags returned by xOpen() */
+- rc = sqlite3OsOpen(pVfs, pPager->zFilename, pPager->fd, vfsFlags, &fout);
+- assert( !memDb );
+- readOnly = (fout&SQLITE_OPEN_READONLY);
++ while( rc==SQLITE_OK && pPager->journalOff<szJ ){
++ u32 ii; /* Loop counter */
++ u32 nJRec = 0; /* Number of Journal Records */
++ u32 dummy;
++ rc = readJournalHdr(pPager, 0, szJ, &nJRec, &dummy);
++ assert( rc!=SQLITE_DONE );
+
+- /* If the file was successfully opened for read/write access,
+- ** choose a default page size in case we have to create the
+- ** database file. The default page size is the maximum of:
+- **
+- ** + SQLITE_DEFAULT_PAGE_SIZE,
+- ** + The value returned by sqlite3OsSectorSize()
+- ** + The largest page size that can be written atomically.
++ /*
++ ** The "pPager->journalHdr+JOURNAL_HDR_SZ(pPager)==pPager->journalOff"
++ ** test is related to ticket #2565. See the discussion in the
++ ** pager_playback() function for additional information.
+ */
+- if( rc==SQLITE_OK ){
+- int iDc = sqlite3OsDeviceCharacteristics(pPager->fd);
+- if( !readOnly ){
+- setSectorSize(pPager);
+- assert(SQLITE_DEFAULT_PAGE_SIZE<=SQLITE_MAX_DEFAULT_PAGE_SIZE);
+- if( szPageDflt<pPager->sectorSize ){
+- if( pPager->sectorSize>SQLITE_MAX_DEFAULT_PAGE_SIZE ){
+- szPageDflt = SQLITE_MAX_DEFAULT_PAGE_SIZE;
+- }else{
+- szPageDflt = (u32)pPager->sectorSize;
+- }
+- }
+-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+- {
+- int ii;
+- assert(SQLITE_IOCAP_ATOMIC512==(512>>8));
+- assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8));
+- assert(SQLITE_MAX_DEFAULT_PAGE_SIZE<=65536);
+- for(ii=szPageDflt; ii<=SQLITE_MAX_DEFAULT_PAGE_SIZE; ii=ii*2){
+- if( iDc&(SQLITE_IOCAP_ATOMIC|(ii>>8)) ){
+- szPageDflt = ii;
+- }
+- }
+- }
+-#endif
+- }
+- pPager->noLock = sqlite3_uri_boolean(zFilename, "nolock", 0);
+- if( (iDc & SQLITE_IOCAP_IMMUTABLE)!=0
+- || sqlite3_uri_boolean(zFilename, "immutable", 0) ){
+- vfsFlags |= SQLITE_OPEN_READONLY;
+- goto act_like_temp_file;
+- }
++ if( nJRec==0
++ && pPager->journalHdr+JOURNAL_HDR_SZ(pPager)==pPager->journalOff
++ ){
++ nJRec = (u32)((szJ - pPager->journalOff)/JOURNAL_PG_SZ(pPager));
+ }
+- }else{
+- /* If a temporary file is requested, it is not opened immediately.
+- ** In this case we accept the default page size and delay actually
+- ** opening the file until the first call to OsWrite().
+- **
+- ** This branch is also run for an in-memory database. An in-memory
+- ** database is the same as a temp-file that is never written out to
+- ** disk and uses an in-memory rollback journal.
+- **
+- ** This branch also runs for files marked as immutable.
+- */
+-act_like_temp_file:
+- tempFile = 1;
+- pPager->eState = PAGER_READER; /* Pretend we already have a lock */
+- pPager->eLock = EXCLUSIVE_LOCK; /* Pretend we are in EXCLUSIVE locking mode */
+- pPager->noLock = 1; /* Do no locking */
+- readOnly = (vfsFlags&SQLITE_OPEN_READONLY);
++ for(ii=0; rc==SQLITE_OK && ii<nJRec && pPager->journalOff<szJ; ii++){
++ rc = pager_playback_one_page(pPager, &pPager->journalOff, pDone, 1, 1);
++ }
++ assert( rc!=SQLITE_DONE );
+ }
++ assert( rc!=SQLITE_OK || pPager->journalOff>=szJ );
+
+- /* The following call to PagerSetPagesize() serves to set the value of
+- ** Pager.pageSize and to allocate the Pager.pTmpSpace buffer.
++ /* Finally, rollback pages from the sub-journal. Page that were
++ ** previously rolled back out of the main journal (and are hence in pDone)
++ ** will be skipped. Out-of-range pages are also skipped.
+ */
+- if( rc==SQLITE_OK ){
+- assert( pPager->memDb==0 );
+- rc = sqlite3PagerSetPagesize(pPager, &szPageDflt, -1);
+- testcase( rc!=SQLITE_OK );
++ if( pSavepoint ){
++ u32 ii; /* Loop counter */
++ i64 offset = (i64)pSavepoint->iSubRec*(4+pPager->pageSize);
++
++ if( pagerUseWal(pPager) ){
++ rc = sqlite3WalSavepointUndo(pPager->pWal, pSavepoint->aWalData);
++ }
++ for(ii=pSavepoint->iSubRec; rc==SQLITE_OK && ii<pPager->nSubRec; ii++){
++ assert( offset==(i64)ii*(4+pPager->pageSize) );
++ rc = pager_playback_one_page(pPager, &offset, pDone, 0, 1);
++ }
++ assert( rc!=SQLITE_DONE );
+ }
+
+- /* Initialize the PCache object. */
++ sqlite3BitvecDestroy(pDone);
+ if( rc==SQLITE_OK ){
+- assert( nExtra<1000 );
+- nExtra = ROUND8(nExtra);
+- rc = sqlite3PcacheOpen(szPageDflt, nExtra, !memDb,
+- !memDb?pagerStress:0, (void *)pPager, pPager->pPCache);
++ pPager->journalOff = szJ;
+ }
+
+- /* If an error occurred above, free the Pager structure and close the file.
+- */
+- if( rc!=SQLITE_OK ){
+- sqlite3OsClose(pPager->fd);
+- sqlite3PageFree(pPager->pTmpSpace);
+- sqlite3_free(pPager);
+- return rc;
++ return rc;
+}
+
-+SQLITE_PRIVATE void sqlite3pager_sqlite3PagerSetError( Pager *pPager, int error) {
-+ pPager->errCode = error;
++/*
++** Change the maximum number of in-memory pages that are allowed.
++*/
++SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){
++ sqlite3PcacheSetCachesize(pPager->pPCache, mxPage);
+}
+
++/*
++** Invoke SQLITE_FCNTL_MMAP_SIZE based on the current value of szMmap.
++*/
++static void pagerFixMaplimit(Pager *pPager){
++#if SQLITE_MAX_MMAP_SIZE>0
++ sqlite3_file *fd = pPager->fd;
++ if( isOpen(fd) && fd->pMethods->iVersion>=3 ){
++ sqlite3_int64 sz;
++ sz = pPager->szMmap;
++ pPager->bUseFetch = (sz>0);
++ sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_MMAP_SIZE, &sz);
+ }
+#endif
-+/* END SQLCIPHER */
++}
+
+- PAGERTRACE(("OPEN %d %s\n", FILEHANDLEID(pPager->fd), pPager->zFilename));
+- IOTRACE(("OPEN %p %s\n", pPager, pPager->zFilename))
++/*
++** Change the maximum size of any memory mapping made of the database file.
++*/
++SQLITE_PRIVATE void sqlite3PagerSetMmapLimit(Pager *pPager, sqlite3_int64 szMmap){
++ pPager->szMmap = szMmap;
++ pagerFixMaplimit(pPager);
++}
+
+- pPager->useJournal = (u8)useJournal;
+- /* pPager->stmtOpen = 0; */
+- /* pPager->stmtInUse = 0; */
+- /* pPager->nRef = 0; */
+- /* pPager->stmtSize = 0; */
+- /* pPager->stmtJSize = 0; */
+- /* pPager->nPage = 0; */
+- pPager->mxPgno = SQLITE_MAX_PAGE_COUNT;
+- /* pPager->state = PAGER_UNLOCK; */
+- /* pPager->errMask = 0; */
+- pPager->tempFile = (u8)tempFile;
+- assert( tempFile==PAGER_LOCKINGMODE_NORMAL
+- || tempFile==PAGER_LOCKINGMODE_EXCLUSIVE );
+- assert( PAGER_LOCKINGMODE_EXCLUSIVE==1 );
+- pPager->exclusiveMode = (u8)tempFile;
+- pPager->changeCountDone = pPager->tempFile;
+- pPager->memDb = (u8)memDb;
+- pPager->readOnly = (u8)readOnly;
+- assert( useJournal || pPager->tempFile );
+- pPager->noSync = pPager->tempFile;
++/*
++** Free as much memory as possible from the pager.
++*/
++SQLITE_PRIVATE void sqlite3PagerShrink(Pager *pPager){
++ sqlite3PcacheShrink(pPager->pPCache);
++}
++
++/*
++** Adjust settings of the pager to those specified in the pgFlags parameter.
++**
++** The "level" in pgFlags & PAGER_SYNCHRONOUS_MASK sets the robustness
++** of the database to damage due to OS crashes or power failures by
++** changing the number of syncs()s when writing the journals.
++** There are three levels:
++**
++** OFF sqlite3OsSync() is never called. This is the default
++** for temporary and transient files.
++**
++** NORMAL The journal is synced once before writes begin on the
++** database. This is normally adequate protection, but
++** it is theoretically possible, though very unlikely,
++** that an inopertune power failure could leave the journal
++** in a state which would cause damage to the database
++** when it is rolled back.
++**
++** FULL The journal is synced twice before writes begin on the
++** database (with some additional information - the nRec field
++** of the journal header - being written in between the two
++** syncs). If we assume that writing a
++** single disk sector is atomic, then this mode provides
++** assurance that the journal will not be corrupted to the
++** point of causing damage to the database during rollback.
++**
++** The above is for a rollback-journal mode. For WAL mode, OFF continues
++** to mean that no syncs ever occur. NORMAL means that the WAL is synced
++** prior to the start of checkpoint and that the database file is synced
++** at the conclusion of the checkpoint if the entire content of the WAL
++** was written back into the database. But no sync operations occur for
++** an ordinary commit in NORMAL mode with WAL. FULL means that the WAL
++** file is synced following each commit operation, in addition to the
++** syncs associated with NORMAL.
++**
++** Do not confuse synchronous=FULL with SQLITE_SYNC_FULL. The
++** SQLITE_SYNC_FULL macro means to use the MacOSX-style full-fsync
++** using fcntl(F_FULLFSYNC). SQLITE_SYNC_NORMAL means to do an
++** ordinary fsync() call. There is no difference between SQLITE_SYNC_FULL
++** and SQLITE_SYNC_NORMAL on platforms other than MacOSX. But the
++** synchronous=FULL versus synchronous=NORMAL setting determines when
++** the xSync primitive is called and is relevant to all platforms.
++**
++** Numeric values associated with these states are OFF==1, NORMAL=2,
++** and FULL=3.
++*/
++#ifndef SQLITE_OMIT_PAGER_PRAGMAS
++SQLITE_PRIVATE void sqlite3PagerSetFlags(
++ Pager *pPager, /* The pager to set safety level for */
++ unsigned pgFlags /* Various flags */
++){
++ unsigned level = pgFlags & PAGER_SYNCHRONOUS_MASK;
++ assert( level>=1 && level<=3 );
++ pPager->noSync = (level==1 || pPager->tempFile) ?1:0;
++ pPager->fullSync = (level==3 && !pPager->tempFile) ?1:0;
+ if( pPager->noSync ){
+- assert( pPager->fullSync==0 );
+- assert( pPager->syncFlags==0 );
+- assert( pPager->walSyncFlags==0 );
+- assert( pPager->ckptSyncFlags==0 );
++ pPager->syncFlags = 0;
++ pPager->ckptSyncFlags = 0;
++ }else if( pgFlags & PAGER_FULLFSYNC ){
++ pPager->syncFlags = SQLITE_SYNC_FULL;
++ pPager->ckptSyncFlags = SQLITE_SYNC_FULL;
++ }else if( pgFlags & PAGER_CKPT_FULLFSYNC ){
++ pPager->syncFlags = SQLITE_SYNC_NORMAL;
++ pPager->ckptSyncFlags = SQLITE_SYNC_FULL;
+ }else{
+- pPager->fullSync = 1;
+ pPager->syncFlags = SQLITE_SYNC_NORMAL;
+- pPager->walSyncFlags = SQLITE_SYNC_NORMAL | WAL_SYNC_TRANSACTIONS;
+ pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL;
+ }
+- /* pPager->pFirst = 0; */
+- /* pPager->pFirstSynced = 0; */
+- /* pPager->pLast = 0; */
+- pPager->nExtra = (u16)nExtra;
+- pPager->journalSizeLimit = SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT;
+- assert( isOpen(pPager->fd) || tempFile );
+- setSectorSize(pPager);
+- if( !useJournal ){
+- pPager->journalMode = PAGER_JOURNALMODE_OFF;
+- }else if( memDb ){
+- pPager->journalMode = PAGER_JOURNALMODE_MEMORY;
++ pPager->walSyncFlags = pPager->syncFlags;
++ if( pPager->fullSync ){
++ pPager->walSyncFlags |= WAL_SYNC_TRANSACTIONS;
++ }
++ if( pgFlags & PAGER_CACHESPILL ){
++ pPager->doNotSpill &= ~SPILLFLAG_OFF;
++ }else{
++ pPager->doNotSpill |= SPILLFLAG_OFF;
+ }
+- /* pPager->xBusyHandler = 0; */
+- /* pPager->pBusyHandlerArg = 0; */
+- pPager->xReiniter = xReinit;
+- /* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */
+- /* pPager->szMmap = SQLITE_DEFAULT_MMAP_SIZE // will be set by btree.c */
+-
+- *ppPager = pPager;
+- return SQLITE_OK;
+ }
++#endif
+
++/*
++** The following global variable is incremented whenever the library
++** attempts to open a temporary file. This information is used for
++** testing and analysis only.
++*/
++#ifdef SQLITE_TEST
++SQLITE_API int sqlite3_opentemp_count = 0;
++#endif
+
+-/* Verify that the database file has not be deleted or renamed out from
+-** under the pager. Return SQLITE_OK if the database is still were it ought
+-** to be on disk. Return non-zero (SQLITE_READONLY_DBMOVED or some other error
+-** code from sqlite3OsAccess()) if the database has gone missing.
++/*
++** Open a temporary file.
++**
++** Write the file descriptor into *pFile. Return SQLITE_OK on success
++** or some other error code if we fail. The OS will automatically
++** delete the temporary file when it is closed.
++**
++** The flags passed to the VFS layer xOpen() call are those specified
++** by parameter vfsFlags ORed with the following:
++**
++** SQLITE_OPEN_READWRITE
++** SQLITE_OPEN_CREATE
++** SQLITE_OPEN_EXCLUSIVE
++** SQLITE_OPEN_DELETEONCLOSE
+ */
+-static int databaseIsUnmoved(Pager *pPager){
+- int bHasMoved = 0;
+- int rc;
++static int pagerOpentemp(
++ Pager *pPager, /* The pager object */
++ sqlite3_file *pFile, /* Write the file descriptor here */
++ int vfsFlags /* Flags passed through to the VFS */
++){
++ int rc; /* Return code */
+
+- if( pPager->tempFile ) return SQLITE_OK;
+- if( pPager->dbSize==0 ) return SQLITE_OK;
+- assert( pPager->zFilename && pPager->zFilename[0] );
+- rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_HAS_MOVED, &bHasMoved);
+- if( rc==SQLITE_NOTFOUND ){
+- /* If the HAS_MOVED file-control is unimplemented, assume that the file
+- ** has not been moved. That is the historical behavior of SQLite: prior to
+- ** version 3.8.3, it never checked */
+- rc = SQLITE_OK;
+- }else if( rc==SQLITE_OK && bHasMoved ){
+- rc = SQLITE_READONLY_DBMOVED;
+- }
++#ifdef SQLITE_TEST
++ sqlite3_opentemp_count++; /* Used for testing and analysis only */
++#endif
++
++ vfsFlags |= SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
++ SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE;
++ rc = sqlite3OsOpen(pPager->pVfs, 0, pFile, vfsFlags, 0);
++ assert( rc!=SQLITE_OK || isOpen(pFile) );
+ return rc;
+ }
+
+-
+ /*
+-** This function is called after transitioning from PAGER_UNLOCK to
+-** PAGER_SHARED state. It tests if there is a hot journal present in
+-** the file-system for the given pager. A hot journal is one that
+-** needs to be played back. According to this function, a hot-journal
+-** file exists if the following criteria are met:
+-**
+-** * The journal file exists in the file system, and
+-** * No process holds a RESERVED or greater lock on the database file, and
+-** * The database file itself is greater than 0 bytes in size, and
+-** * The first byte of the journal file exists and is not 0x00.
++** Set the busy handler function.
+ **
+-** If the current size of the database file is 0 but a journal file
+-** exists, that is probably an old journal left over from a prior
+-** database with the same name. In this case the journal file is
+-** just deleted using OsDelete, *pExists is set to 0 and SQLITE_OK
+-** is returned.
++** The pager invokes the busy-handler if sqlite3OsLock() returns
++** SQLITE_BUSY when trying to upgrade from no-lock to a SHARED lock,
++** or when trying to upgrade from a RESERVED lock to an EXCLUSIVE
++** lock. It does *not* invoke the busy handler when upgrading from
++** SHARED to RESERVED, or when upgrading from SHARED to EXCLUSIVE
++** (which occurs during hot-journal rollback). Summary:
+ **
+-** This routine does not check if there is a master journal filename
+-** at the end of the file. If there is, and that master journal file
+-** does not exist, then the journal file is not really hot. In this
+-** case this routine will return a false-positive. The pager_playback()
+-** routine will discover that the journal file is not really hot and
+-** will not roll it back.
++** Transition | Invokes xBusyHandler
++** --------------------------------------------------------
++** NO_LOCK -> SHARED_LOCK | Yes
++** SHARED_LOCK -> RESERVED_LOCK | No
++** SHARED_LOCK -> EXCLUSIVE_LOCK | No
++** RESERVED_LOCK -> EXCLUSIVE_LOCK | Yes
+ **
+-** If a hot-journal file is found to exist, *pExists is set to 1 and
+-** SQLITE_OK returned. If no hot-journal file is present, *pExists is
+-** set to 0 and SQLITE_OK returned. If an IO error occurs while trying
+-** to determine whether or not a hot-journal file exists, the IO error
+-** code is returned and the value of *pExists is undefined.
++** If the busy-handler callback returns non-zero, the lock is
++** retried. If it returns zero, then the SQLITE_BUSY error is
++** returned to the caller of the pager API function.
+ */
+-static int hasHotJournal(Pager *pPager, int *pExists){
+- sqlite3_vfs * const pVfs = pPager->pVfs;
+- int rc = SQLITE_OK; /* Return code */
+- int exists = 1; /* True if a journal file is present */
+- int jrnlOpen = !!isOpen(pPager->jfd);
+-
+- assert( pPager->useJournal );
+- assert( isOpen(pPager->fd) );
+- assert( pPager->eState==PAGER_OPEN );
+-
+- assert( jrnlOpen==0 || ( sqlite3OsDeviceCharacteristics(pPager->jfd) &
+- SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN
+- ));
+-
+- *pExists = 0;
+- if( !jrnlOpen ){
+- rc = sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &exists);
+- }
+- if( rc==SQLITE_OK && exists ){
+- int locked = 0; /* True if some process holds a RESERVED lock */
+-
+- /* Race condition here: Another process might have been holding the
+- ** the RESERVED lock and have a journal open at the sqlite3OsAccess()
+- ** call above, but then delete the journal and drop the lock before
+- ** we get to the following sqlite3OsCheckReservedLock() call. If that
+- ** is the case, this routine might think there is a hot journal when
+- ** in fact there is none. This results in a false-positive which will
+- ** be dealt with by the playback routine. Ticket #3883.
+- */
+- rc = sqlite3OsCheckReservedLock(pPager->fd, &locked);
+- if( rc==SQLITE_OK && !locked ){
+- Pgno nPage; /* Number of pages in database file */
++SQLITE_PRIVATE void sqlite3PagerSetBusyhandler(
++ Pager *pPager, /* Pager object */
++ int (*xBusyHandler)(void *), /* Pointer to busy-handler function */
++ void *pBusyHandlerArg /* Argument to pass to xBusyHandler */
++){
++ pPager->xBusyHandler = xBusyHandler;
++ pPager->pBusyHandlerArg = pBusyHandlerArg;
+
+- rc = pagerPagecount(pPager, &nPage);
+- if( rc==SQLITE_OK ){
+- /* If the database is zero pages in size, that means that either (1) the
+- ** journal is a remnant from a prior database with the same name where
+- ** the database file but not the journal was deleted, or (2) the initial
+- ** transaction that populates a new database is being rolled back.
+- ** In either case, the journal file can be deleted. However, take care
+- ** not to delete the journal file if it is already open due to
+- ** journal_mode=PERSIST.
+- */
+- if( nPage==0 && !jrnlOpen ){
+- sqlite3BeginBenignMalloc();
+- if( pagerLockDb(pPager, RESERVED_LOCK)==SQLITE_OK ){
+- sqlite3OsDelete(pVfs, pPager->zJournal, 0);
+- if( !pPager->exclusiveMode ) pagerUnlockDb(pPager, SHARED_LOCK);
+- }
+- sqlite3EndBenignMalloc();
+- }else{
+- /* The journal file exists and no other connection has a reserved
+- ** or greater lock on the database file. Now check that there is
+- ** at least one non-zero bytes at the start of the journal file.
+- ** If there is, then we consider this journal to be hot. If not,
+- ** it can be ignored.
+- */
+- if( !jrnlOpen ){
+- int f = SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL;
+- rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &f);
+- }
+- if( rc==SQLITE_OK ){
+- u8 first = 0;
+- rc = sqlite3OsRead(pPager->jfd, (void *)&first, 1, 0);
+- if( rc==SQLITE_IOERR_SHORT_READ ){
+- rc = SQLITE_OK;
+- }
+- if( !jrnlOpen ){
+- sqlite3OsClose(pPager->jfd);
+- }
+- *pExists = (first!=0);
+- }else if( rc==SQLITE_CANTOPEN ){
+- /* If we cannot open the rollback journal file in order to see if
+- ** it has a zero header, that might be due to an I/O error, or
+- ** it might be due to the race condition described above and in
+- ** ticket #3883. Either way, assume that the journal is hot.
+- ** This might be a false positive. But if it is, then the
+- ** automatic journal playback and recovery mechanism will deal
+- ** with it under an EXCLUSIVE lock where we do not need to
+- ** worry so much with race conditions.
+- */
+- *pExists = 1;
+- rc = SQLITE_OK;
+- }
+- }
+- }
+- }
++ if( isOpen(pPager->fd) ){
++ void **ap = (void **)&pPager->xBusyHandler;
++ assert( ((int(*)(void *))(ap[0]))==xBusyHandler );
++ assert( ap[1]==pBusyHandlerArg );
++ sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_BUSYHANDLER, (void *)ap);
+ }
+-
+- return rc;
+ }
+
+ /*
+-** This function is called to obtain a shared lock on the database file.
+-** It is illegal to call sqlite3PagerAcquire() until after this function
+-** has been successfully called. If a shared-lock is already held when
+-** this function is called, it is a no-op.
++** Change the page size used by the Pager object. The new page size
++** is passed in *pPageSize.
+ **
+-** The following operations are also performed by this function.
++** If the pager is in the error state when this function is called, it
++** is a no-op. The value returned is the error state error code (i.e.
++** one of SQLITE_IOERR, an SQLITE_IOERR_xxx sub-code or SQLITE_FULL).
+ **
+-** 1) If the pager is currently in PAGER_OPEN state (no lock held
+-** on the database file), then an attempt is made to obtain a
+-** SHARED lock on the database file. Immediately after obtaining
+-** the SHARED lock, the file-system is checked for a hot-journal,
+-** which is played back if present. Following any hot-journal
+-** rollback, the contents of the cache are validated by checking
+-** the 'change-counter' field of the database file header and
+-** discarded if they are found to be invalid.
++** Otherwise, if all of the following are true:
+ **
+-** 2) If the pager is running in exclusive-mode, and there are currently
+-** no outstanding references to any pages, and is in the error state,
+-** then an attempt is made to clear the error state by discarding
+-** the contents of the page cache and rolling back any open journal
+-** file.
++** * the new page size (value of *pPageSize) is valid (a power
++** of two between 512 and SQLITE_MAX_PAGE_SIZE, inclusive), and
+ **
+-** If everything is successful, SQLITE_OK is returned. If an IO error
+-** occurs while locking the database, checking for a hot-journal file or
+-** rolling back a journal file, the IO error code is returned.
++** * there are no outstanding page references, and
++**
++** * the database is either not an in-memory database or it is
++** an in-memory database that currently consists of zero pages.
++**
++** then the pager object page size is set to *pPageSize.
++**
++** If the page size is changed, then this function uses sqlite3PagerMalloc()
++** to obtain a new Pager.pTmpSpace buffer. If this allocation attempt
++** fails, SQLITE_NOMEM is returned and the page size remains unchanged.
++** In all other cases, SQLITE_OK is returned.
++**
++** If the page size is not changed, either because one of the enumerated
++** conditions above is not true, the pager was in error state when this
++** function was called, or because the memory allocation attempt failed,
++** then *pPageSize is set to the old, retained page size before returning.
+ */
+-SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
+- int rc = SQLITE_OK; /* Return code */
++SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nReserve){
++ int rc = SQLITE_OK;
+
+- /* This routine is only called from b-tree and only when there are no
+- ** outstanding pages. This implies that the pager state should either
+- ** be OPEN or READER. READER is only possible if the pager is or was in
+- ** exclusive access mode.
++ /* It is not possible to do a full assert_pager_state() here, as this
++ ** function may be called from within PagerOpen(), before the state
++ ** of the Pager object is internally consistent.
++ **
++ ** At one point this function returned an error if the pager was in
++ ** PAGER_ERROR state. But since PAGER_ERROR state guarantees that
++ ** there is at least one outstanding page reference, this function
++ ** is a no-op for that case anyhow.
+ */
+- assert( sqlite3PcacheRefCount(pPager->pPCache)==0 );
+- assert( assert_pager_state(pPager) );
+- assert( pPager->eState==PAGER_OPEN || pPager->eState==PAGER_READER );
+- if( NEVER(MEMDB && pPager->errCode) ){ return pPager->errCode; }
+-
+- if( !pagerUseWal(pPager) && pPager->eState==PAGER_OPEN ){
+- int bHotJournal = 1; /* True if there exists a hot journal-file */
+
+- assert( !MEMDB );
++ u32 pageSize = *pPageSize;
++ assert( pageSize==0 || (pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE) );
++ if( (pPager->memDb==0 || pPager->dbSize==0)
++ && sqlite3PcacheRefCount(pPager->pPCache)==0
++ && pageSize && pageSize!=(u32)pPager->pageSize
++ ){
++ char *pNew = NULL; /* New temp space */
++ i64 nByte = 0;
+
+- rc = pager_wait_on_lock(pPager, SHARED_LOCK);
+- if( rc!=SQLITE_OK ){
+- assert( pPager->eLock==NO_LOCK || pPager->eLock==UNKNOWN_LOCK );
+- goto failed;
++ if( pPager->eState>PAGER_OPEN && isOpen(pPager->fd) ){
++ rc = sqlite3OsFileSize(pPager->fd, &nByte);
++ }
++ if( rc==SQLITE_OK ){
++ pNew = (char *)sqlite3PageMalloc(pageSize);
++ if( !pNew ) rc = SQLITE_NOMEM;
+ }
+
+- /* If a journal file exists, and there is no RESERVED lock on the
+- ** database file, then it either needs to be played back or deleted.
+- */
+- if( pPager->eLock<=SHARED_LOCK ){
+- rc = hasHotJournal(pPager, &bHotJournal);
++ if( rc==SQLITE_OK ){
++ pager_reset(pPager);
++ rc = sqlite3PcacheSetPageSize(pPager->pPCache, pageSize);
+ }
+- if( rc!=SQLITE_OK ){
+- goto failed;
++ if( rc==SQLITE_OK ){
++ sqlite3PageFree(pPager->pTmpSpace);
++ pPager->pTmpSpace = pNew;
++ pPager->dbSize = (Pgno)((nByte+pageSize-1)/pageSize);
++ pPager->pageSize = pageSize;
++ }else{
++ sqlite3PageFree(pNew);
+ }
+- if( bHotJournal ){
+- if( pPager->readOnly ){
+- rc = SQLITE_READONLY_ROLLBACK;
+- goto failed;
+- }
++ }
+
+- /* Get an EXCLUSIVE lock on the database file. At this point it is
+- ** important that a RESERVED lock is not obtained on the way to the
+- ** EXCLUSIVE lock. If it were, another process might open the
+- ** database file, detect the RESERVED lock, and conclude that the
+- ** database is safe to read while this process is still rolling the
+- ** hot-journal back.
+- **
+- ** Because the intermediate RESERVED lock is not requested, any
+- ** other process attempting to access the database file will get to
+- ** this point in the code and fail to obtain its own EXCLUSIVE lock
+- ** on the database file.
+- **
+- ** Unless the pager is in locking_mode=exclusive mode, the lock is
+- ** downgraded to SHARED_LOCK before this function returns.
+- */
+- rc = pagerLockDb(pPager, EXCLUSIVE_LOCK);
+- if( rc!=SQLITE_OK ){
+- goto failed;
+- }
+-
+- /* If it is not already open and the file exists on disk, open the
+- ** journal for read/write access. Write access is required because
+- ** in exclusive-access mode the file descriptor will be kept open
+- ** and possibly used for a transaction later on. Also, write-access
+- ** is usually required to finalize the journal in journal_mode=persist
+- ** mode (and also for journal_mode=truncate on some systems).
+- **
+- ** If the journal does not exist, it usually means that some
+- ** other connection managed to get in and roll it back before
+- ** this connection obtained the exclusive lock above. Or, it
+- ** may mean that the pager was in the error-state when this
+- ** function was called and the journal file does not exist.
+- */
+- if( !isOpen(pPager->jfd) ){
+- sqlite3_vfs * const pVfs = pPager->pVfs;
+- int bExists; /* True if journal file exists */
+- rc = sqlite3OsAccess(
+- pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &bExists);
+- if( rc==SQLITE_OK && bExists ){
+- int fout = 0;
+- int f = SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_JOURNAL;
+- assert( !pPager->tempFile );
+- rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &fout);
+- assert( rc!=SQLITE_OK || isOpen(pPager->jfd) );
+- if( rc==SQLITE_OK && fout&SQLITE_OPEN_READONLY ){
+- rc = SQLITE_CANTOPEN_BKPT;
+- sqlite3OsClose(pPager->jfd);
+- }
+- }
+- }
+-
+- /* Playback and delete the journal. Drop the database write
+- ** lock and reacquire the read lock. Purge the cache before
+- ** playing back the hot-journal so that we don't end up with
+- ** an inconsistent cache. Sync the hot journal before playing
+- ** it back since the process that crashed and left the hot journal
+- ** probably did not sync it and we are required to always sync
+- ** the journal before playing it back.
+- */
+- if( isOpen(pPager->jfd) ){
+- assert( rc==SQLITE_OK );
+- rc = pagerSyncHotJournal(pPager);
+- if( rc==SQLITE_OK ){
+- rc = pager_playback(pPager, 1);
+- pPager->eState = PAGER_OPEN;
+- }
+- }else if( !pPager->exclusiveMode ){
+- pagerUnlockDb(pPager, SHARED_LOCK);
+- }
++ *pPageSize = pPager->pageSize;
++ if( rc==SQLITE_OK ){
++ if( nReserve<0 ) nReserve = pPager->nReserve;
++ assert( nReserve>=0 && nReserve<1000 );
++ pPager->nReserve = (i16)nReserve;
++ pagerReportSize(pPager);
++ pagerFixMaplimit(pPager);
++ }
++ return rc;
++}
+
+- if( rc!=SQLITE_OK ){
+- /* This branch is taken if an error occurs while trying to open
+- ** or roll back a hot-journal while holding an EXCLUSIVE lock. The
+- ** pager_unlock() routine will be called before returning to unlock
+- ** the file. If the unlock attempt fails, then Pager.eLock must be
+- ** set to UNKNOWN_LOCK (see the comment above the #define for
+- ** UNKNOWN_LOCK above for an explanation).
+- **
+- ** In order to get pager_unlock() to do this, set Pager.eState to
+- ** PAGER_ERROR now. This is not actually counted as a transition
+- ** to ERROR state in the state diagram at the top of this file,
+- ** since we know that the same call to pager_unlock() will very
+- ** shortly transition the pager object to the OPEN state. Calling
+- ** assert_pager_state() would fail now, as it should not be possible
+- ** to be in ERROR state when there are zero outstanding page
+- ** references.
+- */
+- pager_error(pPager, rc);
+- goto failed;
+- }
++/*
++** Return a pointer to the "temporary page" buffer held internally
++** by the pager. This is a buffer that is big enough to hold the
++** entire content of a database page. This buffer is used internally
++** during rollback and will be overwritten whenever a rollback
++** occurs. But other modules are free to use it too, as long as
++** no rollbacks are happening.
++*/
++SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager *pPager){
++ return pPager->pTmpSpace;
++}
+
+- assert( pPager->eState==PAGER_OPEN );
+- assert( (pPager->eLock==SHARED_LOCK)
+- || (pPager->exclusiveMode && pPager->eLock>SHARED_LOCK)
+- );
++/*
++** Attempt to set the maximum database page count if mxPage is positive.
++** Make no changes if mxPage is zero or negative. And never reduce the
++** maximum page count below the current size of the database.
++**
++** Regardless of mxPage, return the current maximum page count.
++*/
++SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager *pPager, int mxPage){
++ if( mxPage>0 ){
++ pPager->mxPgno = mxPage;
++ }
++ assert( pPager->eState!=PAGER_OPEN ); /* Called only by OP_MaxPgcnt */
++ assert( pPager->mxPgno>=pPager->dbSize ); /* OP_MaxPgcnt enforces this */
++ return pPager->mxPgno;
++}
++
++/*
++** The following set of routines are used to disable the simulated
++** I/O error mechanism. These routines are used to avoid simulated
++** errors in places where we do not care about errors.
++**
++** Unless -DSQLITE_TEST=1 is used, these routines are all no-ops
++** and generate no code.
++*/
++#ifdef SQLITE_TEST
++SQLITE_API extern int sqlite3_io_error_pending;
++SQLITE_API extern int sqlite3_io_error_hit;
++static int saved_cnt;
++void disable_simulated_io_errors(void){
++ saved_cnt = sqlite3_io_error_pending;
++ sqlite3_io_error_pending = -1;
++}
++void enable_simulated_io_errors(void){
++ sqlite3_io_error_pending = saved_cnt;
++}
++#else
++# define disable_simulated_io_errors()
++# define enable_simulated_io_errors()
++#endif
++
++/*
++** Read the first N bytes from the beginning of the file into memory
++** that pDest points to.
++**
++** If the pager was opened on a transient file (zFilename==""), or
++** opened on a file less than N bytes in size, the output buffer is
++** zeroed and SQLITE_OK returned. The rationale for this is that this
++** function is used to read database headers, and a new transient or
++** zero sized database has a header than consists entirely of zeroes.
++**
++** If any IO error apart from SQLITE_IOERR_SHORT_READ is encountered,
++** the error code is returned to the caller and the contents of the
++** output buffer undefined.
++*/
++SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager *pPager, int N, unsigned char *pDest){
++ int rc = SQLITE_OK;
++ memset(pDest, 0, N);
++ assert( isOpen(pPager->fd) || pPager->tempFile );
++
++ /* This routine is only called by btree immediately after creating
++ ** the Pager object. There has not been an opportunity to transition
++ ** to WAL mode yet.
++ */
++ assert( !pagerUseWal(pPager) );
++
++ if( isOpen(pPager->fd) ){
++ IOTRACE(("DBHDR %p 0 %d\n", pPager, N))
++ rc = sqlite3OsRead(pPager->fd, pDest, N, 0);
++ if( rc==SQLITE_IOERR_SHORT_READ ){
++ rc = SQLITE_OK;
+ }
++ }
++ return rc;
++}
+
+- if( !pPager->tempFile && pPager->hasBeenUsed ){
+- /* The shared-lock has just been acquired then check to
+- ** see if the database has been modified. If the database has changed,
+- ** flush the cache. The pPager->hasBeenUsed flag prevents this from
+- ** occurring on the very first access to a file, in order to save a
+- ** single unnecessary sqlite3OsRead() call at the start-up.
+- **
+- ** Database changes is detected by looking at 15 bytes beginning
+- ** at offset 24 into the file. The first 4 of these 16 bytes are
+- ** a 32-bit counter that is incremented with each change. The
+- ** other bytes change randomly with each file change when
+- ** a codec is in use.
+- **
+- ** There is a vanishingly small chance that a change will not be
+- ** detected. The chance of an undetected change is so small that
+- ** it can be neglected.
+- */
+- Pgno nPage = 0;
+- char dbFileVers[sizeof(pPager->dbFileVers)];
++/*
++** This function may only be called when a read-transaction is open on
++** the pager. It returns the total number of pages in the database.
++**
++** However, if the file is between 1 and <page-size> bytes in size, then
++** this is considered a 1 page file.
++*/
++SQLITE_PRIVATE void sqlite3PagerPagecount(Pager *pPager, int *pnPage){
++ assert( pPager->eState>=PAGER_READER );
++ assert( pPager->eState!=PAGER_WRITER_FINISHED );
++ *pnPage = (int)pPager->dbSize;
++}
+
+- rc = pagerPagecount(pPager, &nPage);
+- if( rc ) goto failed;
+
+- if( nPage>0 ){
+- IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers)));
+- rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24);
+- if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){
+- goto failed;
+- }
+- }else{
+- memset(dbFileVers, 0, sizeof(dbFileVers));
+- }
++/*
++** Try to obtain a lock of type locktype on the database file. If
++** a similar or greater lock is already held, this function is a no-op
++** (returning SQLITE_OK immediately).
++**
++** Otherwise, attempt to obtain the lock using sqlite3OsLock(). Invoke
++** the busy callback if the lock is currently not available. Repeat
++** until the busy callback returns false or until the attempt to
++** obtain the lock succeeds.
++**
++** Return SQLITE_OK on success and an error code if we cannot obtain
++** the lock. If the lock is obtained successfully, set the Pager.state
++** variable to locktype before returning.
++*/
++static int pager_wait_on_lock(Pager *pPager, int locktype){
++ int rc; /* Return code */
+
+- if( memcmp(pPager->dbFileVers, dbFileVers, sizeof(dbFileVers))!=0 ){
+- pager_reset(pPager);
++ /* Check that this is either a no-op (because the requested lock is
++ ** already held), or one of the transitions that the busy-handler
++ ** may be invoked during, according to the comment above
++ ** sqlite3PagerSetBusyhandler().
++ */
++ assert( (pPager->eLock>=locktype)
++ || (pPager->eLock==NO_LOCK && locktype==SHARED_LOCK)
++ || (pPager->eLock==RESERVED_LOCK && locktype==EXCLUSIVE_LOCK)
++ );
+
+- /* Unmap the database file. It is possible that external processes
+- ** may have truncated the database file and then extended it back
+- ** to its original size while this process was not holding a lock.
+- ** In this case there may exist a Pager.pMap mapping that appears
+- ** to be the right size but is not actually valid. Avoid this
+- ** possibility by unmapping the db here. */
+- if( USEFETCH(pPager) ){
+- sqlite3OsUnfetch(pPager->fd, 0, 0);
+- }
+- }
+- }
++ do {
++ rc = pagerLockDb(pPager, locktype);
++ }while( rc==SQLITE_BUSY && pPager->xBusyHandler(pPager->pBusyHandlerArg) );
++ return rc;
++}
+
+- /* If there is a WAL file in the file-system, open this database in WAL
+- ** mode. Otherwise, the following function call is a no-op.
+- */
+- rc = pagerOpenWalIfPresent(pPager);
+-#ifndef SQLITE_OMIT_WAL
+- assert( pPager->pWal==0 || rc==SQLITE_OK );
++/*
++** Function assertTruncateConstraint(pPager) checks that one of the
++** following is true for all dirty pages currently in the page-cache:
++**
++** a) The page number is less than or equal to the size of the
++** current database image, in pages, OR
++**
++** b) if the page content were written at this time, it would not
++** be necessary to write the current content out to the sub-journal
++** (as determined by function subjRequiresPage()).
++**
++** If the condition asserted by this function were not true, and the
++** dirty page were to be discarded from the cache via the pagerStress()
++** routine, pagerStress() would not write the current page content to
++** the database file. If a savepoint transaction were rolled back after
++** this happened, the correct behavior would be to restore the current
++** content of the page. However, since this content is not present in either
++** the database file or the portion of the rollback journal and
++** sub-journal rolled back the content could not be restored and the
++** database image would become corrupt. It is therefore fortunate that
++** this circumstance cannot arise.
++*/
++#if defined(SQLITE_DEBUG)
++static void assertTruncateConstraintCb(PgHdr *pPg){
++ assert( pPg->flags&PGHDR_DIRTY );
++ assert( !subjRequiresPage(pPg) || pPg->pgno<=pPg->pPager->dbSize );
++}
++static void assertTruncateConstraint(Pager *pPager){
++ sqlite3PcacheIterateDirty(pPager->pPCache, assertTruncateConstraintCb);
++}
++#else
++# define assertTruncateConstraint(pPager)
+ #endif
++
++/*
++** Truncate the in-memory database file image to nPage pages. This
++** function does not actually modify the database file on disk. It
++** just sets the internal state of the pager object so that the
++** truncation will be done when the current transaction is committed.
++**
++** This function is only called right before committing a transaction.
++** Once this function has been called, the transaction must either be
++** rolled back or committed. It is not safe to call this function and
++** then continue writing to the database.
++*/
++SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){
++ assert( pPager->dbSize>=nPage );
++ assert( pPager->eState>=PAGER_WRITER_CACHEMOD );
++ pPager->dbSize = nPage;
++
++ /* At one point the code here called assertTruncateConstraint() to
++ ** ensure that all pages being truncated away by this operation are,
++ ** if one or more savepoints are open, present in the savepoint
++ ** journal so that they can be restored if the savepoint is rolled
++ ** back. This is no longer necessary as this function is now only
++ ** called right before committing a transaction. So although the
++ ** Pager object may still have open savepoints (Pager.nSavepoint!=0),
++ ** they cannot be rolled back. So the assertTruncateConstraint() call
++ ** is no longer correct. */
++}
++
++
++/*
++** This function is called before attempting a hot-journal rollback. It
++** syncs the journal file to disk, then sets pPager->journalHdr to the
++** size of the journal file so that the pager_playback() routine knows
++** that the entire journal file has been synced.
++**
++** Syncing a hot-journal to disk before attempting to roll it back ensures
++** that if a power-failure occurs during the rollback, the process that
++** attempts rollback following system recovery sees the same journal
++** content as this process.
++**
++** If everything goes as planned, SQLITE_OK is returned. Otherwise,
++** an SQLite error code.
++*/
++static int pagerSyncHotJournal(Pager *pPager){
++ int rc = SQLITE_OK;
++ if( !pPager->noSync ){
++ rc = sqlite3OsSync(pPager->jfd, SQLITE_SYNC_NORMAL);
++ }
++ if( rc==SQLITE_OK ){
++ rc = sqlite3OsFileSize(pPager->jfd, &pPager->journalHdr);
++ }
++ return rc;
++}
++
++/*
++** Obtain a reference to a memory mapped page object for page number pgno.
++** The new object will use the pointer pData, obtained from xFetch().
++** If successful, set *ppPage to point to the new page reference
++** and return SQLITE_OK. Otherwise, return an SQLite error code and set
++** *ppPage to zero.
++**
++** Page references obtained by calling this function should be released
++** by calling pagerReleaseMapPage().
++*/
++static int pagerAcquireMapPage(
++ Pager *pPager, /* Pager object */
++ Pgno pgno, /* Page number */
++ void *pData, /* xFetch()'d data for this page */
++ PgHdr **ppPage /* OUT: Acquired page object */
++){
++ PgHdr *p; /* Memory mapped page to return */
++
++ if( pPager->pMmapFreelist ){
++ *ppPage = p = pPager->pMmapFreelist;
++ pPager->pMmapFreelist = p->pDirty;
++ p->pDirty = 0;
++ memset(p->pExtra, 0, pPager->nExtra);
++ }else{
++ *ppPage = p = (PgHdr *)sqlite3MallocZero(sizeof(PgHdr) + pPager->nExtra);
++ if( p==0 ){
++ sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1) * pPager->pageSize, pData);
++ return SQLITE_NOMEM;
++ }
++ p->pExtra = (void *)&p[1];
++ p->flags = PGHDR_MMAP;
++ p->nRef = 1;
++ p->pPager = pPager;
+ }
+
+- if( pagerUseWal(pPager) ){
+- assert( rc==SQLITE_OK );
+- rc = pagerBeginReadTransaction(pPager);
+- }
++ assert( p->pExtra==(void *)&p[1] );
++ assert( p->pPage==0 );
++ assert( p->flags==PGHDR_MMAP );
++ assert( p->pPager==pPager );
++ assert( p->nRef==1 );
+
+- if( pPager->eState==PAGER_OPEN && rc==SQLITE_OK ){
+- rc = pagerPagecount(pPager, &pPager->dbSize);
+- }
++ p->pgno = pgno;
++ p->pData = pData;
++ pPager->nMmapOut++;
+
+- failed:
+- if( rc!=SQLITE_OK ){
+- assert( !MEMDB );
+- pager_unlock(pPager);
+- assert( pPager->eState==PAGER_OPEN );
+- }else{
+- pPager->eState = PAGER_READER;
+- }
+- return rc;
++ return SQLITE_OK;
+ }
+
+ /*
+-** If the reference count has reached zero, rollback any active
+-** transaction and unlock the pager.
+-**
+-** Except, in locking_mode=EXCLUSIVE when there is nothing to in
+-** the rollback journal, the unlock is not performed and there is
+-** nothing to rollback, so this routine is a no-op.
+-*/
+-static void pagerUnlockIfUnused(Pager *pPager){
+- if( pPager->nMmapOut==0 && (sqlite3PcacheRefCount(pPager->pPCache)==0) ){
+- pagerUnlockAndRollback(pPager);
++** Release a reference to page pPg. pPg must have been returned by an
++** earlier call to pagerAcquireMapPage().
++*/
++static void pagerReleaseMapPage(PgHdr *pPg){
++ Pager *pPager = pPg->pPager;
++ pPager->nMmapOut--;
++ pPg->pDirty = pPager->pMmapFreelist;
++ pPager->pMmapFreelist = pPg;
++
++ assert( pPager->fd->pMethods->iVersion>=3 );
++ sqlite3OsUnfetch(pPager->fd, (i64)(pPg->pgno-1)*pPager->pageSize, pPg->pData);
++}
++
++/*
++** Free all PgHdr objects stored in the Pager.pMmapFreelist list.
++*/
++static void pagerFreeMapHdrs(Pager *pPager){
++ PgHdr *p;
++ PgHdr *pNext;
++ for(p=pPager->pMmapFreelist; p; p=pNext){
++ pNext = p->pDirty;
++ sqlite3_free(p);
+ }
+ }
+
++
+ /*
+-** Acquire a reference to page number pgno in pager pPager (a page
+-** reference has type DbPage*). If the requested reference is
+-** successfully obtained, it is copied to *ppPage and SQLITE_OK returned.
+-**
+-** If the requested page is already in the cache, it is returned.
+-** Otherwise, a new page object is allocated and populated with data
+-** read from the database file. In some cases, the pcache module may
+-** choose not to allocate a new page object and may reuse an existing
+-** object with no outstanding references.
+-**
+-** The extra data appended to a page is always initialized to zeros the
+-** first time a page is loaded into memory. If the page requested is
+-** already in the cache when this function is called, then the extra
+-** data is left as it was when the page object was last used.
+-**
+-** If the database image is smaller than the requested page or if a
+-** non-zero value is passed as the noContent parameter and the
+-** requested page is not already stored in the cache, then no
+-** actual disk read occurs. In this case the memory image of the
+-** page is initialized to all zeros.
+-**
+-** If noContent is true, it means that we do not care about the contents
+-** of the page. This occurs in two scenarios:
+-**
+-** a) When reading a free-list leaf page from the database, and
+-**
+-** b) When a savepoint is being rolled back and we need to load
+-** a new page into the cache to be filled with the data read
+-** from the savepoint journal.
+-**
+-** If noContent is true, then the data returned is zeroed instead of
+-** being read from the database. Additionally, the bits corresponding
+-** to pgno in Pager.pInJournal (bitvec of pages already written to the
+-** journal file) and the PagerSavepoint.pInSavepoint bitvecs of any open
+-** savepoints are set. This means if the page is made writable at any
+-** point in the future, using a call to sqlite3PagerWrite(), its contents
+-** will not be journaled. This saves IO.
++** Shutdown the page cache. Free all memory and close all files.
+ **
+-** The acquisition might fail for several reasons. In all cases,
+-** an appropriate error code is returned and *ppPage is set to NULL.
++** If a transaction was in progress when this routine is called, that
++** transaction is rolled back. All outstanding pages are invalidated
++** and their memory is freed. Any attempt to use a page associated
++** with this page cache after this function returns will likely
++** result in a coredump.
+ **
+-** See also sqlite3PagerLookup(). Both this routine and Lookup() attempt
+-** to find a page in the in-memory cache first. If the page is not already
+-** in memory, this routine goes to disk to read it in whereas Lookup()
+-** just returns 0. This routine acquires a read-lock the first time it
+-** has to go to disk, and could also playback an old journal if necessary.
+-** Since Lookup() never goes to disk, it never has to deal with locks
+-** or journal files.
++** This function always succeeds. If a transaction is active an attempt
++** is made to roll it back. If an error occurs during the rollback
++** a hot journal may be left in the filesystem but no error is returned
++** to the caller.
+ */
+-SQLITE_PRIVATE int sqlite3PagerAcquire(
+- Pager *pPager, /* The pager open on the database file */
+- Pgno pgno, /* Page number to fetch */
+- DbPage **ppPage, /* Write a pointer to the page here */
+- int flags /* PAGER_GET_XXX flags */
+-){
+- int rc = SQLITE_OK;
+- PgHdr *pPg = 0;
+- u32 iFrame = 0; /* Frame to read from WAL file */
+- const int noContent = (flags & PAGER_GET_NOCONTENT);
+-
+- /* It is acceptable to use a read-only (mmap) page for any page except
+- ** page 1 if there is no write-transaction open or the ACQUIRE_READONLY
+- ** flag was specified by the caller. And so long as the db is not a
+- ** temporary or in-memory database. */
+- const int bMmapOk = (pgno!=1 && USEFETCH(pPager)
+- && (pPager->eState==PAGER_READER || (flags & PAGER_GET_READONLY))
+-#ifdef SQLITE_HAS_CODEC
+- && pPager->xCodec==0
+-#endif
+- );
++SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager){
++ u8 *pTmp = (u8 *)pPager->pTmpSpace;
+
+- assert( pPager->eState>=PAGER_READER );
+ assert( assert_pager_state(pPager) );
+- assert( noContent==0 || bMmapOk==0 );
+-
+- if( pgno==0 ){
+- return SQLITE_CORRUPT_BKPT;
+- }
+- pPager->hasBeenUsed = 1;
+-
+- /* If the pager is in the error state, return an error immediately.
+- ** Otherwise, request the page from the PCache layer. */
+- if( pPager->errCode!=SQLITE_OK ){
+- rc = pPager->errCode;
++ disable_simulated_io_errors();
++ sqlite3BeginBenignMalloc();
++ pagerFreeMapHdrs(pPager);
++ /* pPager->errCode = 0; */
++ pPager->exclusiveMode = 0;
++#ifndef SQLITE_OMIT_WAL
++ sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags, pPager->pageSize, pTmp);
++ pPager->pWal = 0;
++#endif
++ pager_reset(pPager);
++ if( MEMDB ){
++ pager_unlock(pPager);
+ }else{
+- if( bMmapOk && pagerUseWal(pPager) ){
+- rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
+- if( rc!=SQLITE_OK ) goto pager_acquire_err;
+- }
+-
+- if( bMmapOk && iFrame==0 ){
+- void *pData = 0;
+-
+- rc = sqlite3OsFetch(pPager->fd,
+- (i64)(pgno-1) * pPager->pageSize, pPager->pageSize, &pData
+- );
+-
+- if( rc==SQLITE_OK && pData ){
+- if( pPager->eState>PAGER_READER ){
+- pPg = sqlite3PagerLookup(pPager, pgno);
+- }
+- if( pPg==0 ){
+- rc = pagerAcquireMapPage(pPager, pgno, pData, &pPg);
+- }else{
+- sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1)*pPager->pageSize, pData);
+- }
+- if( pPg ){
+- assert( rc==SQLITE_OK );
+- *ppPage = pPg;
+- return SQLITE_OK;
+- }
+- }
+- if( rc!=SQLITE_OK ){
+- goto pager_acquire_err;
+- }
+- }
+-
+- {
+- sqlite3_pcache_page *pBase;
+- pBase = sqlite3PcacheFetch(pPager->pPCache, pgno, 3);
+- if( pBase==0 ){
+- rc = sqlite3PcacheFetchStress(pPager->pPCache, pgno, &pBase);
+- if( rc!=SQLITE_OK ) goto pager_acquire_err;
+- }
+- pPg = *ppPage = sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pBase);
+- if( pPg==0 ) rc = SQLITE_NOMEM;
++ /* If it is open, sync the journal file before calling UnlockAndRollback.
++ ** If this is not done, then an unsynced portion of the open journal
++ ** file may be played back into the database. If a power failure occurs
++ ** while this is happening, the database could become corrupt.
++ **
++ ** If an error occurs while trying to sync the journal, shift the pager
++ ** into the ERROR state. This causes UnlockAndRollback to unlock the
++ ** database and close the journal file without attempting to roll it
++ ** back or finalize it. The next database user will have to do hot-journal
++ ** rollback before accessing the database file.
++ */
++ if( isOpen(pPager->jfd) ){
++ pager_error(pPager, pagerSyncHotJournal(pPager));
+ }
++ pagerUnlockAndRollback(pPager);
+ }
++ sqlite3EndBenignMalloc();
++ enable_simulated_io_errors();
++ PAGERTRACE(("CLOSE %d\n", PAGERID(pPager)));
++ IOTRACE(("CLOSE %p\n", pPager))
++ sqlite3OsClose(pPager->jfd);
++ sqlite3OsClose(pPager->fd);
++ sqlite3PageFree(pTmp);
++ sqlite3PcacheClose(pPager->pPCache);
+
+- if( rc!=SQLITE_OK ){
+- /* Either the call to sqlite3PcacheFetch() returned an error or the
+- ** pager was already in the error-state when this function was called.
+- ** Set pPg to 0 and jump to the exception handler. */
+- pPg = 0;
+- goto pager_acquire_err;
+- }
+- assert( (*ppPage)->pgno==pgno );
+- assert( (*ppPage)->pPager==pPager || (*ppPage)->pPager==0 );
+-
+- if( (*ppPage)->pPager && !noContent ){
+- /* In this case the pcache already contains an initialized copy of
+- ** the page. Return without further ado. */
+- assert( pgno<=PAGER_MAX_PGNO && pgno!=PAGER_MJ_PGNO(pPager) );
+- pPager->aStat[PAGER_STAT_HIT]++;
+- return SQLITE_OK;
+-
+- }else{
+- /* The pager cache has created a new page. Its content needs to
+- ** be initialized. */
+-
+- pPg = *ppPage;
+- pPg->pPager = pPager;
+-
+- /* The maximum page number is 2^31. Return SQLITE_CORRUPT if a page
+- ** number greater than this, or the unused locking-page, is requested. */
+- if( pgno>PAGER_MAX_PGNO || pgno==PAGER_MJ_PGNO(pPager) ){
+- rc = SQLITE_CORRUPT_BKPT;
+- goto pager_acquire_err;
+- }
++#ifdef SQLITE_HAS_CODEC
++ if( pPager->xCodecFree ) pPager->xCodecFree(pPager->pCodec);
++#endif
+
+- if( MEMDB || pPager->dbSize<pgno || noContent || !isOpen(pPager->fd) ){
+- if( pgno>pPager->mxPgno ){
+- rc = SQLITE_FULL;
+- goto pager_acquire_err;
+- }
+- if( noContent ){
+- /* Failure to set the bits in the InJournal bit-vectors is benign.
+- ** It merely means that we might do some extra work to journal a
+- ** page that does not need to be journaled. Nevertheless, be sure
+- ** to test the case where a malloc error occurs while trying to set
+- ** a bit in a bit vector.
+- */
+- sqlite3BeginBenignMalloc();
+- if( pgno<=pPager->dbOrigSize ){
+- TESTONLY( rc = ) sqlite3BitvecSet(pPager->pInJournal, pgno);
+- testcase( rc==SQLITE_NOMEM );
+- }
+- TESTONLY( rc = ) addToSavepointBitvecs(pPager, pgno);
+- testcase( rc==SQLITE_NOMEM );
+- sqlite3EndBenignMalloc();
+- }
+- memset(pPg->pData, 0, pPager->pageSize);
+- IOTRACE(("ZERO %p %d\n", pPager, pgno));
+- }else{
+- if( pagerUseWal(pPager) && bMmapOk==0 ){
+- rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
+- if( rc!=SQLITE_OK ) goto pager_acquire_err;
+- }
+- assert( pPg->pPager==pPager );
+- pPager->aStat[PAGER_STAT_MISS]++;
+- rc = readDbPage(pPg, iFrame);
+- if( rc!=SQLITE_OK ){
+- goto pager_acquire_err;
+- }
+- }
+- pager_set_pagehash(pPg);
+- }
++ assert( !pPager->aSavepoint && !pPager->pInJournal );
++ assert( !isOpen(pPager->jfd) && !isOpen(pPager->sjfd) );
+
++ sqlite3_free(pPager);
+ return SQLITE_OK;
+-
+-pager_acquire_err:
+- assert( rc!=SQLITE_OK );
+- if( pPg ){
+- sqlite3PcacheDrop(pPg);
+- }
+- pagerUnlockIfUnused(pPager);
+-
+- *ppPage = 0;
+- return rc;
+ }
+
++#if !defined(NDEBUG) || defined(SQLITE_TEST)
+ /*
+-** Acquire a page if it is already in the in-memory cache. Do
+-** not read the page from disk. Return a pointer to the page,
+-** or 0 if the page is not in cache.
+-**
+-** See also sqlite3PagerGet(). The difference between this routine
+-** and sqlite3PagerGet() is that _get() will go to the disk and read
+-** in the page if the page is not already in cache. This routine
+-** returns NULL if the page is not in cache or if a disk I/O error
+-** has ever happened.
++** Return the page number for page pPg.
+ */
+-SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
+- sqlite3_pcache_page *pPage;
+- assert( pPager!=0 );
+- assert( pgno!=0 );
+- assert( pPager->pPCache!=0 );
+- pPage = sqlite3PcacheFetch(pPager->pPCache, pgno, 0);
+- assert( pPage==0 || pPager->hasBeenUsed );
+- return sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pPage);
++SQLITE_PRIVATE Pgno sqlite3PagerPagenumber(DbPage *pPg){
++ return pPg->pgno;
+ }
++#endif
+
+ /*
+-** Release a page reference.
+-**
+-** If the number of references to the page drop to zero, then the
+-** page is added to the LRU list. When all references to all pages
+-** are released, a rollback occurs and the lock on the database is
+-** removed.
++** Increment the reference count for page pPg.
+ */
+-SQLITE_PRIVATE void sqlite3PagerUnrefNotNull(DbPage *pPg){
+- Pager *pPager;
+- assert( pPg!=0 );
+- pPager = pPg->pPager;
+- if( pPg->flags & PGHDR_MMAP ){
+- pagerReleaseMapPage(pPg);
+- }else{
+- sqlite3PcacheRelease(pPg);
+- }
+- pagerUnlockIfUnused(pPager);
+-}
+-SQLITE_PRIVATE void sqlite3PagerUnref(DbPage *pPg){
+- if( pPg ) sqlite3PagerUnrefNotNull(pPg);
++SQLITE_PRIVATE void sqlite3PagerRef(DbPage *pPg){
++ sqlite3PcacheRef(pPg);
+ }
+
+ /*
+-** This function is called at the start of every write transaction.
+-** There must already be a RESERVED or EXCLUSIVE lock on the database
+-** file when this routine is called.
++** Sync the journal. In other words, make sure all the pages that have
++** been written to the journal have actually reached the surface of the
++** disk and can be restored in the event of a hot-journal rollback.
+ **
+-** Open the journal file for pager pPager and write a journal header
+-** to the start of it. If there are active savepoints, open the sub-journal
+-** as well. This function is only used when the journal file is being
+-** opened to write a rollback log for a transaction. It is not used
+-** when opening a hot journal file to roll it back.
++** If the Pager.noSync flag is set, then this function is a no-op.
++** Otherwise, the actions required depend on the journal-mode and the
++** device characteristics of the file-system, as follows:
+ **
+-** If the journal file is already open (as it may be in exclusive mode),
+-** then this function just writes a journal header to the start of the
+-** already open file.
++** * If the journal file is an in-memory journal file, no action need
++** be taken.
+ **
+-** Whether or not the journal file is opened by this function, the
+-** Pager.pInJournal bitvec structure is allocated.
++** * Otherwise, if the device does not support the SAFE_APPEND property,
++** then the nRec field of the most recently written journal header
++** is updated to contain the number of journal records that have
++** been written following it. If the pager is operating in full-sync
++** mode, then the journal file is synced before this field is updated.
+ **
+-** Return SQLITE_OK if everything is successful. Otherwise, return
+-** SQLITE_NOMEM if the attempt to allocate Pager.pInJournal fails, or
+-** an IO error code if opening or writing the journal file fails.
++** * If the device does not support the SEQUENTIAL property, then
++** journal file is synced.
++**
++** Or, in pseudo-code:
++**
++** if( NOT <in-memory journal> ){
++** if( NOT SAFE_APPEND ){
++** if( <full-sync mode> ) xSync(<journal file>);
++** <update nRec field>
++** }
++** if( NOT SEQUENTIAL ) xSync(<journal file>);
++** }
++**
++** If successful, this routine clears the PGHDR_NEED_SYNC flag of every
++** page currently held in memory before returning SQLITE_OK. If an IO
++** error is encountered, then the IO error code is returned to the caller.
+ */
+-static int pager_open_journal(Pager *pPager){
+- int rc = SQLITE_OK; /* Return code */
+- sqlite3_vfs * const pVfs = pPager->pVfs; /* Local cache of vfs pointer */
++static int syncJournal(Pager *pPager, int newHdr){
++ int rc; /* Return code */
+
+- assert( pPager->eState==PAGER_WRITER_LOCKED );
++ assert( pPager->eState==PAGER_WRITER_CACHEMOD
++ || pPager->eState==PAGER_WRITER_DBMOD
++ );
+ assert( assert_pager_state(pPager) );
+- assert( pPager->pInJournal==0 );
+-
+- /* If already in the error state, this function is a no-op. But on
+- ** the other hand, this routine is never called if we are already in
+- ** an error state. */
+- if( NEVER(pPager->errCode) ) return pPager->errCode;
++ assert( !pagerUseWal(pPager) );
+
+- if( !pagerUseWal(pPager) && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){
+- pPager->pInJournal = sqlite3BitvecCreate(pPager->dbSize);
+- if( pPager->pInJournal==0 ){
+- return SQLITE_NOMEM;
+- }
+-
+- /* Open the journal file if it is not already open. */
+- if( !isOpen(pPager->jfd) ){
+- if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ){
+- sqlite3MemJournalOpen(pPager->jfd);
+- }else{
+- const int flags = /* VFS flags to open journal file */
+- SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|
+- (pPager->tempFile ?
+- (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL):
+- (SQLITE_OPEN_MAIN_JOURNAL)
+- );
++ rc = sqlite3PagerExclusiveLock(pPager);
++ if( rc!=SQLITE_OK ) return rc;
+
+- /* Verify that the database still has the same name as it did when
+- ** it was originally opened. */
+- rc = databaseIsUnmoved(pPager);
+- if( rc==SQLITE_OK ){
+-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+- rc = sqlite3JournalOpen(
+- pVfs, pPager->zJournal, pPager->jfd, flags, jrnlBufferSize(pPager)
+- );
+-#else
+- rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags, 0);
+-#endif
++ if( !pPager->noSync ){
++ assert( !pPager->tempFile );
++ if( isOpen(pPager->jfd) && pPager->journalMode!=PAGER_JOURNALMODE_MEMORY ){
++ const int iDc = sqlite3OsDeviceCharacteristics(pPager->fd);
++ assert( isOpen(pPager->jfd) );
++
++ if( 0==(iDc&SQLITE_IOCAP_SAFE_APPEND) ){
++ /* This block deals with an obscure problem. If the last connection
++ ** that wrote to this database was operating in persistent-journal
++ ** mode, then the journal file may at this point actually be larger
++ ** than Pager.journalOff bytes. If the next thing in the journal
++ ** file happens to be a journal-header (written as part of the
++ ** previous connection's transaction), and a crash or power-failure
++ ** occurs after nRec is updated but before this connection writes
++ ** anything else to the journal file (or commits/rolls back its
++ ** transaction), then SQLite may become confused when doing the
++ ** hot-journal rollback following recovery. It may roll back all
++ ** of this connections data, then proceed to rolling back the old,
++ ** out-of-date data that follows it. Database corruption.
++ **
++ ** To work around this, if the journal file does appear to contain
++ ** a valid header following Pager.journalOff, then write a 0x00
++ ** byte to the start of it to prevent it from being recognized.
++ **
++ ** Variable iNextHdrOffset is set to the offset at which this
++ ** problematic header will occur, if it exists. aMagic is used
++ ** as a temporary buffer to inspect the first couple of bytes of
++ ** the potential journal header.
++ */
++ i64 iNextHdrOffset;
++ u8 aMagic[8];
++ u8 zHeader[sizeof(aJournalMagic)+4];
++
++ memcpy(zHeader, aJournalMagic, sizeof(aJournalMagic));
++ put32bits(&zHeader[sizeof(aJournalMagic)], pPager->nRec);
++
++ iNextHdrOffset = journalHdrOffset(pPager);
++ rc = sqlite3OsRead(pPager->jfd, aMagic, 8, iNextHdrOffset);
++ if( rc==SQLITE_OK && 0==memcmp(aMagic, aJournalMagic, 8) ){
++ static const u8 zerobyte = 0;
++ rc = sqlite3OsWrite(pPager->jfd, &zerobyte, 1, iNextHdrOffset);
++ }
++ if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){
++ return rc;
++ }
++
++ /* Write the nRec value into the journal file header. If in
++ ** full-synchronous mode, sync the journal first. This ensures that
++ ** all data has really hit the disk before nRec is updated to mark
++ ** it as a candidate for rollback.
++ **
++ ** This is not required if the persistent media supports the
++ ** SAFE_APPEND property. Because in this case it is not possible
++ ** for garbage data to be appended to the file, the nRec field
++ ** is populated with 0xFFFFFFFF when the journal header is written
++ ** and never needs to be updated.
++ */
++ if( pPager->fullSync && 0==(iDc&SQLITE_IOCAP_SEQUENTIAL) ){
++ PAGERTRACE(("SYNC journal of %d\n", PAGERID(pPager)));
++ IOTRACE(("JSYNC %p\n", pPager))
++ rc = sqlite3OsSync(pPager->jfd, pPager->syncFlags);
++ if( rc!=SQLITE_OK ) return rc;
+ }
++ IOTRACE(("JHDR %p %lld\n", pPager, pPager->journalHdr));
++ rc = sqlite3OsWrite(
++ pPager->jfd, zHeader, sizeof(zHeader), pPager->journalHdr
++ );
++ if( rc!=SQLITE_OK ) return rc;
++ }
++ if( 0==(iDc&SQLITE_IOCAP_SEQUENTIAL) ){
++ PAGERTRACE(("SYNC journal of %d\n", PAGERID(pPager)));
++ IOTRACE(("JSYNC %p\n", pPager))
++ rc = sqlite3OsSync(pPager->jfd, pPager->syncFlags|
++ (pPager->syncFlags==SQLITE_SYNC_FULL?SQLITE_SYNC_DATAONLY:0)
++ );
++ if( rc!=SQLITE_OK ) return rc;
+ }
+- assert( rc!=SQLITE_OK || isOpen(pPager->jfd) );
+- }
+-
+-
+- /* Write the first journal header to the journal file and open
+- ** the sub-journal if necessary.
+- */
+- if( rc==SQLITE_OK ){
+- /* TODO: Check if all of these are really required. */
+- pPager->nRec = 0;
+- pPager->journalOff = 0;
+- pPager->setMaster = 0;
+- pPager->journalHdr = 0;
+- rc = writeJournalHdr(pPager);
+- }
+- }
+
+- if( rc!=SQLITE_OK ){
+- sqlite3BitvecDestroy(pPager->pInJournal);
+- pPager->pInJournal = 0;
+- }else{
+- assert( pPager->eState==PAGER_WRITER_LOCKED );
+- pPager->eState = PAGER_WRITER_CACHEMOD;
++ pPager->journalHdr = pPager->journalOff;
++ if( newHdr && 0==(iDc&SQLITE_IOCAP_SAFE_APPEND) ){
++ pPager->nRec = 0;
++ rc = writeJournalHdr(pPager);
++ if( rc!=SQLITE_OK ) return rc;
++ }
++ }else{
++ pPager->journalHdr = pPager->journalOff;
++ }
+ }
+
+- return rc;
++ /* Unless the pager is in noSync mode, the journal file was just
++ ** successfully synced. Either way, clear the PGHDR_NEED_SYNC flag on
++ ** all pages.
++ */
++ sqlite3PcacheClearSyncFlags(pPager->pPCache);
++ pPager->eState = PAGER_WRITER_DBMOD;
++ assert( assert_pager_state(pPager) );
++ return SQLITE_OK;
+ }
+
+ /*
+-** Begin a write-transaction on the specified pager object. If a
+-** write-transaction has already been opened, this function is a no-op.
++** The argument is the first in a linked list of dirty pages connected
++** by the PgHdr.pDirty pointer. This function writes each one of the
++** in-memory pages in the list to the database file. The argument may
++** be NULL, representing an empty list. In this case this function is
++** a no-op.
+ **
+-** If the exFlag argument is false, then acquire at least a RESERVED
+-** lock on the database file. If exFlag is true, then acquire at least
+-** an EXCLUSIVE lock. If such a lock is already held, no locking
+-** functions need be called.
++** The pager must hold at least a RESERVED lock when this function
++** is called. Before writing anything to the database file, this lock
++** is upgraded to an EXCLUSIVE lock. If the lock cannot be obtained,
++** SQLITE_BUSY is returned and no data is written to the database file.
++**
++** If the pager is a temp-file pager and the actual file-system file
++** is not yet open, it is created and opened before any data is
++** written out.
+ **
+-** If the subjInMemory argument is non-zero, then any sub-journal opened
+-** within this transaction will be opened as an in-memory file. This
+-** has no effect if the sub-journal is already opened (as it may be when
+-** running in exclusive mode) or if the transaction does not require a
+-** sub-journal. If the subjInMemory argument is zero, then any required
+-** sub-journal is implemented in-memory if pPager is an in-memory database,
+-** or using a temporary file otherwise.
++** Once the lock has been upgraded and, if necessary, the file opened,
++** the pages are written out to the database file in list order. Writing
++** a page is skipped if it meets either of the following criteria:
++**
++** * The page number is greater than Pager.dbSize, or
++** * The PGHDR_DONT_WRITE flag is set on the page.
++**
++** If writing out a page causes the database file to grow, Pager.dbFileSize
++** is updated accordingly. If page 1 is written out, then the value cached
++** in Pager.dbFileVers[] is updated to match the new value stored in
++** the database file.
++**
++** If everything is successful, SQLITE_OK is returned. If an IO error
++** occurs, an IO error code is returned. Or, if the EXCLUSIVE lock cannot
++** be obtained, SQLITE_BUSY is returned.
+ */
+-SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory){
+- int rc = SQLITE_OK;
++static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
++ int rc = SQLITE_OK; /* Return code */
+
+- if( pPager->errCode ) return pPager->errCode;
+- assert( pPager->eState>=PAGER_READER && pPager->eState<PAGER_ERROR );
+- pPager->subjInMemory = (u8)subjInMemory;
++ /* This function is only called for rollback pagers in WRITER_DBMOD state. */
++ assert( !pagerUseWal(pPager) );
++ assert( pPager->eState==PAGER_WRITER_DBMOD );
++ assert( pPager->eLock==EXCLUSIVE_LOCK );
+
+- if( ALWAYS(pPager->eState==PAGER_READER) ){
+- assert( pPager->pInJournal==0 );
++ /* If the file is a temp-file has not yet been opened, open it now. It
++ ** is not possible for rc to be other than SQLITE_OK if this branch
++ ** is taken, as pager_wait_on_lock() is a no-op for temp-files.
++ */
++ if( !isOpen(pPager->fd) ){
++ assert( pPager->tempFile && rc==SQLITE_OK );
++ rc = pagerOpentemp(pPager, pPager->fd, pPager->vfsFlags);
++ }
+
+- if( pagerUseWal(pPager) ){
+- /* If the pager is configured to use locking_mode=exclusive, and an
+- ** exclusive lock on the database is not already held, obtain it now.
+- */
+- if( pPager->exclusiveMode && sqlite3WalExclusiveMode(pPager->pWal, -1) ){
+- rc = pagerLockDb(pPager, EXCLUSIVE_LOCK);
+- if( rc!=SQLITE_OK ){
+- return rc;
+- }
+- sqlite3WalExclusiveMode(pPager->pWal, 1);
+- }
++ /* Before the first write, give the VFS a hint of what the final
++ ** file size will be.
++ */
++ assert( rc!=SQLITE_OK || isOpen(pPager->fd) );
++ if( rc==SQLITE_OK
++ && pPager->dbHintSize<pPager->dbSize
++ && (pList->pDirty || pList->pgno>pPager->dbHintSize)
++ ){
++ sqlite3_int64 szFile = pPager->pageSize * (sqlite3_int64)pPager->dbSize;
++ sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_SIZE_HINT, &szFile);
++ pPager->dbHintSize = pPager->dbSize;
++ }
+
+- /* Grab the write lock on the log file. If successful, upgrade to
+- ** PAGER_RESERVED state. Otherwise, return an error code to the caller.
+- ** The busy-handler is not invoked if another connection already
+- ** holds the write-lock. If possible, the upper layer will call it.
+- */
+- rc = sqlite3WalBeginWriteTransaction(pPager->pWal);
+- }else{
+- /* Obtain a RESERVED lock on the database file. If the exFlag parameter
+- ** is true, then immediately upgrade this to an EXCLUSIVE lock. The
+- ** busy-handler callback can be used when upgrading to the EXCLUSIVE
+- ** lock, but not when obtaining the RESERVED lock.
++ while( rc==SQLITE_OK && pList ){
++ Pgno pgno = pList->pgno;
++
++ /* If there are dirty pages in the page cache with page numbers greater
++ ** than Pager.dbSize, this means sqlite3PagerTruncateImage() was called to
++ ** make the file smaller (presumably by auto-vacuum code). Do not write
++ ** any such pages to the file.
++ **
++ ** Also, do not write out any page that has the PGHDR_DONT_WRITE flag
++ ** set (set by sqlite3PagerDontWrite()).
++ */
++ if( pgno<=pPager->dbSize && 0==(pList->flags&PGHDR_DONT_WRITE) ){
++ i64 offset = (pgno-1)*(i64)pPager->pageSize; /* Offset to write */
++ char *pData; /* Data to write */
++
++ assert( (pList->flags&PGHDR_NEED_SYNC)==0 );
++ if( pList->pgno==1 ) pager_write_changecounter(pList);
++
++ /* Encode the database */
++ CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM, pData);
++
++ /* Write out the page data. */
++ rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset);
++
++ /* If page 1 was just written, update Pager.dbFileVers to match
++ ** the value now stored in the database file. If writing this
++ ** page caused the database file to grow, update dbFileSize.
+ */
+- rc = pagerLockDb(pPager, RESERVED_LOCK);
+- if( rc==SQLITE_OK && exFlag ){
+- rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
++ if( pgno==1 ){
++ memcpy(&pPager->dbFileVers, &pData[24], sizeof(pPager->dbFileVers));
+ }
+- }
++ if( pgno>pPager->dbFileSize ){
++ pPager->dbFileSize = pgno;
++ }
++ pPager->aStat[PAGER_STAT_WRITE]++;
+
+- if( rc==SQLITE_OK ){
+- /* Change to WRITER_LOCKED state.
+- **
+- ** WAL mode sets Pager.eState to PAGER_WRITER_LOCKED or CACHEMOD
+- ** when it has an open transaction, but never to DBMOD or FINISHED.
+- ** This is because in those states the code to roll back savepoint
+- ** transactions may copy data from the sub-journal into the database
+- ** file as well as into the page cache. Which would be incorrect in
+- ** WAL mode.
+- */
+- pPager->eState = PAGER_WRITER_LOCKED;
+- pPager->dbHintSize = pPager->dbSize;
+- pPager->dbFileSize = pPager->dbSize;
+- pPager->dbOrigSize = pPager->dbSize;
+- pPager->journalOff = 0;
+- }
++ /* Update any backup objects copying the contents of this pager. */
++ sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)pList->pData);
+
+- assert( rc==SQLITE_OK || pPager->eState==PAGER_READER );
+- assert( rc!=SQLITE_OK || pPager->eState==PAGER_WRITER_LOCKED );
+- assert( assert_pager_state(pPager) );
++ PAGERTRACE(("STORE %d page %d hash(%08x)\n",
++ PAGERID(pPager), pgno, pager_pagehash(pList)));
++ IOTRACE(("PGOUT %p %d\n", pPager, pgno));
++ PAGER_INCR(sqlite3_pager_writedb_count);
++ }else{
++ PAGERTRACE(("NOSTORE %d page %d\n", PAGERID(pPager), pgno));
++ }
++ pager_set_pagehash(pList);
++ pList = pList->pDirty;
+ }
+
+- PAGERTRACE(("TRANSACTION %d\n", PAGERID(pPager)));
+ return rc;
+ }
+
+ /*
+-** Mark a single data page as writeable. The page is written into the
+-** main journal or sub-journal as required. If the page is written into
+-** one of the journals, the corresponding bit is set in the
+-** Pager.pInJournal bitvec and the PagerSavepoint.pInSavepoint bitvecs
+-** of any open savepoints as appropriate.
++** Ensure that the sub-journal file is open. If it is already open, this
++** function is a no-op.
++**
++** SQLITE_OK is returned if everything goes according to plan. An
++** SQLITE_IOERR_XXX error code is returned if a call to sqlite3OsOpen()
++** fails.
+ */
+-static int pager_write(PgHdr *pPg){
+- Pager *pPager = pPg->pPager;
++static int openSubJournal(Pager *pPager){
+ int rc = SQLITE_OK;
+- int inJournal;
+-
+- /* This routine is not called unless a write-transaction has already
+- ** been started. The journal file may or may not be open at this point.
+- ** It is never called in the ERROR state.
+- */
+- assert( pPager->eState==PAGER_WRITER_LOCKED
+- || pPager->eState==PAGER_WRITER_CACHEMOD
+- || pPager->eState==PAGER_WRITER_DBMOD
+- );
+- assert( assert_pager_state(pPager) );
+- assert( pPager->errCode==0 );
+- assert( pPager->readOnly==0 );
+-
+- CHECK_PAGE(pPg);
+-
+- /* The journal file needs to be opened. Higher level routines have already
+- ** obtained the necessary locks to begin the write-transaction, but the
+- ** rollback journal might not yet be open. Open it now if this is the case.
+- **
+- ** This is done before calling sqlite3PcacheMakeDirty() on the page.
+- ** Otherwise, if it were done after calling sqlite3PcacheMakeDirty(), then
+- ** an error might occur and the pager would end up in WRITER_LOCKED state
+- ** with pages marked as dirty in the cache.
+- */
+- if( pPager->eState==PAGER_WRITER_LOCKED ){
+- rc = pager_open_journal(pPager);
+- if( rc!=SQLITE_OK ) return rc;
++ if( !isOpen(pPager->sjfd) ){
++ if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY || pPager->subjInMemory ){
++ sqlite3MemJournalOpen(pPager->sjfd);
++ }else{
++ rc = pagerOpentemp(pPager, pPager->sjfd, SQLITE_OPEN_SUBJOURNAL);
++ }
+ }
+- assert( pPager->eState>=PAGER_WRITER_CACHEMOD );
+- assert( assert_pager_state(pPager) );
+-
+- /* Mark the page as dirty. If the page has already been written
+- ** to the journal then we can return right away.
+- */
+- sqlite3PcacheMakeDirty(pPg);
+- inJournal = pageInJournal(pPager, pPg);
+- if( inJournal && (pPager->nSavepoint==0 || !subjRequiresPage(pPg)) ){
+- assert( !pagerUseWal(pPager) );
+- }else{
+-
+- /* The transaction journal now exists and we have a RESERVED or an
+- ** EXCLUSIVE lock on the main database file. Write the current page to
+- ** the transaction journal if it is not there already.
+- */
+- if( !inJournal && !pagerUseWal(pPager) ){
+- assert( pagerUseWal(pPager)==0 );
+- if( pPg->pgno<=pPager->dbOrigSize && isOpen(pPager->jfd) ){
+- u32 cksum;
+- char *pData2;
+- i64 iOff = pPager->journalOff;
+-
+- /* We should never write to the journal file the page that
+- ** contains the database locks. The following assert verifies
+- ** that we do not. */
+- assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) );
+-
+- assert( pPager->journalHdr<=pPager->journalOff );
+- CODEC2(pPager, pPg->pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2);
+- cksum = pager_cksum(pPager, (u8*)pData2);
+-
+- /* Even if an IO or diskfull error occurs while journalling the
+- ** page in the block above, set the need-sync flag for the page.
+- ** Otherwise, when the transaction is rolled back, the logic in
+- ** playback_one_page() will think that the page needs to be restored
+- ** in the database file. And if an IO error occurs while doing so,
+- ** then corruption may follow.
+- */
+- pPg->flags |= PGHDR_NEED_SYNC;
++ return rc;
++}
+
+- rc = write32bits(pPager->jfd, iOff, pPg->pgno);
+- if( rc!=SQLITE_OK ) return rc;
+- rc = sqlite3OsWrite(pPager->jfd, pData2, pPager->pageSize, iOff+4);
+- if( rc!=SQLITE_OK ) return rc;
+- rc = write32bits(pPager->jfd, iOff+pPager->pageSize+4, cksum);
+- if( rc!=SQLITE_OK ) return rc;
++/*
++** Append a record of the current state of page pPg to the sub-journal.
++** It is the callers responsibility to use subjRequiresPage() to check
++** that it is really required before calling this function.
++**
++** If successful, set the bit corresponding to pPg->pgno in the bitvecs
++** for all open savepoints before returning.
++**
++** This function returns SQLITE_OK if everything is successful, an IO
++** error code if the attempt to write to the sub-journal fails, or
++** SQLITE_NOMEM if a malloc fails while setting a bit in a savepoint
++** bitvec.
++*/
++static int subjournalPage(PgHdr *pPg){
++ int rc = SQLITE_OK;
++ Pager *pPager = pPg->pPager;
++ if( pPager->journalMode!=PAGER_JOURNALMODE_OFF ){
+
+- IOTRACE(("JOUT %p %d %lld %d\n", pPager, pPg->pgno,
+- pPager->journalOff, pPager->pageSize));
+- PAGER_INCR(sqlite3_pager_writej_count);
+- PAGERTRACE(("JOURNAL %d page %d needSync=%d hash(%08x)\n",
+- PAGERID(pPager), pPg->pgno,
+- ((pPg->flags&PGHDR_NEED_SYNC)?1:0), pager_pagehash(pPg)));
++ /* Open the sub-journal, if it has not already been opened */
++ assert( pPager->useJournal );
++ assert( isOpen(pPager->jfd) || pagerUseWal(pPager) );
++ assert( isOpen(pPager->sjfd) || pPager->nSubRec==0 );
++ assert( pagerUseWal(pPager)
++ || pageInJournal(pPager, pPg)
++ || pPg->pgno>pPager->dbOrigSize
++ );
++ rc = openSubJournal(pPager);
+
+- pPager->journalOff += 8 + pPager->pageSize;
+- pPager->nRec++;
+- assert( pPager->pInJournal!=0 );
+- rc = sqlite3BitvecSet(pPager->pInJournal, pPg->pgno);
+- testcase( rc==SQLITE_NOMEM );
+- assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
+- rc |= addToSavepointBitvecs(pPager, pPg->pgno);
+- if( rc!=SQLITE_OK ){
+- assert( rc==SQLITE_NOMEM );
+- return rc;
+- }
+- }else{
+- if( pPager->eState!=PAGER_WRITER_DBMOD ){
+- pPg->flags |= PGHDR_NEED_SYNC;
+- }
+- PAGERTRACE(("APPEND %d page %d needSync=%d\n",
+- PAGERID(pPager), pPg->pgno,
+- ((pPg->flags&PGHDR_NEED_SYNC)?1:0)));
+- }
+- }
++ /* If the sub-journal was opened successfully (or was already open),
++ ** write the journal record into the file. */
++ if( rc==SQLITE_OK ){
++ void *pData = pPg->pData;
++ i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize);
++ char *pData2;
+
+- /* If the statement journal is open and the page is not in it,
+- ** then write the current page to the statement journal. Note that
+- ** the statement journal format differs from the standard journal format
+- ** in that it omits the checksums and the header.
+- */
+- if( pPager->nSavepoint>0 && subjRequiresPage(pPg) ){
+- rc = subjournalPage(pPg);
++ CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2);
++ PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno));
++ rc = write32bits(pPager->sjfd, offset, pPg->pgno);
++ if( rc==SQLITE_OK ){
++ rc = sqlite3OsWrite(pPager->sjfd, pData2, pPager->pageSize, offset+4);
++ }
+ }
+ }
+-
+- /* Update the database size and return.
+- */
+- if( pPager->dbSize<pPg->pgno ){
+- pPager->dbSize = pPg->pgno;
++ if( rc==SQLITE_OK ){
++ pPager->nSubRec++;
++ assert( pPager->nSavepoint>0 );
++ rc = addToSavepointBitvecs(pPager, pPg->pgno);
+ }
+ return rc;
+ }
+
+ /*
+-** This is a variant of sqlite3PagerWrite() that runs when the sector size
+-** is larger than the page size. SQLite makes the (reasonable) assumption that
+-** all bytes of a sector are written together by hardware. Hence, all bytes of
+-** a sector need to be journalled in case of a power loss in the middle of
+-** a write.
++** This function is called by the pcache layer when it has reached some
++** soft memory limit. The first argument is a pointer to a Pager object
++** (cast as a void*). The pager is always 'purgeable' (not an in-memory
++** database). The second argument is a reference to a page that is
++** currently dirty but has no outstanding references. The page
++** is always associated with the Pager object passed as the first
++** argument.
+ **
+-** Usually, the sector size is less than or equal to the page size, in which
+-** case pages can be individually written. This routine only runs in the exceptional
+-** case where the page size is smaller than the sector size.
++** The job of this function is to make pPg clean by writing its contents
++** out to the database file, if possible. This may involve syncing the
++** journal file.
++**
++** If successful, sqlite3PcacheMakeClean() is called on the page and
++** SQLITE_OK returned. If an IO error occurs while trying to make the
++** page clean, the IO error code is returned. If the page cannot be
++** made clean for some other reason, but no error occurs, then SQLITE_OK
++** is returned by sqlite3PcacheMakeClean() is not called.
+ */
+-static SQLITE_NOINLINE int pagerWriteLargeSector(PgHdr *pPg){
+- int rc = SQLITE_OK; /* Return code */
+- Pgno nPageCount; /* Total number of pages in database file */
+- Pgno pg1; /* First page of the sector pPg is located on. */
+- int nPage = 0; /* Number of pages starting at pg1 to journal */
+- int ii; /* Loop counter */
+- int needSync = 0; /* True if any page has PGHDR_NEED_SYNC */
+- Pager *pPager = pPg->pPager; /* The pager that owns pPg */
+- Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize);
++static int pagerStress(void *p, PgHdr *pPg){
++ Pager *pPager = (Pager *)p;
++ int rc = SQLITE_OK;
+
+- /* Set the doNotSpill NOSYNC bit to 1. This is because we cannot allow
+- ** a journal header to be written between the pages journaled by
+- ** this function.
+- */
+- assert( !MEMDB );
+- assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)==0 );
+- pPager->doNotSpill |= SPILLFLAG_NOSYNC;
++ assert( pPg->pPager==pPager );
++ assert( pPg->flags&PGHDR_DIRTY );
+
+- /* This trick assumes that both the page-size and sector-size are
+- ** an integer power of 2. It sets variable pg1 to the identifier
+- ** of the first page of the sector pPg is located on.
++ /* The doNotSpill NOSYNC bit is set during times when doing a sync of
++ ** journal (and adding a new header) is not allowed. This occurs
++ ** during calls to sqlite3PagerWrite() while trying to journal multiple
++ ** pages belonging to the same sector.
++ **
++ ** The doNotSpill ROLLBACK and OFF bits inhibits all cache spilling
++ ** regardless of whether or not a sync is required. This is set during
++ ** a rollback or by user request, respectively.
++ **
++ ** Spilling is also prohibited when in an error state since that could
++ ** lead to database corruption. In the current implementation it
++ ** is impossible for sqlite3PcacheFetch() to be called with createFlag==3
++ ** while in the error state, hence it is impossible for this routine to
++ ** be called in the error state. Nevertheless, we include a NEVER()
++ ** test for the error state as a safeguard against future changes.
+ */
+- pg1 = ((pPg->pgno-1) & ~(nPagePerSector-1)) + 1;
+-
+- nPageCount = pPager->dbSize;
+- if( pPg->pgno>nPageCount ){
+- nPage = (pPg->pgno - pg1)+1;
+- }else if( (pg1+nPagePerSector-1)>nPageCount ){
+- nPage = nPageCount+1-pg1;
+- }else{
+- nPage = nPagePerSector;
++ if( NEVER(pPager->errCode) ) return SQLITE_OK;
++ testcase( pPager->doNotSpill & SPILLFLAG_ROLLBACK );
++ testcase( pPager->doNotSpill & SPILLFLAG_OFF );
++ testcase( pPager->doNotSpill & SPILLFLAG_NOSYNC );
++ if( pPager->doNotSpill
++ && ((pPager->doNotSpill & (SPILLFLAG_ROLLBACK|SPILLFLAG_OFF))!=0
++ || (pPg->flags & PGHDR_NEED_SYNC)!=0)
++ ){
++ return SQLITE_OK;
+ }
+- assert(nPage>0);
+- assert(pg1<=pPg->pgno);
+- assert((pg1+nPage)>pPg->pgno);
+
+- for(ii=0; ii<nPage && rc==SQLITE_OK; ii++){
+- Pgno pg = pg1+ii;
+- PgHdr *pPage;
+- if( pg==pPg->pgno || !sqlite3BitvecTest(pPager->pInJournal, pg) ){
+- if( pg!=PAGER_MJ_PGNO(pPager) ){
+- rc = sqlite3PagerGet(pPager, pg, &pPage);
+- if( rc==SQLITE_OK ){
+- rc = pager_write(pPage);
+- if( pPage->flags&PGHDR_NEED_SYNC ){
+- needSync = 1;
+- }
+- sqlite3PagerUnrefNotNull(pPage);
+- }
+- }
+- }else if( (pPage = sqlite3PagerLookup(pPager, pg))!=0 ){
+- if( pPage->flags&PGHDR_NEED_SYNC ){
+- needSync = 1;
+- }
+- sqlite3PagerUnrefNotNull(pPage);
++ pPg->pDirty = 0;
++ if( pagerUseWal(pPager) ){
++ /* Write a single frame for this page to the log. */
++ if( subjRequiresPage(pPg) ){
++ rc = subjournalPage(pPg);
++ }
++ if( rc==SQLITE_OK ){
++ rc = pagerWalFrames(pPager, pPg, 0, 0);
++ }
++ }else{
++
++ /* Sync the journal file if required. */
++ if( pPg->flags&PGHDR_NEED_SYNC
++ || pPager->eState==PAGER_WRITER_CACHEMOD
++ ){
++ rc = syncJournal(pPager, 1);
++ }
++
++ /* If the page number of this page is larger than the current size of
++ ** the database image, it may need to be written to the sub-journal.
++ ** This is because the call to pager_write_pagelist() below will not
++ ** actually write data to the file in this case.
++ **
++ ** Consider the following sequence of events:
++ **
++ ** BEGIN;
++ ** <journal page X>
++ ** <modify page X>
++ ** SAVEPOINT sp;
++ ** <shrink database file to Y pages>
++ ** pagerStress(page X)
++ ** ROLLBACK TO sp;
++ **
++ ** If (X>Y), then when pagerStress is called page X will not be written
++ ** out to the database file, but will be dropped from the cache. Then,
++ ** following the "ROLLBACK TO sp" statement, reading page X will read
++ ** data from the database file. This will be the copy of page X as it
++ ** was when the transaction started, not as it was when "SAVEPOINT sp"
++ ** was executed.
++ **
++ ** The solution is to write the current data for page X into the
++ ** sub-journal file now (if it is not already there), so that it will
++ ** be restored to its current value when the "ROLLBACK TO sp" is
++ ** executed.
++ */
++ if( NEVER(
++ rc==SQLITE_OK && pPg->pgno>pPager->dbSize && subjRequiresPage(pPg)
++ ) ){
++ rc = subjournalPage(pPg);
++ }
++
++ /* Write the contents of the page out to the database file. */
++ if( rc==SQLITE_OK ){
++ assert( (pPg->flags&PGHDR_NEED_SYNC)==0 );
++ rc = pager_write_pagelist(pPager, pPg);
+ }
+ }
+
+- /* If the PGHDR_NEED_SYNC flag is set for any of the nPage pages
+- ** starting at pg1, then it needs to be set for all of them. Because
+- ** writing to any of these nPage pages may damage the others, the
+- ** journal file must contain sync()ed copies of all of them
+- ** before any of them can be written out to the database file.
+- */
+- if( rc==SQLITE_OK && needSync ){
+- assert( !MEMDB );
+- for(ii=0; ii<nPage; ii++){
+- PgHdr *pPage = sqlite3PagerLookup(pPager, pg1+ii);
+- if( pPage ){
+- pPage->flags |= PGHDR_NEED_SYNC;
+- sqlite3PagerUnrefNotNull(pPage);
+- }
+- }
++ /* Mark the page as clean. */
++ if( rc==SQLITE_OK ){
++ PAGERTRACE(("STRESS %d page %d\n", PAGERID(pPager), pPg->pgno));
++ sqlite3PcacheMakeClean(pPg);
+ }
+
+- assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)!=0 );
+- pPager->doNotSpill &= ~SPILLFLAG_NOSYNC;
+- return rc;
++ return pager_error(pPager, rc);
+ }
+
++
+ /*
+-** Mark a data page as writeable. This routine must be called before
+-** making changes to a page. The caller must check the return value
+-** of this function and be careful not to change any page data unless
+-** this routine returns SQLITE_OK.
++** Allocate and initialize a new Pager object and put a pointer to it
++** in *ppPager. The pager should eventually be freed by passing it
++** to sqlite3PagerClose().
+ **
+-** The difference between this function and pager_write() is that this
+-** function also deals with the special case where 2 or more pages
+-** fit on a single disk sector. In this case all co-resident pages
+-** must have been written to the journal file before returning.
++** The zFilename argument is the path to the database file to open.
++** If zFilename is NULL then a randomly-named temporary file is created
++** and used as the file to be cached. Temporary files are be deleted
++** automatically when they are closed. If zFilename is ":memory:" then
++** all information is held in cache. It is never written to disk.
++** This can be used to implement an in-memory database.
+ **
+-** If an error occurs, SQLITE_NOMEM or an IO error code is returned
+-** as appropriate. Otherwise, SQLITE_OK.
++** The nExtra parameter specifies the number of bytes of space allocated
++** along with each page reference. This space is available to the user
++** via the sqlite3PagerGetExtra() API.
++**
++** The flags argument is used to specify properties that affect the
++** operation of the pager. It should be passed some bitwise combination
++** of the PAGER_* flags.
++**
++** The vfsFlags parameter is a bitmask to pass to the flags parameter
++** of the xOpen() method of the supplied VFS when opening files.
++**
++** If the pager object is allocated and the specified file opened
++** successfully, SQLITE_OK is returned and *ppPager set to point to
++** the new pager object. If an error occurs, *ppPager is set to NULL
++** and error code returned. This function may return SQLITE_NOMEM
++** (sqlite3Malloc() is used to allocate memory), SQLITE_CANTOPEN or
++** various SQLITE_IO_XXX errors.
+ */
+-SQLITE_PRIVATE int sqlite3PagerWrite(PgHdr *pPg){
+- assert( (pPg->flags & PGHDR_MMAP)==0 );
+- assert( pPg->pPager->eState>=PAGER_WRITER_LOCKED );
+- assert( pPg->pPager->eState!=PAGER_ERROR );
+- assert( assert_pager_state(pPg->pPager) );
+- if( pPg->pPager->sectorSize > (u32)pPg->pPager->pageSize ){
+- return pagerWriteLargeSector(pPg);
++SQLITE_PRIVATE int sqlite3PagerOpen(
++ sqlite3_vfs *pVfs, /* The virtual file system to use */
++ Pager **ppPager, /* OUT: Return the Pager structure here */
++ const char *zFilename, /* Name of the database file to open */
++ int nExtra, /* Extra bytes append to each in-memory page */
++ int flags, /* flags controlling this file */
++ int vfsFlags, /* flags passed through to sqlite3_vfs.xOpen() */
++ void (*xReinit)(DbPage*) /* Function to reinitialize pages */
++){
++ u8 *pPtr;
++ Pager *pPager = 0; /* Pager object to allocate and return */
++ int rc = SQLITE_OK; /* Return code */
++ int tempFile = 0; /* True for temp files (incl. in-memory files) */
++ int memDb = 0; /* True if this is an in-memory file */
++ int readOnly = 0; /* True if this is a read-only file */
++ int journalFileSize; /* Bytes to allocate for each journal fd */
++ char *zPathname = 0; /* Full path to database file */
++ int nPathname = 0; /* Number of bytes in zPathname */
++ int useJournal = (flags & PAGER_OMIT_JOURNAL)==0; /* False to omit journal */
++ int pcacheSize = sqlite3PcacheSize(); /* Bytes to allocate for PCache */
++ u32 szPageDflt = SQLITE_DEFAULT_PAGE_SIZE; /* Default page size */
++ const char *zUri = 0; /* URI args to copy */
++ int nUri = 0; /* Number of bytes of URI args at *zUri */
++
++ /* Figure out how much space is required for each journal file-handle
++ ** (there are two of them, the main journal and the sub-journal). This
++ ** is the maximum space required for an in-memory journal file handle
++ ** and a regular journal file-handle. Note that a "regular journal-handle"
++ ** may be a wrapper capable of caching the first portion of the journal
++ ** file in memory to implement the atomic-write optimization (see
++ ** source file journal.c).
++ */
++ if( sqlite3JournalSize(pVfs)>sqlite3MemJournalSize() ){
++ journalFileSize = ROUND8(sqlite3JournalSize(pVfs));
+ }else{
+- return pager_write(pPg);
++ journalFileSize = ROUND8(sqlite3MemJournalSize());
+ }
+-}
+
+-/*
+-** Return TRUE if the page given in the argument was previously passed
+-** to sqlite3PagerWrite(). In other words, return TRUE if it is ok
+-** to change the content of the page.
+-*/
+-#ifndef NDEBUG
+-SQLITE_PRIVATE int sqlite3PagerIswriteable(DbPage *pPg){
+- return pPg->flags&PGHDR_DIRTY;
+-}
+-#endif
++ /* Set the output variable to NULL in case an error occurs. */
++ *ppPager = 0;
+
+-/*
+-** A call to this routine tells the pager that it is not necessary to
+-** write the information on page pPg back to the disk, even though
+-** that page might be marked as dirty. This happens, for example, when
+-** the page has been added as a leaf of the freelist and so its
+-** content no longer matters.
+-**
+-** The overlying software layer calls this routine when all of the data
+-** on the given page is unused. The pager marks the page as clean so
+-** that it does not get written to disk.
+-**
+-** Tests show that this optimization can quadruple the speed of large
+-** DELETE operations.
+-*/
+-SQLITE_PRIVATE void sqlite3PagerDontWrite(PgHdr *pPg){
+- Pager *pPager = pPg->pPager;
+- if( (pPg->flags&PGHDR_DIRTY) && pPager->nSavepoint==0 ){
+- PAGERTRACE(("DONT_WRITE page %d of %d\n", pPg->pgno, PAGERID(pPager)));
+- IOTRACE(("CLEAN %p %d\n", pPager, pPg->pgno))
+- pPg->flags |= PGHDR_DONT_WRITE;
+- pager_set_pagehash(pPg);
++#ifndef SQLITE_OMIT_MEMORYDB
++ if( flags & PAGER_MEMORY ){
++ memDb = 1;
++ if( zFilename && zFilename[0] ){
++ zPathname = sqlite3DbStrDup(0, zFilename);
++ if( zPathname==0 ) return SQLITE_NOMEM;
++ nPathname = sqlite3Strlen30(zPathname);
++ zFilename = 0;
++ }
+ }
+-}
+-
+-/*
+-** This routine is called to increment the value of the database file
+-** change-counter, stored as a 4-byte big-endian integer starting at
+-** byte offset 24 of the pager file. The secondary change counter at
+-** 92 is also updated, as is the SQLite version number at offset 96.
+-**
+-** But this only happens if the pPager->changeCountDone flag is false.
+-** To avoid excess churning of page 1, the update only happens once.
+-** See also the pager_write_changecounter() routine that does an
+-** unconditional update of the change counters.
+-**
+-** If the isDirectMode flag is zero, then this is done by calling
+-** sqlite3PagerWrite() on page 1, then modifying the contents of the
+-** page data. In this case the file will be updated when the current
+-** transaction is committed.
+-**
+-** The isDirectMode flag may only be non-zero if the library was compiled
+-** with the SQLITE_ENABLE_ATOMIC_WRITE macro defined. In this case,
+-** if isDirect is non-zero, then the database file is updated directly
+-** by writing an updated version of page 1 using a call to the
+-** sqlite3OsWrite() function.
+-*/
+-static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
+- int rc = SQLITE_OK;
++#endif
+
+- assert( pPager->eState==PAGER_WRITER_CACHEMOD
+- || pPager->eState==PAGER_WRITER_DBMOD
+- );
+- assert( assert_pager_state(pPager) );
++ /* Compute and store the full pathname in an allocated buffer pointed
++ ** to by zPathname, length nPathname. Or, if this is a temporary file,
++ ** leave both nPathname and zPathname set to 0.
++ */
++ if( zFilename && zFilename[0] ){
++ const char *z;
++ nPathname = pVfs->mxPathname+1;
++ zPathname = sqlite3DbMallocRaw(0, nPathname*2);
++ if( zPathname==0 ){
++ return SQLITE_NOMEM;
++ }
++ zPathname[0] = 0; /* Make sure initialized even if FullPathname() fails */
++ rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname);
++ nPathname = sqlite3Strlen30(zPathname);
++ z = zUri = &zFilename[sqlite3Strlen30(zFilename)+1];
++ while( *z ){
++ z += sqlite3Strlen30(z)+1;
++ z += sqlite3Strlen30(z)+1;
++ }
++ nUri = (int)(&z[1] - zUri);
++ assert( nUri>=0 );
++ if( rc==SQLITE_OK && nPathname+8>pVfs->mxPathname ){
++ /* This branch is taken when the journal path required by
++ ** the database being opened will be more than pVfs->mxPathname
++ ** bytes in length. This means the database cannot be opened,
++ ** as it will not be possible to open the journal file or even
++ ** check for a hot-journal before reading.
++ */
++ rc = SQLITE_CANTOPEN_BKPT;
++ }
++ if( rc!=SQLITE_OK ){
++ sqlite3DbFree(0, zPathname);
++ return rc;
++ }
++ }
+
+- /* Declare and initialize constant integer 'isDirect'. If the
+- ** atomic-write optimization is enabled in this build, then isDirect
+- ** is initialized to the value passed as the isDirectMode parameter
+- ** to this function. Otherwise, it is always set to zero.
++ /* Allocate memory for the Pager structure, PCache object, the
++ ** three file descriptors, the database file name and the journal
++ ** file name. The layout in memory is as follows:
+ **
+- ** The idea is that if the atomic-write optimization is not
+- ** enabled at compile time, the compiler can omit the tests of
+- ** 'isDirect' below, as well as the block enclosed in the
+- ** "if( isDirect )" condition.
++ ** Pager object (sizeof(Pager) bytes)
++ ** PCache object (sqlite3PcacheSize() bytes)
++ ** Database file handle (pVfs->szOsFile bytes)
++ ** Sub-journal file handle (journalFileSize bytes)
++ ** Main journal file handle (journalFileSize bytes)
++ ** Database file name (nPathname+1 bytes)
++ ** Journal file name (nPathname+8+1 bytes)
+ */
+-#ifndef SQLITE_ENABLE_ATOMIC_WRITE
+-# define DIRECT_MODE 0
+- assert( isDirectMode==0 );
+- UNUSED_PARAMETER(isDirectMode);
+-#else
+-# define DIRECT_MODE isDirectMode
++ pPtr = (u8 *)sqlite3MallocZero(
++ ROUND8(sizeof(*pPager)) + /* Pager structure */
++ ROUND8(pcacheSize) + /* PCache object */
++ ROUND8(pVfs->szOsFile) + /* The main db file */
++ journalFileSize * 2 + /* The two journal files */
++ nPathname + 1 + nUri + /* zFilename */
++ nPathname + 8 + 2 /* zJournal */
++#ifndef SQLITE_OMIT_WAL
++ + nPathname + 4 + 2 /* zWal */
+ #endif
++ );
++ assert( EIGHT_BYTE_ALIGNMENT(SQLITE_INT_TO_PTR(journalFileSize)) );
++ if( !pPtr ){
++ sqlite3DbFree(0, zPathname);
++ return SQLITE_NOMEM;
++ }
++ pPager = (Pager*)(pPtr);
++ pPager->pPCache = (PCache*)(pPtr += ROUND8(sizeof(*pPager)));
++ pPager->fd = (sqlite3_file*)(pPtr += ROUND8(pcacheSize));
++ pPager->sjfd = (sqlite3_file*)(pPtr += ROUND8(pVfs->szOsFile));
++ pPager->jfd = (sqlite3_file*)(pPtr += journalFileSize);
++ pPager->zFilename = (char*)(pPtr += journalFileSize);
++ assert( EIGHT_BYTE_ALIGNMENT(pPager->jfd) );
+
+- if( !pPager->changeCountDone && ALWAYS(pPager->dbSize>0) ){
+- PgHdr *pPgHdr; /* Reference to page 1 */
+-
+- assert( !pPager->tempFile && isOpen(pPager->fd) );
++ /* Fill in the Pager.zFilename and Pager.zJournal buffers, if required. */
++ if( zPathname ){
++ assert( nPathname>0 );
++ pPager->zJournal = (char*)(pPtr += nPathname + 1 + nUri);
++ memcpy(pPager->zFilename, zPathname, nPathname);
++ if( nUri ) memcpy(&pPager->zFilename[nPathname+1], zUri, nUri);
++ memcpy(pPager->zJournal, zPathname, nPathname);
++ memcpy(&pPager->zJournal[nPathname], "-journal\000", 8+2);
++ sqlite3FileSuffix3(pPager->zFilename, pPager->zJournal);
++#ifndef SQLITE_OMIT_WAL
++ pPager->zWal = &pPager->zJournal[nPathname+8+1];
++ memcpy(pPager->zWal, zPathname, nPathname);
++ memcpy(&pPager->zWal[nPathname], "-wal\000", 4+1);
++ sqlite3FileSuffix3(pPager->zFilename, pPager->zWal);
++#endif
++ sqlite3DbFree(0, zPathname);
++ }
++ pPager->pVfs = pVfs;
++ pPager->vfsFlags = vfsFlags;
+
+- /* Open page 1 of the file for writing. */
+- rc = sqlite3PagerGet(pPager, 1, &pPgHdr);
+- assert( pPgHdr==0 || rc==SQLITE_OK );
++ /* Open the pager file.
++ */
++ if( zFilename && zFilename[0] ){
++ int fout = 0; /* VFS flags returned by xOpen() */
++ rc = sqlite3OsOpen(pVfs, pPager->zFilename, pPager->fd, vfsFlags, &fout);
++ assert( !memDb );
++ readOnly = (fout&SQLITE_OPEN_READONLY);
+
+- /* If page one was fetched successfully, and this function is not
+- ** operating in direct-mode, make page 1 writable. When not in
+- ** direct mode, page 1 is always held in cache and hence the PagerGet()
+- ** above is always successful - hence the ALWAYS on rc==SQLITE_OK.
++ /* If the file was successfully opened for read/write access,
++ ** choose a default page size in case we have to create the
++ ** database file. The default page size is the maximum of:
++ **
++ ** + SQLITE_DEFAULT_PAGE_SIZE,
++ ** + The value returned by sqlite3OsSectorSize()
++ ** + The largest page size that can be written atomically.
+ */
+- if( !DIRECT_MODE && ALWAYS(rc==SQLITE_OK) ){
+- rc = sqlite3PagerWrite(pPgHdr);
+- }
+-
+ if( rc==SQLITE_OK ){
+- /* Actually do the update of the change counter */
+- pager_write_changecounter(pPgHdr);
+-
+- /* If running in direct mode, write the contents of page 1 to the file. */
+- if( DIRECT_MODE ){
+- const void *zBuf;
+- assert( pPager->dbFileSize>0 );
+- CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM, zBuf);
+- if( rc==SQLITE_OK ){
+- rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0);
+- pPager->aStat[PAGER_STAT_WRITE]++;
++ int iDc = sqlite3OsDeviceCharacteristics(pPager->fd);
++ if( !readOnly ){
++ setSectorSize(pPager);
++ assert(SQLITE_DEFAULT_PAGE_SIZE<=SQLITE_MAX_DEFAULT_PAGE_SIZE);
++ if( szPageDflt<pPager->sectorSize ){
++ if( pPager->sectorSize>SQLITE_MAX_DEFAULT_PAGE_SIZE ){
++ szPageDflt = SQLITE_MAX_DEFAULT_PAGE_SIZE;
++ }else{
++ szPageDflt = (u32)pPager->sectorSize;
++ }
+ }
+- if( rc==SQLITE_OK ){
+- /* Update the pager's copy of the change-counter. Otherwise, the
+- ** next time a read transaction is opened the cache will be
+- ** flushed (as the change-counter values will not match). */
+- const void *pCopy = (const void *)&((const char *)zBuf)[24];
+- memcpy(&pPager->dbFileVers, pCopy, sizeof(pPager->dbFileVers));
+- pPager->changeCountDone = 1;
++#ifdef SQLITE_ENABLE_ATOMIC_WRITE
++ {
++ int ii;
++ assert(SQLITE_IOCAP_ATOMIC512==(512>>8));
++ assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8));
++ assert(SQLITE_MAX_DEFAULT_PAGE_SIZE<=65536);
++ for(ii=szPageDflt; ii<=SQLITE_MAX_DEFAULT_PAGE_SIZE; ii=ii*2){
++ if( iDc&(SQLITE_IOCAP_ATOMIC|(ii>>8)) ){
++ szPageDflt = ii;
++ }
++ }
+ }
+- }else{
+- pPager->changeCountDone = 1;
++#endif
++ }
++ pPager->noLock = sqlite3_uri_boolean(zFilename, "nolock", 0);
++ if( (iDc & SQLITE_IOCAP_IMMUTABLE)!=0
++ || sqlite3_uri_boolean(zFilename, "immutable", 0) ){
++ vfsFlags |= SQLITE_OPEN_READONLY;
++ goto act_like_temp_file;
+ }
+ }
++ }else{
++ /* If a temporary file is requested, it is not opened immediately.
++ ** In this case we accept the default page size and delay actually
++ ** opening the file until the first call to OsWrite().
++ **
++ ** This branch is also run for an in-memory database. An in-memory
++ ** database is the same as a temp-file that is never written out to
++ ** disk and uses an in-memory rollback journal.
++ **
++ ** This branch also runs for files marked as immutable.
++ */
++act_like_temp_file:
++ tempFile = 1;
++ pPager->eState = PAGER_READER; /* Pretend we already have a lock */
++ pPager->eLock = EXCLUSIVE_LOCK; /* Pretend we are in EXCLUSIVE locking mode */
++ pPager->noLock = 1; /* Do no locking */
++ readOnly = (vfsFlags&SQLITE_OPEN_READONLY);
++ }
+
+- /* Release the page reference. */
+- sqlite3PagerUnref(pPgHdr);
++ /* The following call to PagerSetPagesize() serves to set the value of
++ ** Pager.pageSize and to allocate the Pager.pTmpSpace buffer.
++ */
++ if( rc==SQLITE_OK ){
++ assert( pPager->memDb==0 );
++ rc = sqlite3PagerSetPagesize(pPager, &szPageDflt, -1);
++ testcase( rc!=SQLITE_OK );
+ }
+- return rc;
++
++ /* Initialize the PCache object. */
++ if( rc==SQLITE_OK ){
++ assert( nExtra<1000 );
++ nExtra = ROUND8(nExtra);
++ rc = sqlite3PcacheOpen(szPageDflt, nExtra, !memDb,
++ !memDb?pagerStress:0, (void *)pPager, pPager->pPCache);
++ }
++
++ /* If an error occurred above, free the Pager structure and close the file.
++ */
++ if( rc!=SQLITE_OK ){
++ sqlite3OsClose(pPager->fd);
++ sqlite3PageFree(pPager->pTmpSpace);
++ sqlite3_free(pPager);
++ return rc;
++ }
++
++ PAGERTRACE(("OPEN %d %s\n", FILEHANDLEID(pPager->fd), pPager->zFilename));
++ IOTRACE(("OPEN %p %s\n", pPager, pPager->zFilename))
++
++ pPager->useJournal = (u8)useJournal;
++ /* pPager->stmtOpen = 0; */
++ /* pPager->stmtInUse = 0; */
++ /* pPager->nRef = 0; */
++ /* pPager->stmtSize = 0; */
++ /* pPager->stmtJSize = 0; */
++ /* pPager->nPage = 0; */
++ pPager->mxPgno = SQLITE_MAX_PAGE_COUNT;
++ /* pPager->state = PAGER_UNLOCK; */
++ /* pPager->errMask = 0; */
++ pPager->tempFile = (u8)tempFile;
++ assert( tempFile==PAGER_LOCKINGMODE_NORMAL
++ || tempFile==PAGER_LOCKINGMODE_EXCLUSIVE );
++ assert( PAGER_LOCKINGMODE_EXCLUSIVE==1 );
++ pPager->exclusiveMode = (u8)tempFile;
++ pPager->changeCountDone = pPager->tempFile;
++ pPager->memDb = (u8)memDb;
++ pPager->readOnly = (u8)readOnly;
++ assert( useJournal || pPager->tempFile );
++ pPager->noSync = pPager->tempFile;
++ if( pPager->noSync ){
++ assert( pPager->fullSync==0 );
++ assert( pPager->syncFlags==0 );
++ assert( pPager->walSyncFlags==0 );
++ assert( pPager->ckptSyncFlags==0 );
++ }else{
++ pPager->fullSync = 1;
++ pPager->syncFlags = SQLITE_SYNC_NORMAL;
++ pPager->walSyncFlags = SQLITE_SYNC_NORMAL | WAL_SYNC_TRANSACTIONS;
++ pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL;
++ }
++ /* pPager->pFirst = 0; */
++ /* pPager->pFirstSynced = 0; */
++ /* pPager->pLast = 0; */
++ pPager->nExtra = (u16)nExtra;
++ pPager->journalSizeLimit = SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT;
++ assert( isOpen(pPager->fd) || tempFile );
++ setSectorSize(pPager);
++ if( !useJournal ){
++ pPager->journalMode = PAGER_JOURNALMODE_OFF;
++ }else if( memDb ){
++ pPager->journalMode = PAGER_JOURNALMODE_MEMORY;
++ }
++ /* pPager->xBusyHandler = 0; */
++ /* pPager->pBusyHandlerArg = 0; */
++ pPager->xReiniter = xReinit;
++ /* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */
++ /* pPager->szMmap = SQLITE_DEFAULT_MMAP_SIZE // will be set by btree.c */
++
++ *ppPager = pPager;
++ return SQLITE_OK;
+ }
+
+-/*
+-** Sync the database file to disk. This is a no-op for in-memory databases
+-** or pages with the Pager.noSync flag set.
+-**
+-** If successful, or if called on a pager for which it is a no-op, this
+-** function returns SQLITE_OK. Otherwise, an IO error code is returned.
++
++/* Verify that the database file has not be deleted or renamed out from
++** under the pager. Return SQLITE_OK if the database is still were it ought
++** to be on disk. Return non-zero (SQLITE_READONLY_DBMOVED or some other error
++** code from sqlite3OsAccess()) if the database has gone missing.
+ */
+-SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager, const char *zMaster){
+- int rc = SQLITE_OK;
++static int databaseIsUnmoved(Pager *pPager){
++ int bHasMoved = 0;
++ int rc;
+
+- if( isOpen(pPager->fd) ){
+- void *pArg = (void*)zMaster;
+- rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SYNC, pArg);
+- if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
+- }
+- if( rc==SQLITE_OK && !pPager->noSync ){
+- assert( !MEMDB );
+- rc = sqlite3OsSync(pPager->fd, pPager->syncFlags);
++ if( pPager->tempFile ) return SQLITE_OK;
++ if( pPager->dbSize==0 ) return SQLITE_OK;
++ assert( pPager->zFilename && pPager->zFilename[0] );
++ rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_HAS_MOVED, &bHasMoved);
++ if( rc==SQLITE_NOTFOUND ){
++ /* If the HAS_MOVED file-control is unimplemented, assume that the file
++ ** has not been moved. That is the historical behavior of SQLite: prior to
++ ** version 3.8.3, it never checked */
++ rc = SQLITE_OK;
++ }else if( rc==SQLITE_OK && bHasMoved ){
++ rc = SQLITE_READONLY_DBMOVED;
+ }
+ return rc;
+ }
+
++
+ /*
+-** This function may only be called while a write-transaction is active in
+-** rollback. If the connection is in WAL mode, this call is a no-op.
+-** Otherwise, if the connection does not already have an EXCLUSIVE lock on
+-** the database file, an attempt is made to obtain one.
++** This function is called after transitioning from PAGER_UNLOCK to
++** PAGER_SHARED state. It tests if there is a hot journal present in
++** the file-system for the given pager. A hot journal is one that
++** needs to be played back. According to this function, a hot-journal
++** file exists if the following criteria are met:
+ **
+-** If the EXCLUSIVE lock is already held or the attempt to obtain it is
+-** successful, or the connection is in WAL mode, SQLITE_OK is returned.
+-** Otherwise, either SQLITE_BUSY or an SQLITE_IOERR_XXX error code is
+-** returned.
++** * The journal file exists in the file system, and
++** * No process holds a RESERVED or greater lock on the database file, and
++** * The database file itself is greater than 0 bytes in size, and
++** * The first byte of the journal file exists and is not 0x00.
++**
++** If the current size of the database file is 0 but a journal file
++** exists, that is probably an old journal left over from a prior
++** database with the same name. In this case the journal file is
++** just deleted using OsDelete, *pExists is set to 0 and SQLITE_OK
++** is returned.
++**
++** This routine does not check if there is a master journal filename
++** at the end of the file. If there is, and that master journal file
++** does not exist, then the journal file is not really hot. In this
++** case this routine will return a false-positive. The pager_playback()
++** routine will discover that the journal file is not really hot and
++** will not roll it back.
++**
++** If a hot-journal file is found to exist, *pExists is set to 1 and
++** SQLITE_OK returned. If no hot-journal file is present, *pExists is
++** set to 0 and SQLITE_OK returned. If an IO error occurs while trying
++** to determine whether or not a hot-journal file exists, the IO error
++** code is returned and the value of *pExists is undefined.
+ */
+-SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager *pPager){
+- int rc = SQLITE_OK;
+- assert( pPager->eState==PAGER_WRITER_CACHEMOD
+- || pPager->eState==PAGER_WRITER_DBMOD
+- || pPager->eState==PAGER_WRITER_LOCKED
+- );
+- assert( assert_pager_state(pPager) );
+- if( 0==pagerUseWal(pPager) ){
+- rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
++static int hasHotJournal(Pager *pPager, int *pExists){
++ sqlite3_vfs * const pVfs = pPager->pVfs;
++ int rc = SQLITE_OK; /* Return code */
++ int exists = 1; /* True if a journal file is present */
++ int jrnlOpen = !!isOpen(pPager->jfd);
++
++ assert( pPager->useJournal );
++ assert( isOpen(pPager->fd) );
++ assert( pPager->eState==PAGER_OPEN );
++
++ assert( jrnlOpen==0 || ( sqlite3OsDeviceCharacteristics(pPager->jfd) &
++ SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN
++ ));
++
++ *pExists = 0;
++ if( !jrnlOpen ){
++ rc = sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &exists);
++ }
++ if( rc==SQLITE_OK && exists ){
++ int locked = 0; /* True if some process holds a RESERVED lock */
++
++ /* Race condition here: Another process might have been holding the
++ ** the RESERVED lock and have a journal open at the sqlite3OsAccess()
++ ** call above, but then delete the journal and drop the lock before
++ ** we get to the following sqlite3OsCheckReservedLock() call. If that
++ ** is the case, this routine might think there is a hot journal when
++ ** in fact there is none. This results in a false-positive which will
++ ** be dealt with by the playback routine. Ticket #3883.
++ */
++ rc = sqlite3OsCheckReservedLock(pPager->fd, &locked);
++ if( rc==SQLITE_OK && !locked ){
++ Pgno nPage; /* Number of pages in database file */
++
++ rc = pagerPagecount(pPager, &nPage);
++ if( rc==SQLITE_OK ){
++ /* If the database is zero pages in size, that means that either (1) the
++ ** journal is a remnant from a prior database with the same name where
++ ** the database file but not the journal was deleted, or (2) the initial
++ ** transaction that populates a new database is being rolled back.
++ ** In either case, the journal file can be deleted. However, take care
++ ** not to delete the journal file if it is already open due to
++ ** journal_mode=PERSIST.
++ */
++ if( nPage==0 && !jrnlOpen ){
++ sqlite3BeginBenignMalloc();
++ if( pagerLockDb(pPager, RESERVED_LOCK)==SQLITE_OK ){
++ sqlite3OsDelete(pVfs, pPager->zJournal, 0);
++ if( !pPager->exclusiveMode ) pagerUnlockDb(pPager, SHARED_LOCK);
++ }
++ sqlite3EndBenignMalloc();
++ }else{
++ /* The journal file exists and no other connection has a reserved
++ ** or greater lock on the database file. Now check that there is
++ ** at least one non-zero bytes at the start of the journal file.
++ ** If there is, then we consider this journal to be hot. If not,
++ ** it can be ignored.
++ */
++ if( !jrnlOpen ){
++ int f = SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL;
++ rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &f);
++ }
++ if( rc==SQLITE_OK ){
++ u8 first = 0;
++ rc = sqlite3OsRead(pPager->jfd, (void *)&first, 1, 0);
++ if( rc==SQLITE_IOERR_SHORT_READ ){
++ rc = SQLITE_OK;
++ }
++ if( !jrnlOpen ){
++ sqlite3OsClose(pPager->jfd);
++ }
++ *pExists = (first!=0);
++ }else if( rc==SQLITE_CANTOPEN ){
++ /* If we cannot open the rollback journal file in order to see if
++ ** it has a zero header, that might be due to an I/O error, or
++ ** it might be due to the race condition described above and in
++ ** ticket #3883. Either way, assume that the journal is hot.
++ ** This might be a false positive. But if it is, then the
++ ** automatic journal playback and recovery mechanism will deal
++ ** with it under an EXCLUSIVE lock where we do not need to
++ ** worry so much with race conditions.
++ */
++ *pExists = 1;
++ rc = SQLITE_OK;
++ }
++ }
++ }
++ }
+ }
++
+ return rc;
+ }
+
+ /*
+-** Sync the database file for the pager pPager. zMaster points to the name
+-** of a master journal file that should be written into the individual
+-** journal file. zMaster may be NULL, which is interpreted as no master
+-** journal (a single database transaction).
+-**
+-** This routine ensures that:
++** This function is called to obtain a shared lock on the database file.
++** It is illegal to call sqlite3PagerAcquire() until after this function
++** has been successfully called. If a shared-lock is already held when
++** this function is called, it is a no-op.
+ **
+-** * The database file change-counter is updated,
+-** * the journal is synced (unless the atomic-write optimization is used),
+-** * all dirty pages are written to the database file,
+-** * the database file is truncated (if required), and
+-** * the database file synced.
++** The following operations are also performed by this function.
+ **
+-** The only thing that remains to commit the transaction is to finalize
+-** (delete, truncate or zero the first part of) the journal file (or
+-** delete the master journal file if specified).
++** 1) If the pager is currently in PAGER_OPEN state (no lock held
++** on the database file), then an attempt is made to obtain a
++** SHARED lock on the database file. Immediately after obtaining
++** the SHARED lock, the file-system is checked for a hot-journal,
++** which is played back if present. Following any hot-journal
++** rollback, the contents of the cache are validated by checking
++** the 'change-counter' field of the database file header and
++** discarded if they are found to be invalid.
+ **
+-** Note that if zMaster==NULL, this does not overwrite a previous value
+-** passed to an sqlite3PagerCommitPhaseOne() call.
++** 2) If the pager is running in exclusive-mode, and there are currently
++** no outstanding references to any pages, and is in the error state,
++** then an attempt is made to clear the error state by discarding
++** the contents of the page cache and rolling back any open journal
++** file.
+ **
+-** If the final parameter - noSync - is true, then the database file itself
+-** is not synced. The caller must call sqlite3PagerSync() directly to
+-** sync the database file before calling CommitPhaseTwo() to delete the
+-** journal file in this case.
++** If everything is successful, SQLITE_OK is returned. If an IO error
++** occurs while locking the database, checking for a hot-journal file or
++** rolling back a journal file, the IO error code is returned.
+ */
+-SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
+- Pager *pPager, /* Pager object */
+- const char *zMaster, /* If not NULL, the master journal name */
+- int noSync /* True to omit the xSync on the db file */
+-){
+- int rc = SQLITE_OK; /* Return code */
++SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
++ int rc = SQLITE_OK; /* Return code */
+
+- assert( pPager->eState==PAGER_WRITER_LOCKED
+- || pPager->eState==PAGER_WRITER_CACHEMOD
+- || pPager->eState==PAGER_WRITER_DBMOD
+- || pPager->eState==PAGER_ERROR
+- );
++ /* This routine is only called from b-tree and only when there are no
++ ** outstanding pages. This implies that the pager state should either
++ ** be OPEN or READER. READER is only possible if the pager is or was in
++ ** exclusive access mode.
++ */
++ assert( sqlite3PcacheRefCount(pPager->pPCache)==0 );
+ assert( assert_pager_state(pPager) );
++ assert( pPager->eState==PAGER_OPEN || pPager->eState==PAGER_READER );
++ if( NEVER(MEMDB && pPager->errCode) ){ return pPager->errCode; }
+
+- /* If a prior error occurred, report that error again. */
+- if( NEVER(pPager->errCode) ) return pPager->errCode;
++ if( !pagerUseWal(pPager) && pPager->eState==PAGER_OPEN ){
++ int bHotJournal = 1; /* True if there exists a hot journal-file */
+
+- PAGERTRACE(("DATABASE SYNC: File=%s zMaster=%s nSize=%d\n",
+- pPager->zFilename, zMaster, pPager->dbSize));
++ assert( !MEMDB );
+
+- /* If no database changes have been made, return early. */
+- if( pPager->eState<PAGER_WRITER_CACHEMOD ) return SQLITE_OK;
++ rc = pager_wait_on_lock(pPager, SHARED_LOCK);
++ if( rc!=SQLITE_OK ){
++ assert( pPager->eLock==NO_LOCK || pPager->eLock==UNKNOWN_LOCK );
++ goto failed;
++ }
+
+- if( MEMDB ){
+- /* If this is an in-memory db, or no pages have been written to, or this
+- ** function has already been called, it is mostly a no-op. However, any
+- ** backup in progress needs to be restarted.
++ /* If a journal file exists, and there is no RESERVED lock on the
++ ** database file, then it either needs to be played back or deleted.
+ */
+- sqlite3BackupRestart(pPager->pBackup);
+- }else{
+- if( pagerUseWal(pPager) ){
+- PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache);
+- PgHdr *pPageOne = 0;
+- if( pList==0 ){
+- /* Must have at least one page for the WAL commit flag.
+- ** Ticket [2d1a5c67dfc2363e44f29d9bbd57f] 2011-05-18 */
+- rc = sqlite3PagerGet(pPager, 1, &pPageOne);
+- pList = pPageOne;
+- pList->pDirty = 0;
+- }
+- assert( rc==SQLITE_OK );
+- if( ALWAYS(pList) ){
+- rc = pagerWalFrames(pPager, pList, pPager->dbSize, 1);
+- }
+- sqlite3PagerUnref(pPageOne);
+- if( rc==SQLITE_OK ){
+- sqlite3PcacheCleanAll(pPager->pPCache);
++ if( pPager->eLock<=SHARED_LOCK ){
++ rc = hasHotJournal(pPager, &bHotJournal);
++ }
++ if( rc!=SQLITE_OK ){
++ goto failed;
++ }
++ if( bHotJournal ){
++ if( pPager->readOnly ){
++ rc = SQLITE_READONLY_ROLLBACK;
++ goto failed;
+ }
+- }else{
+- /* The following block updates the change-counter. Exactly how it
+- ** does this depends on whether or not the atomic-update optimization
+- ** was enabled at compile time, and if this transaction meets the
+- ** runtime criteria to use the operation:
+- **
+- ** * The file-system supports the atomic-write property for
+- ** blocks of size page-size, and
+- ** * This commit is not part of a multi-file transaction, and
+- ** * Exactly one page has been modified and store in the journal file.
++
++ /* Get an EXCLUSIVE lock on the database file. At this point it is
++ ** important that a RESERVED lock is not obtained on the way to the
++ ** EXCLUSIVE lock. If it were, another process might open the
++ ** database file, detect the RESERVED lock, and conclude that the
++ ** database is safe to read while this process is still rolling the
++ ** hot-journal back.
++ **
++ ** Because the intermediate RESERVED lock is not requested, any
++ ** other process attempting to access the database file will get to
++ ** this point in the code and fail to obtain its own EXCLUSIVE lock
++ ** on the database file.
+ **
+- ** If the optimization was not enabled at compile time, then the
+- ** pager_incr_changecounter() function is called to update the change
+- ** counter in 'indirect-mode'. If the optimization is compiled in but
+- ** is not applicable to this transaction, call sqlite3JournalCreate()
+- ** to make sure the journal file has actually been created, then call
+- ** pager_incr_changecounter() to update the change-counter in indirect
+- ** mode.
++ ** Unless the pager is in locking_mode=exclusive mode, the lock is
++ ** downgraded to SHARED_LOCK before this function returns.
++ */
++ rc = pagerLockDb(pPager, EXCLUSIVE_LOCK);
++ if( rc!=SQLITE_OK ){
++ goto failed;
++ }
++
++ /* If it is not already open and the file exists on disk, open the
++ ** journal for read/write access. Write access is required because
++ ** in exclusive-access mode the file descriptor will be kept open
++ ** and possibly used for a transaction later on. Also, write-access
++ ** is usually required to finalize the journal in journal_mode=persist
++ ** mode (and also for journal_mode=truncate on some systems).
+ **
+- ** Otherwise, if the optimization is both enabled and applicable,
+- ** then call pager_incr_changecounter() to update the change-counter
+- ** in 'direct' mode. In this case the journal file will never be
+- ** created for this transaction.
++ ** If the journal does not exist, it usually means that some
++ ** other connection managed to get in and roll it back before
++ ** this connection obtained the exclusive lock above. Or, it
++ ** may mean that the pager was in the error-state when this
++ ** function was called and the journal file does not exist.
+ */
+- #ifdef SQLITE_ENABLE_ATOMIC_WRITE
+- PgHdr *pPg;
+- assert( isOpen(pPager->jfd)
+- || pPager->journalMode==PAGER_JOURNALMODE_OFF
+- || pPager->journalMode==PAGER_JOURNALMODE_WAL
+- );
+- if( !zMaster && isOpen(pPager->jfd)
+- && pPager->journalOff==jrnlBufferSize(pPager)
+- && pPager->dbSize>=pPager->dbOrigSize
+- && (0==(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty)
+- ){
+- /* Update the db file change counter via the direct-write method. The
+- ** following call will modify the in-memory representation of page 1
+- ** to include the updated change counter and then write page 1
+- ** directly to the database file. Because of the atomic-write
+- ** property of the host file-system, this is safe.
+- */
+- rc = pager_incr_changecounter(pPager, 1);
+- }else{
+- rc = sqlite3JournalCreate(pPager->jfd);
+- if( rc==SQLITE_OK ){
+- rc = pager_incr_changecounter(pPager, 0);
++ if( !isOpen(pPager->jfd) ){
++ sqlite3_vfs * const pVfs = pPager->pVfs;
++ int bExists; /* True if journal file exists */
++ rc = sqlite3OsAccess(
++ pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &bExists);
++ if( rc==SQLITE_OK && bExists ){
++ int fout = 0;
++ int f = SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_JOURNAL;
++ assert( !pPager->tempFile );
++ rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &fout);
++ assert( rc!=SQLITE_OK || isOpen(pPager->jfd) );
++ if( rc==SQLITE_OK && fout&SQLITE_OPEN_READONLY ){
++ rc = SQLITE_CANTOPEN_BKPT;
++ sqlite3OsClose(pPager->jfd);
++ }
+ }
+ }
+- #else
+- rc = pager_incr_changecounter(pPager, 0);
+- #endif
+- if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
+-
+- /* Write the master journal name into the journal file. If a master
+- ** journal file name has already been written to the journal file,
+- ** or if zMaster is NULL (no master journal), then this call is a no-op.
+- */
+- rc = writeMasterJournal(pPager, zMaster);
+- if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
+-
+- /* Sync the journal file and write all dirty pages to the database.
+- ** If the atomic-update optimization is being used, this sync will not
+- ** create the journal file or perform any real IO.
+- **
+- ** Because the change-counter page was just modified, unless the
+- ** atomic-update optimization is used it is almost certain that the
+- ** journal requires a sync here. However, in locking_mode=exclusive
+- ** on a system under memory pressure it is just possible that this is
+- ** not the case. In this case it is likely enough that the redundant
+- ** xSync() call will be changed to a no-op by the OS anyhow.
++
++ /* Playback and delete the journal. Drop the database write
++ ** lock and reacquire the read lock. Purge the cache before
++ ** playing back the hot-journal so that we don't end up with
++ ** an inconsistent cache. Sync the hot journal before playing
++ ** it back since the process that crashed and left the hot journal
++ ** probably did not sync it and we are required to always sync
++ ** the journal before playing it back.
+ */
+- rc = syncJournal(pPager, 0);
+- if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
+-
+- rc = pager_write_pagelist(pPager,sqlite3PcacheDirtyList(pPager->pPCache));
+- if( rc!=SQLITE_OK ){
+- assert( rc!=SQLITE_IOERR_BLOCKED );
+- goto commit_phase_one_exit;
++ if( isOpen(pPager->jfd) ){
++ assert( rc==SQLITE_OK );
++ rc = pagerSyncHotJournal(pPager);
++ if( rc==SQLITE_OK ){
++ rc = pager_playback(pPager, 1);
++ pPager->eState = PAGER_OPEN;
++ }
++ }else if( !pPager->exclusiveMode ){
++ pagerUnlockDb(pPager, SHARED_LOCK);
+ }
+- sqlite3PcacheCleanAll(pPager->pPCache);
+
+- /* If the file on disk is smaller than the database image, use
+- ** pager_truncate to grow the file here. This can happen if the database
+- ** image was extended as part of the current transaction and then the
+- ** last page in the db image moved to the free-list. In this case the
+- ** last page is never written out to disk, leaving the database file
+- ** undersized. Fix this now if it is the case. */
+- if( pPager->dbSize>pPager->dbFileSize ){
+- Pgno nNew = pPager->dbSize - (pPager->dbSize==PAGER_MJ_PGNO(pPager));
+- assert( pPager->eState==PAGER_WRITER_DBMOD );
+- rc = pager_truncate(pPager, nNew);
+- if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
+- }
+-
+- /* Finally, sync the database file. */
+- if( !noSync ){
+- rc = sqlite3PagerSync(pPager, zMaster);
++ if( rc!=SQLITE_OK ){
++ /* This branch is taken if an error occurs while trying to open
++ ** or roll back a hot-journal while holding an EXCLUSIVE lock. The
++ ** pager_unlock() routine will be called before returning to unlock
++ ** the file. If the unlock attempt fails, then Pager.eLock must be
++ ** set to UNKNOWN_LOCK (see the comment above the #define for
++ ** UNKNOWN_LOCK above for an explanation).
++ **
++ ** In order to get pager_unlock() to do this, set Pager.eState to
++ ** PAGER_ERROR now. This is not actually counted as a transition
++ ** to ERROR state in the state diagram at the top of this file,
++ ** since we know that the same call to pager_unlock() will very
++ ** shortly transition the pager object to the OPEN state. Calling
++ ** assert_pager_state() would fail now, as it should not be possible
++ ** to be in ERROR state when there are zero outstanding page
++ ** references.
++ */
++ pager_error(pPager, rc);
++ goto failed;
+ }
+- IOTRACE(("DBSYNC %p\n", pPager))
++
++ assert( pPager->eState==PAGER_OPEN );
++ assert( (pPager->eLock==SHARED_LOCK)
++ || (pPager->exclusiveMode && pPager->eLock>SHARED_LOCK)
++ );
+ }
+- }
+
+-commit_phase_one_exit:
+- if( rc==SQLITE_OK && !pagerUseWal(pPager) ){
+- pPager->eState = PAGER_WRITER_FINISHED;
+- }
+- return rc;
+-}
++ if( !pPager->tempFile && pPager->hasBeenUsed ){
++ /* The shared-lock has just been acquired then check to
++ ** see if the database has been modified. If the database has changed,
++ ** flush the cache. The pPager->hasBeenUsed flag prevents this from
++ ** occurring on the very first access to a file, in order to save a
++ ** single unnecessary sqlite3OsRead() call at the start-up.
++ **
++ ** Database changes is detected by looking at 15 bytes beginning
++ ** at offset 24 into the file. The first 4 of these 16 bytes are
++ ** a 32-bit counter that is incremented with each change. The
++ ** other bytes change randomly with each file change when
++ ** a codec is in use.
++ **
++ ** There is a vanishingly small chance that a change will not be
++ ** detected. The chance of an undetected change is so small that
++ ** it can be neglected.
++ */
++ Pgno nPage = 0;
++ char dbFileVers[sizeof(pPager->dbFileVers)];
+
++ rc = pagerPagecount(pPager, &nPage);
++ if( rc ) goto failed;
+
+-/*
+-** When this function is called, the database file has been completely
+-** updated to reflect the changes made by the current transaction and
+-** synced to disk. The journal file still exists in the file-system
+-** though, and if a failure occurs at this point it will eventually
+-** be used as a hot-journal and the current transaction rolled back.
+-**
+-** This function finalizes the journal file, either by deleting,
+-** truncating or partially zeroing it, so that it cannot be used
+-** for hot-journal rollback. Once this is done the transaction is
+-** irrevocably committed.
+-**
+-** If an error occurs, an IO error code is returned and the pager
+-** moves into the error state. Otherwise, SQLITE_OK is returned.
+-*/
+-SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager *pPager){
+- int rc = SQLITE_OK; /* Return code */
++ if( nPage>0 ){
++ IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers)));
++ rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24);
++ if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){
++ goto failed;
++ }
++ }else{
++ memset(dbFileVers, 0, sizeof(dbFileVers));
++ }
+
+- /* This routine should not be called if a prior error has occurred.
+- ** But if (due to a coding error elsewhere in the system) it does get
+- ** called, just return the same error code without doing anything. */
+- if( NEVER(pPager->errCode) ) return pPager->errCode;
++ if( memcmp(pPager->dbFileVers, dbFileVers, sizeof(dbFileVers))!=0 ){
++ pager_reset(pPager);
++
++ /* Unmap the database file. It is possible that external processes
++ ** may have truncated the database file and then extended it back
++ ** to its original size while this process was not holding a lock.
++ ** In this case there may exist a Pager.pMap mapping that appears
++ ** to be the right size but is not actually valid. Avoid this
++ ** possibility by unmapping the db here. */
++ if( USEFETCH(pPager) ){
++ sqlite3OsUnfetch(pPager->fd, 0, 0);
++ }
++ }
++ }
++
++ /* If there is a WAL file in the file-system, open this database in WAL
++ ** mode. Otherwise, the following function call is a no-op.
++ */
++ rc = pagerOpenWalIfPresent(pPager);
++#ifndef SQLITE_OMIT_WAL
++ assert( pPager->pWal==0 || rc==SQLITE_OK );
++#endif
++ }
+
+- assert( pPager->eState==PAGER_WRITER_LOCKED
+- || pPager->eState==PAGER_WRITER_FINISHED
+- || (pagerUseWal(pPager) && pPager->eState==PAGER_WRITER_CACHEMOD)
+- );
+- assert( assert_pager_state(pPager) );
++ if( pagerUseWal(pPager) ){
++ assert( rc==SQLITE_OK );
++ rc = pagerBeginReadTransaction(pPager);
++ }
+
+- /* An optimization. If the database was not actually modified during
+- ** this transaction, the pager is running in exclusive-mode and is
+- ** using persistent journals, then this function is a no-op.
+- **
+- ** The start of the journal file currently contains a single journal
+- ** header with the nRec field set to 0. If such a journal is used as
+- ** a hot-journal during hot-journal rollback, 0 changes will be made
+- ** to the database file. So there is no need to zero the journal
+- ** header. Since the pager is in exclusive mode, there is no need
+- ** to drop any locks either.
+- */
+- if( pPager->eState==PAGER_WRITER_LOCKED
+- && pPager->exclusiveMode
+- && pPager->journalMode==PAGER_JOURNALMODE_PERSIST
+- ){
+- assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) || !pPager->journalOff );
++ if( pPager->eState==PAGER_OPEN && rc==SQLITE_OK ){
++ rc = pagerPagecount(pPager, &pPager->dbSize);
++ }
++
++ failed:
++ if( rc!=SQLITE_OK ){
++ assert( !MEMDB );
++ pager_unlock(pPager);
++ assert( pPager->eState==PAGER_OPEN );
++ }else{
+ pPager->eState = PAGER_READER;
+- return SQLITE_OK;
+ }
++ return rc;
++}
+
+- PAGERTRACE(("COMMIT %d\n", PAGERID(pPager)));
+- pPager->iDataVersion++;
+- rc = pager_end_transaction(pPager, pPager->setMaster, 1);
+- return pager_error(pPager, rc);
++/*
++** If the reference count has reached zero, rollback any active
++** transaction and unlock the pager.
++**
++** Except, in locking_mode=EXCLUSIVE when there is nothing to in
++** the rollback journal, the unlock is not performed and there is
++** nothing to rollback, so this routine is a no-op.
++*/
++static void pagerUnlockIfUnused(Pager *pPager){
++ if( pPager->nMmapOut==0 && (sqlite3PcacheRefCount(pPager->pPCache)==0) ){
++ pagerUnlockAndRollback(pPager);
++ }
+ }
+
+ /*
+-** If a write transaction is open, then all changes made within the
+-** transaction are reverted and the current write-transaction is closed.
+-** The pager falls back to PAGER_READER state if successful, or PAGER_ERROR
+-** state if an error occurs.
++** Acquire a reference to page number pgno in pager pPager (a page
++** reference has type DbPage*). If the requested reference is
++** successfully obtained, it is copied to *ppPage and SQLITE_OK returned.
+ **
+-** If the pager is already in PAGER_ERROR state when this function is called,
+-** it returns Pager.errCode immediately. No work is performed in this case.
++** If the requested page is already in the cache, it is returned.
++** Otherwise, a new page object is allocated and populated with data
++** read from the database file. In some cases, the pcache module may
++** choose not to allocate a new page object and may reuse an existing
++** object with no outstanding references.
+ **
+-** Otherwise, in rollback mode, this function performs two functions:
++** The extra data appended to a page is always initialized to zeros the
++** first time a page is loaded into memory. If the page requested is
++** already in the cache when this function is called, then the extra
++** data is left as it was when the page object was last used.
+ **
+-** 1) It rolls back the journal file, restoring all database file and
+-** in-memory cache pages to the state they were in when the transaction
+-** was opened, and
++** If the database image is smaller than the requested page or if a
++** non-zero value is passed as the noContent parameter and the
++** requested page is not already stored in the cache, then no
++** actual disk read occurs. In this case the memory image of the
++** page is initialized to all zeros.
+ **
+-** 2) It finalizes the journal file, so that it is not used for hot
+-** rollback at any point in the future.
++** If noContent is true, it means that we do not care about the contents
++** of the page. This occurs in two scenarios:
+ **
+-** Finalization of the journal file (task 2) is only performed if the
+-** rollback is successful.
++** a) When reading a free-list leaf page from the database, and
+ **
+-** In WAL mode, all cache-entries containing data modified within the
+-** current transaction are either expelled from the cache or reverted to
+-** their pre-transaction state by re-reading data from the database or
+-** WAL files. The WAL transaction is then closed.
++** b) When a savepoint is being rolled back and we need to load
++** a new page into the cache to be filled with the data read
++** from the savepoint journal.
++**
++** If noContent is true, then the data returned is zeroed instead of
++** being read from the database. Additionally, the bits corresponding
++** to pgno in Pager.pInJournal (bitvec of pages already written to the
++** journal file) and the PagerSavepoint.pInSavepoint bitvecs of any open
++** savepoints are set. This means if the page is made writable at any
++** point in the future, using a call to sqlite3PagerWrite(), its contents
++** will not be journaled. This saves IO.
++**
++** The acquisition might fail for several reasons. In all cases,
++** an appropriate error code is returned and *ppPage is set to NULL.
++**
++** See also sqlite3PagerLookup(). Both this routine and Lookup() attempt
++** to find a page in the in-memory cache first. If the page is not already
++** in memory, this routine goes to disk to read it in whereas Lookup()
++** just returns 0. This routine acquires a read-lock the first time it
++** has to go to disk, and could also playback an old journal if necessary.
++** Since Lookup() never goes to disk, it never has to deal with locks
++** or journal files.
+ */
+-SQLITE_PRIVATE int sqlite3PagerRollback(Pager *pPager){
+- int rc = SQLITE_OK; /* Return code */
+- PAGERTRACE(("ROLLBACK %d\n", PAGERID(pPager)));
++SQLITE_PRIVATE int sqlite3PagerAcquire(
++ Pager *pPager, /* The pager open on the database file */
++ Pgno pgno, /* Page number to fetch */
++ DbPage **ppPage, /* Write a pointer to the page here */
++ int flags /* PAGER_GET_XXX flags */
++){
++ int rc = SQLITE_OK;
++ PgHdr *pPg = 0;
++ u32 iFrame = 0; /* Frame to read from WAL file */
++ const int noContent = (flags & PAGER_GET_NOCONTENT);
+
+- /* PagerRollback() is a no-op if called in READER or OPEN state. If
+- ** the pager is already in the ERROR state, the rollback is not
+- ** attempted here. Instead, the error code is returned to the caller.
+- */
++ /* It is acceptable to use a read-only (mmap) page for any page except
++ ** page 1 if there is no write-transaction open or the ACQUIRE_READONLY
++ ** flag was specified by the caller. And so long as the db is not a
++ ** temporary or in-memory database. */
++ const int bMmapOk = (pgno!=1 && USEFETCH(pPager)
++ && (pPager->eState==PAGER_READER || (flags & PAGER_GET_READONLY))
++#ifdef SQLITE_HAS_CODEC
++ && pPager->xCodec==0
++#endif
++ );
++
++ assert( pPager->eState>=PAGER_READER );
+ assert( assert_pager_state(pPager) );
+- if( pPager->eState==PAGER_ERROR ) return pPager->errCode;
+- if( pPager->eState<=PAGER_READER ) return SQLITE_OK;
++ assert( noContent==0 || bMmapOk==0 );
+
+- if( pagerUseWal(pPager) ){
+- int rc2;
+- rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, -1);
+- rc2 = pager_end_transaction(pPager, pPager->setMaster, 0);
+- if( rc==SQLITE_OK ) rc = rc2;
+- }else if( !isOpen(pPager->jfd) || pPager->eState==PAGER_WRITER_LOCKED ){
+- int eState = pPager->eState;
+- rc = pager_end_transaction(pPager, 0, 0);
+- if( !MEMDB && eState>PAGER_WRITER_LOCKED ){
+- /* This can happen using journal_mode=off. Move the pager to the error
+- ** state to indicate that the contents of the cache may not be trusted.
+- ** Any active readers will get SQLITE_ABORT.
+- */
+- pPager->errCode = SQLITE_ABORT;
+- pPager->eState = PAGER_ERROR;
+- return rc;
+- }
+- }else{
+- rc = pager_playback(pPager, 0);
++ if( pgno==0 ){
++ return SQLITE_CORRUPT_BKPT;
+ }
++ pPager->hasBeenUsed = 1;
+
+- assert( pPager->eState==PAGER_READER || rc!=SQLITE_OK );
+- assert( rc==SQLITE_OK || rc==SQLITE_FULL || rc==SQLITE_CORRUPT
+- || rc==SQLITE_NOMEM || (rc&0xFF)==SQLITE_IOERR
+- || rc==SQLITE_CANTOPEN
+- );
++ /* If the pager is in the error state, return an error immediately.
++ ** Otherwise, request the page from the PCache layer. */
++ if( pPager->errCode!=SQLITE_OK ){
++ rc = pPager->errCode;
++ }else{
++ if( bMmapOk && pagerUseWal(pPager) ){
++ rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
++ if( rc!=SQLITE_OK ) goto pager_acquire_err;
++ }
+
+- /* If an error occurs during a ROLLBACK, we can no longer trust the pager
+- ** cache. So call pager_error() on the way out to make any error persistent.
+- */
+- return pager_error(pPager, rc);
+-}
++ if( bMmapOk && iFrame==0 ){
++ void *pData = 0;
+
+-/*
+-** Return TRUE if the database file is opened read-only. Return FALSE
+-** if the database is (in theory) writable.
+-*/
+-SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager *pPager){
+- return pPager->readOnly;
+-}
++ rc = sqlite3OsFetch(pPager->fd,
++ (i64)(pgno-1) * pPager->pageSize, pPager->pageSize, &pData
++ );
+
+-/*
+-** Return the number of references to the pager.
+-*/
+-SQLITE_PRIVATE int sqlite3PagerRefcount(Pager *pPager){
+- return sqlite3PcacheRefCount(pPager->pPCache);
+-}
++ if( rc==SQLITE_OK && pData ){
++ if( pPager->eState>PAGER_READER ){
++ pPg = sqlite3PagerLookup(pPager, pgno);
++ }
++ if( pPg==0 ){
++ rc = pagerAcquireMapPage(pPager, pgno, pData, &pPg);
++ }else{
++ sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1)*pPager->pageSize, pData);
++ }
++ if( pPg ){
++ assert( rc==SQLITE_OK );
++ *ppPage = pPg;
++ return SQLITE_OK;
++ }
++ }
++ if( rc!=SQLITE_OK ){
++ goto pager_acquire_err;
++ }
++ }
+
+-/*
+-** Return the approximate number of bytes of memory currently
+-** used by the pager and its associated cache.
+-*/
+-SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager *pPager){
+- int perPageSize = pPager->pageSize + pPager->nExtra + sizeof(PgHdr)
+- + 5*sizeof(void*);
+- return perPageSize*sqlite3PcachePagecount(pPager->pPCache)
+- + sqlite3MallocSize(pPager)
+- + pPager->pageSize;
+-}
++ {
++ sqlite3_pcache_page *pBase;
++ pBase = sqlite3PcacheFetch(pPager->pPCache, pgno, 3);
++ if( pBase==0 ){
++ rc = sqlite3PcacheFetchStress(pPager->pPCache, pgno, &pBase);
++ if( rc!=SQLITE_OK ) goto pager_acquire_err;
++ }
++ pPg = *ppPage = sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pBase);
++ if( pPg==0 ) rc = SQLITE_NOMEM;
++ }
++ }
+
+-/*
+-** Return the number of references to the specified page.
+-*/
+-SQLITE_PRIVATE int sqlite3PagerPageRefcount(DbPage *pPage){
+- return sqlite3PcachePageRefcount(pPage);
+-}
++ if( rc!=SQLITE_OK ){
++ /* Either the call to sqlite3PcacheFetch() returned an error or the
++ ** pager was already in the error-state when this function was called.
++ ** Set pPg to 0 and jump to the exception handler. */
++ pPg = 0;
++ goto pager_acquire_err;
++ }
++ assert( (*ppPage)->pgno==pgno );
++ assert( (*ppPage)->pPager==pPager || (*ppPage)->pPager==0 );
+
+-#ifdef SQLITE_TEST
+-/*
+-** This routine is used for testing and analysis only.
+-*/
+-SQLITE_PRIVATE int *sqlite3PagerStats(Pager *pPager){
+- static int a[11];
+- a[0] = sqlite3PcacheRefCount(pPager->pPCache);
+- a[1] = sqlite3PcachePagecount(pPager->pPCache);
+- a[2] = sqlite3PcacheGetCachesize(pPager->pPCache);
+- a[3] = pPager->eState==PAGER_OPEN ? -1 : (int) pPager->dbSize;
+- a[4] = pPager->eState;
+- a[5] = pPager->errCode;
+- a[6] = pPager->aStat[PAGER_STAT_HIT];
+- a[7] = pPager->aStat[PAGER_STAT_MISS];
+- a[8] = 0; /* Used to be pPager->nOvfl */
+- a[9] = pPager->nRead;
+- a[10] = pPager->aStat[PAGER_STAT_WRITE];
+- return a;
+-}
+-#endif
++ if( (*ppPage)->pPager && !noContent ){
++ /* In this case the pcache already contains an initialized copy of
++ ** the page. Return without further ado. */
++ assert( pgno<=PAGER_MAX_PGNO && pgno!=PAGER_MJ_PGNO(pPager) );
++ pPager->aStat[PAGER_STAT_HIT]++;
++ return SQLITE_OK;
+
+-/*
+-** Parameter eStat must be either SQLITE_DBSTATUS_CACHE_HIT or
+-** SQLITE_DBSTATUS_CACHE_MISS. Before returning, *pnVal is incremented by the
+-** current cache hit or miss count, according to the value of eStat. If the
+-** reset parameter is non-zero, the cache hit or miss count is zeroed before
+-** returning.
+-*/
+-SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, int *pnVal){
++ }else{
++ /* The pager cache has created a new page. Its content needs to
++ ** be initialized. */
+
+- assert( eStat==SQLITE_DBSTATUS_CACHE_HIT
+- || eStat==SQLITE_DBSTATUS_CACHE_MISS
+- || eStat==SQLITE_DBSTATUS_CACHE_WRITE
+- );
++ pPg = *ppPage;
++ pPg->pPager = pPager;
+
+- assert( SQLITE_DBSTATUS_CACHE_HIT+1==SQLITE_DBSTATUS_CACHE_MISS );
+- assert( SQLITE_DBSTATUS_CACHE_HIT+2==SQLITE_DBSTATUS_CACHE_WRITE );
+- assert( PAGER_STAT_HIT==0 && PAGER_STAT_MISS==1 && PAGER_STAT_WRITE==2 );
++ /* The maximum page number is 2^31. Return SQLITE_CORRUPT if a page
++ ** number greater than this, or the unused locking-page, is requested. */
++ if( pgno>PAGER_MAX_PGNO || pgno==PAGER_MJ_PGNO(pPager) ){
++ rc = SQLITE_CORRUPT_BKPT;
++ goto pager_acquire_err;
++ }
+
+- *pnVal += pPager->aStat[eStat - SQLITE_DBSTATUS_CACHE_HIT];
+- if( reset ){
+- pPager->aStat[eStat - SQLITE_DBSTATUS_CACHE_HIT] = 0;
++ if( MEMDB || pPager->dbSize<pgno || noContent || !isOpen(pPager->fd) ){
++ if( pgno>pPager->mxPgno ){
++ rc = SQLITE_FULL;
++ goto pager_acquire_err;
++ }
++ if( noContent ){
++ /* Failure to set the bits in the InJournal bit-vectors is benign.
++ ** It merely means that we might do some extra work to journal a
++ ** page that does not need to be journaled. Nevertheless, be sure
++ ** to test the case where a malloc error occurs while trying to set
++ ** a bit in a bit vector.
++ */
++ sqlite3BeginBenignMalloc();
++ if( pgno<=pPager->dbOrigSize ){
++ TESTONLY( rc = ) sqlite3BitvecSet(pPager->pInJournal, pgno);
++ testcase( rc==SQLITE_NOMEM );
++ }
++ TESTONLY( rc = ) addToSavepointBitvecs(pPager, pgno);
++ testcase( rc==SQLITE_NOMEM );
++ sqlite3EndBenignMalloc();
++ }
++ memset(pPg->pData, 0, pPager->pageSize);
++ IOTRACE(("ZERO %p %d\n", pPager, pgno));
++ }else{
++ if( pagerUseWal(pPager) && bMmapOk==0 ){
++ rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
++ if( rc!=SQLITE_OK ) goto pager_acquire_err;
++ }
++ assert( pPg->pPager==pPager );
++ pPager->aStat[PAGER_STAT_MISS]++;
++ rc = readDbPage(pPg, iFrame);
++ if( rc!=SQLITE_OK ){
++ goto pager_acquire_err;
++ }
++ }
++ pager_set_pagehash(pPg);
+ }
++
++ return SQLITE_OK;
++
++pager_acquire_err:
++ assert( rc!=SQLITE_OK );
++ if( pPg ){
++ sqlite3PcacheDrop(pPg);
++ }
++ pagerUnlockIfUnused(pPager);
++
++ *ppPage = 0;
++ return rc;
+ }
+
+ /*
+-** Return true if this is an in-memory pager.
++** Acquire a page if it is already in the in-memory cache. Do
++** not read the page from disk. Return a pointer to the page,
++** or 0 if the page is not in cache.
++**
++** See also sqlite3PagerGet(). The difference between this routine
++** and sqlite3PagerGet() is that _get() will go to the disk and read
++** in the page if the page is not already in cache. This routine
++** returns NULL if the page is not in cache or if a disk I/O error
++** has ever happened.
+ */
+-SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager *pPager){
+- return MEMDB;
++SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
++ sqlite3_pcache_page *pPage;
++ assert( pPager!=0 );
++ assert( pgno!=0 );
++ assert( pPager->pPCache!=0 );
++ pPage = sqlite3PcacheFetch(pPager->pPCache, pgno, 0);
++ assert( pPage==0 || pPager->hasBeenUsed );
++ return sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pPage);
+ }
+
+ /*
+-** Check that there are at least nSavepoint savepoints open. If there are
+-** currently less than nSavepoints open, then open one or more savepoints
+-** to make up the difference. If the number of savepoints is already
+-** equal to nSavepoint, then this function is a no-op.
++** Release a page reference.
+ **
+-** If a memory allocation fails, SQLITE_NOMEM is returned. If an error
+-** occurs while opening the sub-journal file, then an IO error code is
+-** returned. Otherwise, SQLITE_OK.
++** If the number of references to the page drop to zero, then the
++** page is added to the LRU list. When all references to all pages
++** are released, a rollback occurs and the lock on the database is
++** removed.
+ */
+-SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int nSavepoint){
+- int rc = SQLITE_OK; /* Return code */
+- int nCurrent = pPager->nSavepoint; /* Current number of savepoints */
+-
+- assert( pPager->eState>=PAGER_WRITER_LOCKED );
+- assert( assert_pager_state(pPager) );
+-
+- if( nSavepoint>nCurrent && pPager->useJournal ){
+- int ii; /* Iterator variable */
+- PagerSavepoint *aNew; /* New Pager.aSavepoint array */
+-
+- /* Grow the Pager.aSavepoint array using realloc(). Return SQLITE_NOMEM
+- ** if the allocation fails. Otherwise, zero the new portion in case a
+- ** malloc failure occurs while populating it in the for(...) loop below.
+- */
+- aNew = (PagerSavepoint *)sqlite3Realloc(
+- pPager->aSavepoint, sizeof(PagerSavepoint)*nSavepoint
+- );
+- if( !aNew ){
+- return SQLITE_NOMEM;
+- }
+- memset(&aNew[nCurrent], 0, (nSavepoint-nCurrent) * sizeof(PagerSavepoint));
+- pPager->aSavepoint = aNew;
+-
+- /* Populate the PagerSavepoint structures just allocated. */
+- for(ii=nCurrent; ii<nSavepoint; ii++){
+- aNew[ii].nOrig = pPager->dbSize;
+- if( isOpen(pPager->jfd) && pPager->journalOff>0 ){
+- aNew[ii].iOffset = pPager->journalOff;
+- }else{
+- aNew[ii].iOffset = JOURNAL_HDR_SZ(pPager);
+- }
+- aNew[ii].iSubRec = pPager->nSubRec;
+- aNew[ii].pInSavepoint = sqlite3BitvecCreate(pPager->dbSize);
+- if( !aNew[ii].pInSavepoint ){
+- return SQLITE_NOMEM;
+- }
+- if( pagerUseWal(pPager) ){
+- sqlite3WalSavepoint(pPager->pWal, aNew[ii].aWalData);
+- }
+- pPager->nSavepoint = ii+1;
+- }
+- assert( pPager->nSavepoint==nSavepoint );
+- assertTruncateConstraint(pPager);
++SQLITE_PRIVATE void sqlite3PagerUnrefNotNull(DbPage *pPg){
++ Pager *pPager;
++ assert( pPg!=0 );
++ pPager = pPg->pPager;
++ if( pPg->flags & PGHDR_MMAP ){
++ pagerReleaseMapPage(pPg);
++ }else{
++ sqlite3PcacheRelease(pPg);
+ }
+-
+- return rc;
++ pagerUnlockIfUnused(pPager);
++}
++SQLITE_PRIVATE void sqlite3PagerUnref(DbPage *pPg){
++ if( pPg ) sqlite3PagerUnrefNotNull(pPg);
+ }
+
+ /*
+-** This function is called to rollback or release (commit) a savepoint.
+-** The savepoint to release or rollback need not be the most recently
+-** created savepoint.
+-**
+-** Parameter op is always either SAVEPOINT_ROLLBACK or SAVEPOINT_RELEASE.
+-** If it is SAVEPOINT_RELEASE, then release and destroy the savepoint with
+-** index iSavepoint. If it is SAVEPOINT_ROLLBACK, then rollback all changes
+-** that have occurred since the specified savepoint was created.
++** This function is called at the start of every write transaction.
++** There must already be a RESERVED or EXCLUSIVE lock on the database
++** file when this routine is called.
+ **
+-** The savepoint to rollback or release is identified by parameter
+-** iSavepoint. A value of 0 means to operate on the outermost savepoint
+-** (the first created). A value of (Pager.nSavepoint-1) means operate
+-** on the most recently created savepoint. If iSavepoint is greater than
+-** (Pager.nSavepoint-1), then this function is a no-op.
++** Open the journal file for pager pPager and write a journal header
++** to the start of it. If there are active savepoints, open the sub-journal
++** as well. This function is only used when the journal file is being
++** opened to write a rollback log for a transaction. It is not used
++** when opening a hot journal file to roll it back.
+ **
+-** If a negative value is passed to this function, then the current
+-** transaction is rolled back. This is different to calling
+-** sqlite3PagerRollback() because this function does not terminate
+-** the transaction or unlock the database, it just restores the
+-** contents of the database to its original state.
++** If the journal file is already open (as it may be in exclusive mode),
++** then this function just writes a journal header to the start of the
++** already open file.
+ **
+-** In any case, all savepoints with an index greater than iSavepoint
+-** are destroyed. If this is a release operation (op==SAVEPOINT_RELEASE),
+-** then savepoint iSavepoint is also destroyed.
++** Whether or not the journal file is opened by this function, the
++** Pager.pInJournal bitvec structure is allocated.
+ **
+-** This function may return SQLITE_NOMEM if a memory allocation fails,
+-** or an IO error code if an IO error occurs while rolling back a
+-** savepoint. If no errors occur, SQLITE_OK is returned.
+-*/
+-SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
+- int rc = pPager->errCode; /* Return code */
+-
+- assert( op==SAVEPOINT_RELEASE || op==SAVEPOINT_ROLLBACK );
+- assert( iSavepoint>=0 || op==SAVEPOINT_ROLLBACK );
++** Return SQLITE_OK if everything is successful. Otherwise, return
++** SQLITE_NOMEM if the attempt to allocate Pager.pInJournal fails, or
++** an IO error code if opening or writing the journal file fails.
++*/
++static int pager_open_journal(Pager *pPager){
++ int rc = SQLITE_OK; /* Return code */
++ sqlite3_vfs * const pVfs = pPager->pVfs; /* Local cache of vfs pointer */
+
+- if( rc==SQLITE_OK && iSavepoint<pPager->nSavepoint ){
+- int ii; /* Iterator variable */
+- int nNew; /* Number of remaining savepoints after this op. */
++ assert( pPager->eState==PAGER_WRITER_LOCKED );
++ assert( assert_pager_state(pPager) );
++ assert( pPager->pInJournal==0 );
++
++ /* If already in the error state, this function is a no-op. But on
++ ** the other hand, this routine is never called if we are already in
++ ** an error state. */
++ if( NEVER(pPager->errCode) ) return pPager->errCode;
+
+- /* Figure out how many savepoints will still be active after this
+- ** operation. Store this value in nNew. Then free resources associated
+- ** with any savepoints that are destroyed by this operation.
+- */
+- nNew = iSavepoint + (( op==SAVEPOINT_RELEASE ) ? 0 : 1);
+- for(ii=nNew; ii<pPager->nSavepoint; ii++){
+- sqlite3BitvecDestroy(pPager->aSavepoint[ii].pInSavepoint);
++ if( !pagerUseWal(pPager) && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){
++ pPager->pInJournal = sqlite3BitvecCreate(pPager->dbSize);
++ if( pPager->pInJournal==0 ){
++ return SQLITE_NOMEM;
+ }
+- pPager->nSavepoint = nNew;
++
++ /* Open the journal file if it is not already open. */
++ if( !isOpen(pPager->jfd) ){
++ if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ){
++ sqlite3MemJournalOpen(pPager->jfd);
++ }else{
++ const int flags = /* VFS flags to open journal file */
++ SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|
++ (pPager->tempFile ?
++ (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL):
++ (SQLITE_OPEN_MAIN_JOURNAL)
++ );
+
+- /* If this is a release of the outermost savepoint, truncate
+- ** the sub-journal to zero bytes in size. */
+- if( op==SAVEPOINT_RELEASE ){
+- if( nNew==0 && isOpen(pPager->sjfd) ){
+- /* Only truncate if it is an in-memory sub-journal. */
+- if( sqlite3IsMemJournal(pPager->sjfd) ){
+- rc = sqlite3OsTruncate(pPager->sjfd, 0);
+- assert( rc==SQLITE_OK );
++ /* Verify that the database still has the same name as it did when
++ ** it was originally opened. */
++ rc = databaseIsUnmoved(pPager);
++ if( rc==SQLITE_OK ){
++#ifdef SQLITE_ENABLE_ATOMIC_WRITE
++ rc = sqlite3JournalOpen(
++ pVfs, pPager->zJournal, pPager->jfd, flags, jrnlBufferSize(pPager)
++ );
++#else
++ rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags, 0);
++#endif
+ }
+- pPager->nSubRec = 0;
+ }
++ assert( rc!=SQLITE_OK || isOpen(pPager->jfd) );
+ }
+- /* Else this is a rollback operation, playback the specified savepoint.
+- ** If this is a temp-file, it is possible that the journal file has
+- ** not yet been opened. In this case there have been no changes to
+- ** the database file, so the playback operation can be skipped.
++
++
++ /* Write the first journal header to the journal file and open
++ ** the sub-journal if necessary.
+ */
+- else if( pagerUseWal(pPager) || isOpen(pPager->jfd) ){
+- PagerSavepoint *pSavepoint = (nNew==0)?0:&pPager->aSavepoint[nNew-1];
+- rc = pagerPlaybackSavepoint(pPager, pSavepoint);
+- assert(rc!=SQLITE_DONE);
++ if( rc==SQLITE_OK ){
++ /* TODO: Check if all of these are really required. */
++ pPager->nRec = 0;
++ pPager->journalOff = 0;
++ pPager->setMaster = 0;
++ pPager->journalHdr = 0;
++ rc = writeJournalHdr(pPager);
+ }
+ }
+
++ if( rc!=SQLITE_OK ){
++ sqlite3BitvecDestroy(pPager->pInJournal);
++ pPager->pInJournal = 0;
++ }else{
++ assert( pPager->eState==PAGER_WRITER_LOCKED );
++ pPager->eState = PAGER_WRITER_CACHEMOD;
++ }
++
+ return rc;
+ }
+
+ /*
+-** Return the full pathname of the database file.
++** Begin a write-transaction on the specified pager object. If a
++** write-transaction has already been opened, this function is a no-op.
+ **
+-** Except, if the pager is in-memory only, then return an empty string if
+-** nullIfMemDb is true. This routine is called with nullIfMemDb==1 when
+-** used to report the filename to the user, for compatibility with legacy
+-** behavior. But when the Btree needs to know the filename for matching to
+-** shared cache, it uses nullIfMemDb==0 so that in-memory databases can
+-** participate in shared-cache.
++** If the exFlag argument is false, then acquire at least a RESERVED
++** lock on the database file. If exFlag is true, then acquire at least
++** an EXCLUSIVE lock. If such a lock is already held, no locking
++** functions need be called.
++**
++** If the subjInMemory argument is non-zero, then any sub-journal opened
++** within this transaction will be opened as an in-memory file. This
++** has no effect if the sub-journal is already opened (as it may be when
++** running in exclusive mode) or if the transaction does not require a
++** sub-journal. If the subjInMemory argument is zero, then any required
++** sub-journal is implemented in-memory if pPager is an in-memory database,
++** or using a temporary file otherwise.
+ */
+-SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager *pPager, int nullIfMemDb){
+- return (nullIfMemDb && pPager->memDb) ? "" : pPager->zFilename;
+-}
++SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory){
++ int rc = SQLITE_OK;
+
+-/*
+-** Return the VFS structure for the pager.
+-*/
+-SQLITE_PRIVATE const sqlite3_vfs *sqlite3PagerVfs(Pager *pPager){
+- return pPager->pVfs;
+-}
++ if( pPager->errCode ) return pPager->errCode;
++ assert( pPager->eState>=PAGER_READER && pPager->eState<PAGER_ERROR );
++ pPager->subjInMemory = (u8)subjInMemory;
+
+-/*
+-** Return the file handle for the database file associated
+-** with the pager. This might return NULL if the file has
+-** not yet been opened.
+-*/
+-SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager *pPager){
+- return pPager->fd;
+-}
++ if( ALWAYS(pPager->eState==PAGER_READER) ){
++ assert( pPager->pInJournal==0 );
+
+-/*
+-** Return the full pathname of the journal file.
+-*/
+-SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager *pPager){
+- return pPager->zJournal;
+-}
++ if( pagerUseWal(pPager) ){
++ /* If the pager is configured to use locking_mode=exclusive, and an
++ ** exclusive lock on the database is not already held, obtain it now.
++ */
++ if( pPager->exclusiveMode && sqlite3WalExclusiveMode(pPager->pWal, -1) ){
++ rc = pagerLockDb(pPager, EXCLUSIVE_LOCK);
++ if( rc!=SQLITE_OK ){
++ return rc;
++ }
++ sqlite3WalExclusiveMode(pPager->pWal, 1);
++ }
+
+-/*
+-** Return true if fsync() calls are disabled for this pager. Return FALSE
+-** if fsync()s are executed normally.
+-*/
+-SQLITE_PRIVATE int sqlite3PagerNosync(Pager *pPager){
+- return pPager->noSync;
+-}
++ /* Grab the write lock on the log file. If successful, upgrade to
++ ** PAGER_RESERVED state. Otherwise, return an error code to the caller.
++ ** The busy-handler is not invoked if another connection already
++ ** holds the write-lock. If possible, the upper layer will call it.
++ */
++ rc = sqlite3WalBeginWriteTransaction(pPager->pWal);
++ }else{
++ /* Obtain a RESERVED lock on the database file. If the exFlag parameter
++ ** is true, then immediately upgrade this to an EXCLUSIVE lock. The
++ ** busy-handler callback can be used when upgrading to the EXCLUSIVE
++ ** lock, but not when obtaining the RESERVED lock.
++ */
++ rc = pagerLockDb(pPager, RESERVED_LOCK);
++ if( rc==SQLITE_OK && exFlag ){
++ rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
++ }
++ }
+
+-#ifdef SQLITE_HAS_CODEC
+-/*
+-** Set or retrieve the codec for this pager
+-*/
+-SQLITE_PRIVATE void sqlite3PagerSetCodec(
+- Pager *pPager,
+- void *(*xCodec)(void*,void*,Pgno,int),
+- void (*xCodecSizeChng)(void*,int,int),
+- void (*xCodecFree)(void*),
+- void *pCodec
+-){
+- if( pPager->xCodecFree ) pPager->xCodecFree(pPager->pCodec);
+- pPager->xCodec = pPager->memDb ? 0 : xCodec;
+- pPager->xCodecSizeChng = xCodecSizeChng;
+- pPager->xCodecFree = xCodecFree;
+- pPager->pCodec = pCodec;
+- pagerReportSize(pPager);
+-}
+-SQLITE_PRIVATE void *sqlite3PagerGetCodec(Pager *pPager){
+- return pPager->pCodec;
+-}
++ if( rc==SQLITE_OK ){
++ /* Change to WRITER_LOCKED state.
++ **
++ ** WAL mode sets Pager.eState to PAGER_WRITER_LOCKED or CACHEMOD
++ ** when it has an open transaction, but never to DBMOD or FINISHED.
++ ** This is because in those states the code to roll back savepoint
++ ** transactions may copy data from the sub-journal into the database
++ ** file as well as into the page cache. Which would be incorrect in
++ ** WAL mode.
++ */
++ pPager->eState = PAGER_WRITER_LOCKED;
++ pPager->dbHintSize = pPager->dbSize;
++ pPager->dbFileSize = pPager->dbSize;
++ pPager->dbOrigSize = pPager->dbSize;
++ pPager->journalOff = 0;
++ }
+
+-/*
+-** This function is called by the wal module when writing page content
+-** into the log file.
+-**
+-** This function returns a pointer to a buffer containing the encrypted
+-** page content. If a malloc fails, this function may return NULL.
+-*/
+-SQLITE_PRIVATE void *sqlite3PagerCodec(PgHdr *pPg){
+- void *aData = 0;
+- CODEC2(pPg->pPager, pPg->pData, pPg->pgno, 6, return 0, aData);
+- return aData;
+-}
++ assert( rc==SQLITE_OK || pPager->eState==PAGER_READER );
++ assert( rc!=SQLITE_OK || pPager->eState==PAGER_WRITER_LOCKED );
++ assert( assert_pager_state(pPager) );
++ }
+
+-/*
+-** Return the current pager state
+-*/
+-SQLITE_PRIVATE int sqlite3PagerState(Pager *pPager){
+- return pPager->eState;
++ PAGERTRACE(("TRANSACTION %d\n", PAGERID(pPager)));
++ return rc;
+ }
+-#endif /* SQLITE_HAS_CODEC */
+
+-#ifndef SQLITE_OMIT_AUTOVACUUM
+ /*
+-** Move the page pPg to location pgno in the file.
+-**
+-** There must be no references to the page previously located at
+-** pgno (which we call pPgOld) though that page is allowed to be
+-** in cache. If the page previously located at pgno is not already
+-** in the rollback journal, it is not put there by by this routine.
+-**
+-** References to the page pPg remain valid. Updating any
+-** meta-data associated with pPg (i.e. data stored in the nExtra bytes
+-** allocated along with the page) is the responsibility of the caller.
+-**
+-** A transaction must be active when this routine is called. It used to be
+-** required that a statement transaction was not active, but this restriction
+-** has been removed (CREATE INDEX needs to move a page when a statement
+-** transaction is active).
+-**
+-** If the fourth argument, isCommit, is non-zero, then this page is being
+-** moved as part of a database reorganization just before the transaction
+-** is being committed. In this case, it is guaranteed that the database page
+-** pPg refers to will not be written to again within this transaction.
+-**
+-** This function may return SQLITE_NOMEM or an IO error code if an error
+-** occurs. Otherwise, it returns SQLITE_OK.
++** Mark a single data page as writeable. The page is written into the
++** main journal or sub-journal as required. If the page is written into
++** one of the journals, the corresponding bit is set in the
++** Pager.pInJournal bitvec and the PagerSavepoint.pInSavepoint bitvecs
++** of any open savepoints as appropriate.
+ */
+-SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
+- PgHdr *pPgOld; /* The page being overwritten. */
+- Pgno needSyncPgno = 0; /* Old value of pPg->pgno, if sync is required */
+- int rc; /* Return code */
+- Pgno origPgno; /* The original page number */
++static int pager_write(PgHdr *pPg){
++ Pager *pPager = pPg->pPager;
++ int rc = SQLITE_OK;
++ int inJournal;
+
+- assert( pPg->nRef>0 );
+- assert( pPager->eState==PAGER_WRITER_CACHEMOD
++ /* This routine is not called unless a write-transaction has already
++ ** been started. The journal file may or may not be open at this point.
++ ** It is never called in the ERROR state.
++ */
++ assert( pPager->eState==PAGER_WRITER_LOCKED
++ || pPager->eState==PAGER_WRITER_CACHEMOD
+ || pPager->eState==PAGER_WRITER_DBMOD
+ );
+ assert( assert_pager_state(pPager) );
++ assert( pPager->errCode==0 );
++ assert( pPager->readOnly==0 );
+
+- /* In order to be able to rollback, an in-memory database must journal
+- ** the page we are moving from.
+- */
+- if( MEMDB ){
+- rc = sqlite3PagerWrite(pPg);
+- if( rc ) return rc;
+- }
++ CHECK_PAGE(pPg);
+
+- /* If the page being moved is dirty and has not been saved by the latest
+- ** savepoint, then save the current contents of the page into the
+- ** sub-journal now. This is required to handle the following scenario:
+- **
+- ** BEGIN;
+- ** <journal page X, then modify it in memory>
+- ** SAVEPOINT one;
+- ** <Move page X to location Y>
+- ** ROLLBACK TO one;
+- **
+- ** If page X were not written to the sub-journal here, it would not
+- ** be possible to restore its contents when the "ROLLBACK TO one"
+- ** statement were is processed.
++ /* The journal file needs to be opened. Higher level routines have already
++ ** obtained the necessary locks to begin the write-transaction, but the
++ ** rollback journal might not yet be open. Open it now if this is the case.
+ **
+- ** subjournalPage() may need to allocate space to store pPg->pgno into
+- ** one or more savepoint bitvecs. This is the reason this function
+- ** may return SQLITE_NOMEM.
++ ** This is done before calling sqlite3PcacheMakeDirty() on the page.
++ ** Otherwise, if it were done after calling sqlite3PcacheMakeDirty(), then
++ ** an error might occur and the pager would end up in WRITER_LOCKED state
++ ** with pages marked as dirty in the cache.
+ */
+- if( pPg->flags&PGHDR_DIRTY
+- && subjRequiresPage(pPg)
+- && SQLITE_OK!=(rc = subjournalPage(pPg))
+- ){
+- return rc;
++ if( pPager->eState==PAGER_WRITER_LOCKED ){
++ rc = pager_open_journal(pPager);
++ if( rc!=SQLITE_OK ) return rc;
+ }
++ assert( pPager->eState>=PAGER_WRITER_CACHEMOD );
++ assert( assert_pager_state(pPager) );
+
+- PAGERTRACE(("MOVE %d page %d (needSync=%d) moves to %d\n",
+- PAGERID(pPager), pPg->pgno, (pPg->flags&PGHDR_NEED_SYNC)?1:0, pgno));
+- IOTRACE(("MOVE %p %d %d\n", pPager, pPg->pgno, pgno))
+-
+- /* If the journal needs to be sync()ed before page pPg->pgno can
+- ** be written to, store pPg->pgno in local variable needSyncPgno.
+- **
+- ** If the isCommit flag is set, there is no need to remember that
+- ** the journal needs to be sync()ed before database page pPg->pgno
+- ** can be written to. The caller has already promised not to write to it.
++ /* Mark the page as dirty. If the page has already been written
++ ** to the journal then we can return right away.
+ */
+- if( (pPg->flags&PGHDR_NEED_SYNC) && !isCommit ){
+- needSyncPgno = pPg->pgno;
+- assert( pPager->journalMode==PAGER_JOURNALMODE_OFF ||
+- pageInJournal(pPager, pPg) || pPg->pgno>pPager->dbOrigSize );
+- assert( pPg->flags&PGHDR_DIRTY );
++ sqlite3PcacheMakeDirty(pPg);
++ inJournal = pageInJournal(pPager, pPg);
++ if( inJournal && (pPager->nSavepoint==0 || !subjRequiresPage(pPg)) ){
++ assert( !pagerUseWal(pPager) );
++ }else{
++
++ /* The transaction journal now exists and we have a RESERVED or an
++ ** EXCLUSIVE lock on the main database file. Write the current page to
++ ** the transaction journal if it is not there already.
++ */
++ if( !inJournal && !pagerUseWal(pPager) ){
++ assert( pagerUseWal(pPager)==0 );
++ if( pPg->pgno<=pPager->dbOrigSize && isOpen(pPager->jfd) ){
++ u32 cksum;
++ char *pData2;
++ i64 iOff = pPager->journalOff;
++
++ /* We should never write to the journal file the page that
++ ** contains the database locks. The following assert verifies
++ ** that we do not. */
++ assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) );
++
++ assert( pPager->journalHdr<=pPager->journalOff );
++ CODEC2(pPager, pPg->pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2);
++ cksum = pager_cksum(pPager, (u8*)pData2);
++
++ /* Even if an IO or diskfull error occurs while journalling the
++ ** page in the block above, set the need-sync flag for the page.
++ ** Otherwise, when the transaction is rolled back, the logic in
++ ** playback_one_page() will think that the page needs to be restored
++ ** in the database file. And if an IO error occurs while doing so,
++ ** then corruption may follow.
++ */
++ pPg->flags |= PGHDR_NEED_SYNC;
++
++ rc = write32bits(pPager->jfd, iOff, pPg->pgno);
++ if( rc!=SQLITE_OK ) return rc;
++ rc = sqlite3OsWrite(pPager->jfd, pData2, pPager->pageSize, iOff+4);
++ if( rc!=SQLITE_OK ) return rc;
++ rc = write32bits(pPager->jfd, iOff+pPager->pageSize+4, cksum);
++ if( rc!=SQLITE_OK ) return rc;
++
++ IOTRACE(("JOUT %p %d %lld %d\n", pPager, pPg->pgno,
++ pPager->journalOff, pPager->pageSize));
++ PAGER_INCR(sqlite3_pager_writej_count);
++ PAGERTRACE(("JOURNAL %d page %d needSync=%d hash(%08x)\n",
++ PAGERID(pPager), pPg->pgno,
++ ((pPg->flags&PGHDR_NEED_SYNC)?1:0), pager_pagehash(pPg)));
++
++ pPager->journalOff += 8 + pPager->pageSize;
++ pPager->nRec++;
++ assert( pPager->pInJournal!=0 );
++ rc = sqlite3BitvecSet(pPager->pInJournal, pPg->pgno);
++ testcase( rc==SQLITE_NOMEM );
++ assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
++ rc |= addToSavepointBitvecs(pPager, pPg->pgno);
++ if( rc!=SQLITE_OK ){
++ assert( rc==SQLITE_NOMEM );
++ return rc;
++ }
++ }else{
++ if( pPager->eState!=PAGER_WRITER_DBMOD ){
++ pPg->flags |= PGHDR_NEED_SYNC;
++ }
++ PAGERTRACE(("APPEND %d page %d needSync=%d\n",
++ PAGERID(pPager), pPg->pgno,
++ ((pPg->flags&PGHDR_NEED_SYNC)?1:0)));
++ }
++ }
++
++ /* If the statement journal is open and the page is not in it,
++ ** then write the current page to the statement journal. Note that
++ ** the statement journal format differs from the standard journal format
++ ** in that it omits the checksums and the header.
++ */
++ if( pPager->nSavepoint>0 && subjRequiresPage(pPg) ){
++ rc = subjournalPage(pPg);
++ }
+ }
+
+- /* If the cache contains a page with page-number pgno, remove it
+- ** from its hash chain. Also, if the PGHDR_NEED_SYNC flag was set for
+- ** page pgno before the 'move' operation, it needs to be retained
+- ** for the page moved there.
++ /* Update the database size and return.
+ */
+- pPg->flags &= ~PGHDR_NEED_SYNC;
+- pPgOld = sqlite3PagerLookup(pPager, pgno);
+- assert( !pPgOld || pPgOld->nRef==1 );
+- if( pPgOld ){
+- pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC);
+- if( MEMDB ){
+- /* Do not discard pages from an in-memory database since we might
+- ** need to rollback later. Just move the page out of the way. */
+- sqlite3PcacheMove(pPgOld, pPager->dbSize+1);
+- }else{
+- sqlite3PcacheDrop(pPgOld);
+- }
++ if( pPager->dbSize<pPg->pgno ){
++ pPager->dbSize = pPg->pgno;
+ }
++ return rc;
++}
+
+- origPgno = pPg->pgno;
+- sqlite3PcacheMove(pPg, pgno);
+- sqlite3PcacheMakeDirty(pPg);
++/*
++** This is a variant of sqlite3PagerWrite() that runs when the sector size
++** is larger than the page size. SQLite makes the (reasonable) assumption that
++** all bytes of a sector are written together by hardware. Hence, all bytes of
++** a sector need to be journalled in case of a power loss in the middle of
++** a write.
++**
++** Usually, the sector size is less than or equal to the page size, in which
++** case pages can be individually written. This routine only runs in the exceptional
++** case where the page size is smaller than the sector size.
++*/
++static SQLITE_NOINLINE int pagerWriteLargeSector(PgHdr *pPg){
++ int rc = SQLITE_OK; /* Return code */
++ Pgno nPageCount; /* Total number of pages in database file */
++ Pgno pg1; /* First page of the sector pPg is located on. */
++ int nPage = 0; /* Number of pages starting at pg1 to journal */
++ int ii; /* Loop counter */
++ int needSync = 0; /* True if any page has PGHDR_NEED_SYNC */
++ Pager *pPager = pPg->pPager; /* The pager that owns pPg */
++ Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize);
+
+- /* For an in-memory database, make sure the original page continues
+- ** to exist, in case the transaction needs to roll back. Use pPgOld
+- ** as the original page since it has already been allocated.
++ /* Set the doNotSpill NOSYNC bit to 1. This is because we cannot allow
++ ** a journal header to be written between the pages journaled by
++ ** this function.
+ */
+- if( MEMDB ){
+- assert( pPgOld );
+- sqlite3PcacheMove(pPgOld, origPgno);
+- sqlite3PagerUnrefNotNull(pPgOld);
++ assert( !MEMDB );
++ assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)==0 );
++ pPager->doNotSpill |= SPILLFLAG_NOSYNC;
++
++ /* This trick assumes that both the page-size and sector-size are
++ ** an integer power of 2. It sets variable pg1 to the identifier
++ ** of the first page of the sector pPg is located on.
++ */
++ pg1 = ((pPg->pgno-1) & ~(nPagePerSector-1)) + 1;
+
++ nPageCount = pPager->dbSize;
++ if( pPg->pgno>nPageCount ){
++ nPage = (pPg->pgno - pg1)+1;
++ }else if( (pg1+nPagePerSector-1)>nPageCount ){
++ nPage = nPageCount+1-pg1;
++ }else{
++ nPage = nPagePerSector;
+ }
++ assert(nPage>0);
++ assert(pg1<=pPg->pgno);
++ assert((pg1+nPage)>pPg->pgno);
+
+- if( needSyncPgno ){
+- /* If needSyncPgno is non-zero, then the journal file needs to be
+- ** sync()ed before any data is written to database file page needSyncPgno.
+- ** Currently, no such page exists in the page-cache and the
+- ** "is journaled" bitvec flag has been set. This needs to be remedied by
+- ** loading the page into the pager-cache and setting the PGHDR_NEED_SYNC
+- ** flag.
+- **
+- ** If the attempt to load the page into the page-cache fails, (due
+- ** to a malloc() or IO failure), clear the bit in the pInJournal[]
+- ** array. Otherwise, if the page is loaded and written again in
+- ** this transaction, it may be written to the database file before
+- ** it is synced into the journal file. This way, it may end up in
+- ** the journal file twice, but that is not a problem.
+- */
+- PgHdr *pPgHdr;
+- rc = sqlite3PagerGet(pPager, needSyncPgno, &pPgHdr);
+- if( rc!=SQLITE_OK ){
+- if( needSyncPgno<=pPager->dbOrigSize ){
+- assert( pPager->pTmpSpace!=0 );
+- sqlite3BitvecClear(pPager->pInJournal, needSyncPgno, pPager->pTmpSpace);
++ for(ii=0; ii<nPage && rc==SQLITE_OK; ii++){
++ Pgno pg = pg1+ii;
++ PgHdr *pPage;
++ if( pg==pPg->pgno || !sqlite3BitvecTest(pPager->pInJournal, pg) ){
++ if( pg!=PAGER_MJ_PGNO(pPager) ){
++ rc = sqlite3PagerGet(pPager, pg, &pPage);
++ if( rc==SQLITE_OK ){
++ rc = pager_write(pPage);
++ if( pPage->flags&PGHDR_NEED_SYNC ){
++ needSync = 1;
++ }
++ sqlite3PagerUnrefNotNull(pPage);
++ }
+ }
+- return rc;
++ }else if( (pPage = sqlite3PagerLookup(pPager, pg))!=0 ){
++ if( pPage->flags&PGHDR_NEED_SYNC ){
++ needSync = 1;
++ }
++ sqlite3PagerUnrefNotNull(pPage);
+ }
+- pPgHdr->flags |= PGHDR_NEED_SYNC;
+- sqlite3PcacheMakeDirty(pPgHdr);
+- sqlite3PagerUnrefNotNull(pPgHdr);
+ }
+
+- return SQLITE_OK;
+-}
+-#endif
++ /* If the PGHDR_NEED_SYNC flag is set for any of the nPage pages
++ ** starting at pg1, then it needs to be set for all of them. Because
++ ** writing to any of these nPage pages may damage the others, the
++ ** journal file must contain sync()ed copies of all of them
++ ** before any of them can be written out to the database file.
++ */
++ if( rc==SQLITE_OK && needSync ){
++ assert( !MEMDB );
++ for(ii=0; ii<nPage; ii++){
++ PgHdr *pPage = sqlite3PagerLookup(pPager, pg1+ii);
++ if( pPage ){
++ pPage->flags |= PGHDR_NEED_SYNC;
++ sqlite3PagerUnrefNotNull(pPage);
++ }
++ }
++ }
+
+-/*
+-** The page handle passed as the first argument refers to a dirty page
+-** with a page number other than iNew. This function changes the page's
+-** page number to iNew and sets the value of the PgHdr.flags field to
+-** the value passed as the third parameter.
+-*/
+-SQLITE_PRIVATE void sqlite3PagerRekey(DbPage *pPg, Pgno iNew, u16 flags){
+- assert( pPg->pgno!=iNew );
+- pPg->flags = flags;
+- sqlite3PcacheMove(pPg, iNew);
++ assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)!=0 );
++ pPager->doNotSpill &= ~SPILLFLAG_NOSYNC;
++ return rc;
+ }
+
+ /*
+-** Return a pointer to the data for the specified page.
++** Mark a data page as writeable. This routine must be called before
++** making changes to a page. The caller must check the return value
++** of this function and be careful not to change any page data unless
++** this routine returns SQLITE_OK.
++**
++** The difference between this function and pager_write() is that this
++** function also deals with the special case where 2 or more pages
++** fit on a single disk sector. In this case all co-resident pages
++** must have been written to the journal file before returning.
++**
++** If an error occurs, SQLITE_NOMEM or an IO error code is returned
++** as appropriate. Otherwise, SQLITE_OK.
+ */
+-SQLITE_PRIVATE void *sqlite3PagerGetData(DbPage *pPg){
+- assert( pPg->nRef>0 || pPg->pPager->memDb );
+- return pPg->pData;
++SQLITE_PRIVATE int sqlite3PagerWrite(PgHdr *pPg){
++ assert( (pPg->flags & PGHDR_MMAP)==0 );
++ assert( pPg->pPager->eState>=PAGER_WRITER_LOCKED );
++ assert( pPg->pPager->eState!=PAGER_ERROR );
++ assert( assert_pager_state(pPg->pPager) );
++ if( pPg->pPager->sectorSize > (u32)pPg->pPager->pageSize ){
++ return pagerWriteLargeSector(pPg);
++ }else{
++ return pager_write(pPg);
++ }
+ }
+
+ /*
+-** Return a pointer to the Pager.nExtra bytes of "extra" space
+-** allocated along with the specified page.
++** Return TRUE if the page given in the argument was previously passed
++** to sqlite3PagerWrite(). In other words, return TRUE if it is ok
++** to change the content of the page.
+ */
+-SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *pPg){
+- return pPg->pExtra;
++#ifndef NDEBUG
++SQLITE_PRIVATE int sqlite3PagerIswriteable(DbPage *pPg){
++ return pPg->flags&PGHDR_DIRTY;
+ }
++#endif
- /************** End of pager.c ***********************************************/
- /************** Begin file wal.c *********************************************/
-@@ -47711,3561 +51294,2887 @@
- ** Both readers can use the same hash table and mapping section to get
- ** the correct result. There may be entries in the hash table with
- ** K>K0 but to the first reader, those entries will appear to be unused
+ /*
+-** Get/set the locking-mode for this pager. Parameter eMode must be one
+-** of PAGER_LOCKINGMODE_QUERY, PAGER_LOCKINGMODE_NORMAL or
+-** PAGER_LOCKINGMODE_EXCLUSIVE. If the parameter is not _QUERY, then
+-** the locking-mode is set to the value specified.
++** A call to this routine tells the pager that it is not necessary to
++** write the information on page pPg back to the disk, even though
++** that page might be marked as dirty. This happens, for example, when
++** the page has been added as a leaf of the freelist and so its
++** content no longer matters.
+ **
+-** The returned value is either PAGER_LOCKINGMODE_NORMAL or
+-** PAGER_LOCKINGMODE_EXCLUSIVE, indicating the current (possibly updated)
+-** locking-mode.
++** The overlying software layer calls this routine when all of the data
++** on the given page is unused. The pager marks the page as clean so
++** that it does not get written to disk.
++**
++** Tests show that this optimization can quadruple the speed of large
++** DELETE operations.
+ */
+-SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *pPager, int eMode){
+- assert( eMode==PAGER_LOCKINGMODE_QUERY
+- || eMode==PAGER_LOCKINGMODE_NORMAL
+- || eMode==PAGER_LOCKINGMODE_EXCLUSIVE );
+- assert( PAGER_LOCKINGMODE_QUERY<0 );
+- assert( PAGER_LOCKINGMODE_NORMAL>=0 && PAGER_LOCKINGMODE_EXCLUSIVE>=0 );
+- assert( pPager->exclusiveMode || 0==sqlite3WalHeapMemory(pPager->pWal) );
+- if( eMode>=0 && !pPager->tempFile && !sqlite3WalHeapMemory(pPager->pWal) ){
+- pPager->exclusiveMode = (u8)eMode;
++SQLITE_PRIVATE void sqlite3PagerDontWrite(PgHdr *pPg){
++ Pager *pPager = pPg->pPager;
++ if( (pPg->flags&PGHDR_DIRTY) && pPager->nSavepoint==0 ){
++ PAGERTRACE(("DONT_WRITE page %d of %d\n", pPg->pgno, PAGERID(pPager)));
++ IOTRACE(("CLEAN %p %d\n", pPager, pPg->pgno))
++ pPg->flags |= PGHDR_DONT_WRITE;
++ pager_set_pagehash(pPg);
+ }
+- return (int)pPager->exclusiveMode;
+ }
+
+ /*
+-** Set the journal-mode for this pager. Parameter eMode must be one of:
+-**
+-** PAGER_JOURNALMODE_DELETE
+-** PAGER_JOURNALMODE_TRUNCATE
+-** PAGER_JOURNALMODE_PERSIST
+-** PAGER_JOURNALMODE_OFF
+-** PAGER_JOURNALMODE_MEMORY
+-** PAGER_JOURNALMODE_WAL
+-**
+-** The journalmode is set to the value specified if the change is allowed.
+-** The change may be disallowed for the following reasons:
++** This routine is called to increment the value of the database file
++** change-counter, stored as a 4-byte big-endian integer starting at
++** byte offset 24 of the pager file. The secondary change counter at
++** 92 is also updated, as is the SQLite version number at offset 96.
+ **
+-** * An in-memory database can only have its journal_mode set to _OFF
+-** or _MEMORY.
++** But this only happens if the pPager->changeCountDone flag is false.
++** To avoid excess churning of page 1, the update only happens once.
++** See also the pager_write_changecounter() routine that does an
++** unconditional update of the change counters.
+ **
+-** * Temporary databases cannot have _WAL journalmode.
++** If the isDirectMode flag is zero, then this is done by calling
++** sqlite3PagerWrite() on page 1, then modifying the contents of the
++** page data. In this case the file will be updated when the current
++** transaction is committed.
+ **
+-** The returned indicate the current (possibly updated) journal-mode.
++** The isDirectMode flag may only be non-zero if the library was compiled
++** with the SQLITE_ENABLE_ATOMIC_WRITE macro defined. In this case,
++** if isDirect is non-zero, then the database file is updated directly
++** by writing an updated version of page 1 using a call to the
++** sqlite3OsWrite() function.
+ */
+-SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){
+- u8 eOld = pPager->journalMode; /* Prior journalmode */
+-
+-#ifdef SQLITE_DEBUG
+- /* The print_pager_state() routine is intended to be used by the debugger
+- ** only. We invoke it once here to suppress a compiler warning. */
+- print_pager_state(pPager);
+-#endif
+-
++static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
++ int rc = SQLITE_OK;
+
+- /* The eMode parameter is always valid */
+- assert( eMode==PAGER_JOURNALMODE_DELETE
+- || eMode==PAGER_JOURNALMODE_TRUNCATE
+- || eMode==PAGER_JOURNALMODE_PERSIST
+- || eMode==PAGER_JOURNALMODE_OFF
+- || eMode==PAGER_JOURNALMODE_WAL
+- || eMode==PAGER_JOURNALMODE_MEMORY );
++ assert( pPager->eState==PAGER_WRITER_CACHEMOD
++ || pPager->eState==PAGER_WRITER_DBMOD
++ );
++ assert( assert_pager_state(pPager) );
+
+- /* This routine is only called from the OP_JournalMode opcode, and
+- ** the logic there will never allow a temporary file to be changed
+- ** to WAL mode.
++ /* Declare and initialize constant integer 'isDirect'. If the
++ ** atomic-write optimization is enabled in this build, then isDirect
++ ** is initialized to the value passed as the isDirectMode parameter
++ ** to this function. Otherwise, it is always set to zero.
++ **
++ ** The idea is that if the atomic-write optimization is not
++ ** enabled at compile time, the compiler can omit the tests of
++ ** 'isDirect' below, as well as the block enclosed in the
++ ** "if( isDirect )" condition.
+ */
+- assert( pPager->tempFile==0 || eMode!=PAGER_JOURNALMODE_WAL );
++#ifndef SQLITE_ENABLE_ATOMIC_WRITE
++# define DIRECT_MODE 0
++ assert( isDirectMode==0 );
++ UNUSED_PARAMETER(isDirectMode);
++#else
++# define DIRECT_MODE isDirectMode
++#endif
+
+- /* Do allow the journalmode of an in-memory database to be set to
+- ** anything other than MEMORY or OFF
+- */
+- if( MEMDB ){
+- assert( eOld==PAGER_JOURNALMODE_MEMORY || eOld==PAGER_JOURNALMODE_OFF );
+- if( eMode!=PAGER_JOURNALMODE_MEMORY && eMode!=PAGER_JOURNALMODE_OFF ){
+- eMode = eOld;
+- }
+- }
++ if( !pPager->changeCountDone && ALWAYS(pPager->dbSize>0) ){
++ PgHdr *pPgHdr; /* Reference to page 1 */
+
+- if( eMode!=eOld ){
++ assert( !pPager->tempFile && isOpen(pPager->fd) );
+
+- /* Change the journal mode. */
+- assert( pPager->eState!=PAGER_ERROR );
+- pPager->journalMode = (u8)eMode;
++ /* Open page 1 of the file for writing. */
++ rc = sqlite3PagerGet(pPager, 1, &pPgHdr);
++ assert( pPgHdr==0 || rc==SQLITE_OK );
+
+- /* When transistioning from TRUNCATE or PERSIST to any other journal
+- ** mode except WAL, unless the pager is in locking_mode=exclusive mode,
+- ** delete the journal file.
++ /* If page one was fetched successfully, and this function is not
++ ** operating in direct-mode, make page 1 writable. When not in
++ ** direct mode, page 1 is always held in cache and hence the PagerGet()
++ ** above is always successful - hence the ALWAYS on rc==SQLITE_OK.
+ */
+- assert( (PAGER_JOURNALMODE_TRUNCATE & 5)==1 );
+- assert( (PAGER_JOURNALMODE_PERSIST & 5)==1 );
+- assert( (PAGER_JOURNALMODE_DELETE & 5)==0 );
+- assert( (PAGER_JOURNALMODE_MEMORY & 5)==4 );
+- assert( (PAGER_JOURNALMODE_OFF & 5)==0 );
+- assert( (PAGER_JOURNALMODE_WAL & 5)==5 );
++ if( !DIRECT_MODE && ALWAYS(rc==SQLITE_OK) ){
++ rc = sqlite3PagerWrite(pPgHdr);
++ }
+
+- assert( isOpen(pPager->fd) || pPager->exclusiveMode );
+- if( !pPager->exclusiveMode && (eOld & 5)==1 && (eMode & 1)==0 ){
++ if( rc==SQLITE_OK ){
++ /* Actually do the update of the change counter */
++ pager_write_changecounter(pPgHdr);
+
+- /* In this case we would like to delete the journal file. If it is
+- ** not possible, then that is not a problem. Deleting the journal file
+- ** here is an optimization only.
+- **
+- ** Before deleting the journal file, obtain a RESERVED lock on the
+- ** database file. This ensures that the journal file is not deleted
+- ** while it is in use by some other client.
+- */
+- sqlite3OsClose(pPager->jfd);
+- if( pPager->eLock>=RESERVED_LOCK ){
+- sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
+- }else{
+- int rc = SQLITE_OK;
+- int state = pPager->eState;
+- assert( state==PAGER_OPEN || state==PAGER_READER );
+- if( state==PAGER_OPEN ){
+- rc = sqlite3PagerSharedLock(pPager);
+- }
+- if( pPager->eState==PAGER_READER ){
+- assert( rc==SQLITE_OK );
+- rc = pagerLockDb(pPager, RESERVED_LOCK);
+- }
++ /* If running in direct mode, write the contents of page 1 to the file. */
++ if( DIRECT_MODE ){
++ const void *zBuf;
++ assert( pPager->dbFileSize>0 );
++ CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM, zBuf);
+ if( rc==SQLITE_OK ){
+- sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
++ rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0);
++ pPager->aStat[PAGER_STAT_WRITE]++;
+ }
+- if( rc==SQLITE_OK && state==PAGER_READER ){
+- pagerUnlockDb(pPager, SHARED_LOCK);
+- }else if( state==PAGER_OPEN ){
+- pager_unlock(pPager);
++ if( rc==SQLITE_OK ){
++ /* Update the pager's copy of the change-counter. Otherwise, the
++ ** next time a read transaction is opened the cache will be
++ ** flushed (as the change-counter values will not match). */
++ const void *pCopy = (const void *)&((const char *)zBuf)[24];
++ memcpy(&pPager->dbFileVers, pCopy, sizeof(pPager->dbFileVers));
++ pPager->changeCountDone = 1;
+ }
+- assert( state==pPager->eState );
++ }else{
++ pPager->changeCountDone = 1;
+ }
+- }else if( eMode==PAGER_JOURNALMODE_OFF ){
+- sqlite3OsClose(pPager->jfd);
+ }
+- }
+
+- /* Return the new journal mode */
+- return (int)pPager->journalMode;
++ /* Release the page reference. */
++ sqlite3PagerUnref(pPgHdr);
++ }
++ return rc;
+ }
+
+ /*
+-** Return the current journal mode.
++** Sync the database file to disk. This is a no-op for in-memory databases
++** or pages with the Pager.noSync flag set.
++**
++** If successful, or if called on a pager for which it is a no-op, this
++** function returns SQLITE_OK. Otherwise, an IO error code is returned.
+ */
+-SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager *pPager){
+- return (int)pPager->journalMode;
+-}
++SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager, const char *zMaster){
++ int rc = SQLITE_OK;
+
+-/*
+-** Return TRUE if the pager is in a state where it is OK to change the
+-** journalmode. Journalmode changes can only happen when the database
+-** is unmodified.
+-*/
+-SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager *pPager){
+- assert( assert_pager_state(pPager) );
+- if( pPager->eState>=PAGER_WRITER_CACHEMOD ) return 0;
+- if( NEVER(isOpen(pPager->jfd) && pPager->journalOff>0) ) return 0;
+- return 1;
++ if( isOpen(pPager->fd) ){
++ void *pArg = (void*)zMaster;
++ rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SYNC, pArg);
++ if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
++ }
++ if( rc==SQLITE_OK && !pPager->noSync ){
++ assert( !MEMDB );
++ rc = sqlite3OsSync(pPager->fd, pPager->syncFlags);
++ }
++ return rc;
+ }
+
+ /*
+-** Get/set the size-limit used for persistent journal files.
++** This function may only be called while a write-transaction is active in
++** rollback. If the connection is in WAL mode, this call is a no-op.
++** Otherwise, if the connection does not already have an EXCLUSIVE lock on
++** the database file, an attempt is made to obtain one.
+ **
+-** Setting the size limit to -1 means no limit is enforced.
+-** An attempt to set a limit smaller than -1 is a no-op.
++** If the EXCLUSIVE lock is already held or the attempt to obtain it is
++** successful, or the connection is in WAL mode, SQLITE_OK is returned.
++** Otherwise, either SQLITE_BUSY or an SQLITE_IOERR_XXX error code is
++** returned.
+ */
+-SQLITE_PRIVATE i64 sqlite3PagerJournalSizeLimit(Pager *pPager, i64 iLimit){
+- if( iLimit>=-1 ){
+- pPager->journalSizeLimit = iLimit;
+- sqlite3WalLimit(pPager->pWal, iLimit);
++SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager *pPager){
++ int rc = SQLITE_OK;
++ assert( pPager->eState==PAGER_WRITER_CACHEMOD
++ || pPager->eState==PAGER_WRITER_DBMOD
++ || pPager->eState==PAGER_WRITER_LOCKED
++ );
++ assert( assert_pager_state(pPager) );
++ if( 0==pagerUseWal(pPager) ){
++ rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
+ }
+- return pPager->journalSizeLimit;
++ return rc;
+ }
+
+ /*
+-** Return a pointer to the pPager->pBackup variable. The backup module
+-** in backup.c maintains the content of this variable. This module
+-** uses it opaquely as an argument to sqlite3BackupRestart() and
+-** sqlite3BackupUpdate() only.
++** Sync the database file for the pager pPager. zMaster points to the name
++** of a master journal file that should be written into the individual
++** journal file. zMaster may be NULL, which is interpreted as no master
++** journal (a single database transaction).
++**
++** This routine ensures that:
++**
++** * The database file change-counter is updated,
++** * the journal is synced (unless the atomic-write optimization is used),
++** * all dirty pages are written to the database file,
++** * the database file is truncated (if required), and
++** * the database file synced.
++**
++** The only thing that remains to commit the transaction is to finalize
++** (delete, truncate or zero the first part of) the journal file (or
++** delete the master journal file if specified).
++**
++** Note that if zMaster==NULL, this does not overwrite a previous value
++** passed to an sqlite3PagerCommitPhaseOne() call.
++**
++** If the final parameter - noSync - is true, then the database file itself
++** is not synced. The caller must call sqlite3PagerSync() directly to
++** sync the database file before calling CommitPhaseTwo() to delete the
++** journal file in this case.
+ */
+-SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager *pPager){
+- return &pPager->pBackup;
+-}
++SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
++ Pager *pPager, /* Pager object */
++ const char *zMaster, /* If not NULL, the master journal name */
++ int noSync /* True to omit the xSync on the db file */
++){
++ int rc = SQLITE_OK; /* Return code */
+
+-#ifndef SQLITE_OMIT_VACUUM
+-/*
+-** Unless this is an in-memory or temporary database, clear the pager cache.
+-*/
+-SQLITE_PRIVATE void sqlite3PagerClearCache(Pager *pPager){
+- if( !MEMDB && pPager->tempFile==0 ) pager_reset(pPager);
+-}
+-#endif
++ assert( pPager->eState==PAGER_WRITER_LOCKED
++ || pPager->eState==PAGER_WRITER_CACHEMOD
++ || pPager->eState==PAGER_WRITER_DBMOD
++ || pPager->eState==PAGER_ERROR
++ );
++ assert( assert_pager_state(pPager) );
+
+-#ifndef SQLITE_OMIT_WAL
+-/*
+-** This function is called when the user invokes "PRAGMA wal_checkpoint",
+-** "PRAGMA wal_blocking_checkpoint" or calls the sqlite3_wal_checkpoint()
+-** or wal_blocking_checkpoint() API functions.
+-**
+-** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART.
+-*/
+-SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, int eMode, int *pnLog, int *pnCkpt){
+- int rc = SQLITE_OK;
+- if( pPager->pWal ){
+- rc = sqlite3WalCheckpoint(pPager->pWal, eMode,
+- (eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler),
+- pPager->pBusyHandlerArg,
+- pPager->ckptSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
+- pnLog, pnCkpt
+- );
+- }
+- return rc;
+-}
++ /* If a prior error occurred, report that error again. */
++ if( NEVER(pPager->errCode) ) return pPager->errCode;
+
+-SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager){
+- return sqlite3WalCallback(pPager->pWal);
+-}
++ PAGERTRACE(("DATABASE SYNC: File=%s zMaster=%s nSize=%d\n",
++ pPager->zFilename, zMaster, pPager->dbSize));
+
+-/*
+-** Return true if the underlying VFS for the given pager supports the
+-** primitives necessary for write-ahead logging.
+-*/
+-SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager){
+- const sqlite3_io_methods *pMethods = pPager->fd->pMethods;
+- return pPager->exclusiveMode || (pMethods->iVersion>=2 && pMethods->xShmMap);
+-}
++ /* If no database changes have been made, return early. */
++ if( pPager->eState<PAGER_WRITER_CACHEMOD ) return SQLITE_OK;
+
+-/*
+-** Attempt to take an exclusive lock on the database file. If a PENDING lock
+-** is obtained instead, immediately release it.
+-*/
+-static int pagerExclusiveLock(Pager *pPager){
+- int rc; /* Return code */
++ if( MEMDB ){
++ /* If this is an in-memory db, or no pages have been written to, or this
++ ** function has already been called, it is mostly a no-op. However, any
++ ** backup in progress needs to be restarted.
++ */
++ sqlite3BackupRestart(pPager->pBackup);
++ }else{
++ if( pagerUseWal(pPager) ){
++ PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache);
++ PgHdr *pPageOne = 0;
++ if( pList==0 ){
++ /* Must have at least one page for the WAL commit flag.
++ ** Ticket [2d1a5c67dfc2363e44f29d9bbd57f] 2011-05-18 */
++ rc = sqlite3PagerGet(pPager, 1, &pPageOne);
++ pList = pPageOne;
++ pList->pDirty = 0;
++ }
++ assert( rc==SQLITE_OK );
++ if( ALWAYS(pList) ){
++ rc = pagerWalFrames(pPager, pList, pPager->dbSize, 1);
++ }
++ sqlite3PagerUnref(pPageOne);
++ if( rc==SQLITE_OK ){
++ sqlite3PcacheCleanAll(pPager->pPCache);
++ }
++ }else{
++ /* The following block updates the change-counter. Exactly how it
++ ** does this depends on whether or not the atomic-update optimization
++ ** was enabled at compile time, and if this transaction meets the
++ ** runtime criteria to use the operation:
++ **
++ ** * The file-system supports the atomic-write property for
++ ** blocks of size page-size, and
++ ** * This commit is not part of a multi-file transaction, and
++ ** * Exactly one page has been modified and store in the journal file.
++ **
++ ** If the optimization was not enabled at compile time, then the
++ ** pager_incr_changecounter() function is called to update the change
++ ** counter in 'indirect-mode'. If the optimization is compiled in but
++ ** is not applicable to this transaction, call sqlite3JournalCreate()
++ ** to make sure the journal file has actually been created, then call
++ ** pager_incr_changecounter() to update the change-counter in indirect
++ ** mode.
++ **
++ ** Otherwise, if the optimization is both enabled and applicable,
++ ** then call pager_incr_changecounter() to update the change-counter
++ ** in 'direct' mode. In this case the journal file will never be
++ ** created for this transaction.
++ */
++ #ifdef SQLITE_ENABLE_ATOMIC_WRITE
++ PgHdr *pPg;
++ assert( isOpen(pPager->jfd)
++ || pPager->journalMode==PAGER_JOURNALMODE_OFF
++ || pPager->journalMode==PAGER_JOURNALMODE_WAL
++ );
++ if( !zMaster && isOpen(pPager->jfd)
++ && pPager->journalOff==jrnlBufferSize(pPager)
++ && pPager->dbSize>=pPager->dbOrigSize
++ && (0==(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty)
++ ){
++ /* Update the db file change counter via the direct-write method. The
++ ** following call will modify the in-memory representation of page 1
++ ** to include the updated change counter and then write page 1
++ ** directly to the database file. Because of the atomic-write
++ ** property of the host file-system, this is safe.
++ */
++ rc = pager_incr_changecounter(pPager, 1);
++ }else{
++ rc = sqlite3JournalCreate(pPager->jfd);
++ if( rc==SQLITE_OK ){
++ rc = pager_incr_changecounter(pPager, 0);
++ }
++ }
++ #else
++ rc = pager_incr_changecounter(pPager, 0);
++ #endif
++ if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
++
++ /* Write the master journal name into the journal file. If a master
++ ** journal file name has already been written to the journal file,
++ ** or if zMaster is NULL (no master journal), then this call is a no-op.
++ */
++ rc = writeMasterJournal(pPager, zMaster);
++ if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
++
++ /* Sync the journal file and write all dirty pages to the database.
++ ** If the atomic-update optimization is being used, this sync will not
++ ** create the journal file or perform any real IO.
++ **
++ ** Because the change-counter page was just modified, unless the
++ ** atomic-update optimization is used it is almost certain that the
++ ** journal requires a sync here. However, in locking_mode=exclusive
++ ** on a system under memory pressure it is just possible that this is
++ ** not the case. In this case it is likely enough that the redundant
++ ** xSync() call will be changed to a no-op by the OS anyhow.
++ */
++ rc = syncJournal(pPager, 0);
++ if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
++
++ rc = pager_write_pagelist(pPager,sqlite3PcacheDirtyList(pPager->pPCache));
++ if( rc!=SQLITE_OK ){
++ assert( rc!=SQLITE_IOERR_BLOCKED );
++ goto commit_phase_one_exit;
++ }
++ sqlite3PcacheCleanAll(pPager->pPCache);
+
+- assert( pPager->eLock==SHARED_LOCK || pPager->eLock==EXCLUSIVE_LOCK );
+- rc = pagerLockDb(pPager, EXCLUSIVE_LOCK);
+- if( rc!=SQLITE_OK ){
+- /* If the attempt to grab the exclusive lock failed, release the
+- ** pending lock that may have been obtained instead. */
+- pagerUnlockDb(pPager, SHARED_LOCK);
++ /* If the file on disk is smaller than the database image, use
++ ** pager_truncate to grow the file here. This can happen if the database
++ ** image was extended as part of the current transaction and then the
++ ** last page in the db image moved to the free-list. In this case the
++ ** last page is never written out to disk, leaving the database file
++ ** undersized. Fix this now if it is the case. */
++ if( pPager->dbSize>pPager->dbFileSize ){
++ Pgno nNew = pPager->dbSize - (pPager->dbSize==PAGER_MJ_PGNO(pPager));
++ assert( pPager->eState==PAGER_WRITER_DBMOD );
++ rc = pager_truncate(pPager, nNew);
++ if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
++ }
++
++ /* Finally, sync the database file. */
++ if( !noSync ){
++ rc = sqlite3PagerSync(pPager, zMaster);
++ }
++ IOTRACE(("DBSYNC %p\n", pPager))
++ }
+ }
+
++commit_phase_one_exit:
++ if( rc==SQLITE_OK && !pagerUseWal(pPager) ){
++ pPager->eState = PAGER_WRITER_FINISHED;
++ }
+ return rc;
+ }
+
++
+ /*
+-** Call sqlite3WalOpen() to open the WAL handle. If the pager is in
+-** exclusive-locking mode when this function is called, take an EXCLUSIVE
+-** lock on the database file and use heap-memory to store the wal-index
+-** in. Otherwise, use the normal shared-memory.
++** When this function is called, the database file has been completely
++** updated to reflect the changes made by the current transaction and
++** synced to disk. The journal file still exists in the file-system
++** though, and if a failure occurs at this point it will eventually
++** be used as a hot-journal and the current transaction rolled back.
++**
++** This function finalizes the journal file, either by deleting,
++** truncating or partially zeroing it, so that it cannot be used
++** for hot-journal rollback. Once this is done the transaction is
++** irrevocably committed.
++**
++** If an error occurs, an IO error code is returned and the pager
++** moves into the error state. Otherwise, SQLITE_OK is returned.
+ */
+-static int pagerOpenWal(Pager *pPager){
+- int rc = SQLITE_OK;
++SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager *pPager){
++ int rc = SQLITE_OK; /* Return code */
+
+- assert( pPager->pWal==0 && pPager->tempFile==0 );
+- assert( pPager->eLock==SHARED_LOCK || pPager->eLock==EXCLUSIVE_LOCK );
++ /* This routine should not be called if a prior error has occurred.
++ ** But if (due to a coding error elsewhere in the system) it does get
++ ** called, just return the same error code without doing anything. */
++ if( NEVER(pPager->errCode) ) return pPager->errCode;
+
+- /* If the pager is already in exclusive-mode, the WAL module will use
+- ** heap-memory for the wal-index instead of the VFS shared-memory
+- ** implementation. Take the exclusive lock now, before opening the WAL
+- ** file, to make sure this is safe.
+- */
+- if( pPager->exclusiveMode ){
+- rc = pagerExclusiveLock(pPager);
+- }
++ assert( pPager->eState==PAGER_WRITER_LOCKED
++ || pPager->eState==PAGER_WRITER_FINISHED
++ || (pagerUseWal(pPager) && pPager->eState==PAGER_WRITER_CACHEMOD)
++ );
++ assert( assert_pager_state(pPager) );
+
+- /* Open the connection to the log file. If this operation fails,
+- ** (e.g. due to malloc() failure), return an error code.
++ /* An optimization. If the database was not actually modified during
++ ** this transaction, the pager is running in exclusive-mode and is
++ ** using persistent journals, then this function is a no-op.
++ **
++ ** The start of the journal file currently contains a single journal
++ ** header with the nRec field set to 0. If such a journal is used as
++ ** a hot-journal during hot-journal rollback, 0 changes will be made
++ ** to the database file. So there is no need to zero the journal
++ ** header. Since the pager is in exclusive mode, there is no need
++ ** to drop any locks either.
+ */
+- if( rc==SQLITE_OK ){
+- rc = sqlite3WalOpen(pPager->pVfs,
+- pPager->fd, pPager->zWal, pPager->exclusiveMode,
+- pPager->journalSizeLimit, &pPager->pWal
+- );
++ if( pPager->eState==PAGER_WRITER_LOCKED
++ && pPager->exclusiveMode
++ && pPager->journalMode==PAGER_JOURNALMODE_PERSIST
++ ){
++ assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) || !pPager->journalOff );
++ pPager->eState = PAGER_READER;
++ return SQLITE_OK;
+ }
+- pagerFixMaplimit(pPager);
+
+- return rc;
++ PAGERTRACE(("COMMIT %d\n", PAGERID(pPager)));
++ pPager->iDataVersion++;
++ rc = pager_end_transaction(pPager, pPager->setMaster, 1);
++ return pager_error(pPager, rc);
+ }
+
+-
+ /*
+-** The caller must be holding a SHARED lock on the database file to call
+-** this function.
++** If a write transaction is open, then all changes made within the
++** transaction are reverted and the current write-transaction is closed.
++** The pager falls back to PAGER_READER state if successful, or PAGER_ERROR
++** state if an error occurs.
+ **
+-** If the pager passed as the first argument is open on a real database
+-** file (not a temp file or an in-memory database), and the WAL file
+-** is not already open, make an attempt to open it now. If successful,
+-** return SQLITE_OK. If an error occurs or the VFS used by the pager does
+-** not support the xShmXXX() methods, return an error code. *pbOpen is
+-** not modified in either case.
++** If the pager is already in PAGER_ERROR state when this function is called,
++** it returns Pager.errCode immediately. No work is performed in this case.
+ **
+-** If the pager is open on a temp-file (or in-memory database), or if
+-** the WAL file is already open, set *pbOpen to 1 and return SQLITE_OK
+-** without doing anything.
++** Otherwise, in rollback mode, this function performs two functions:
++**
++** 1) It rolls back the journal file, restoring all database file and
++** in-memory cache pages to the state they were in when the transaction
++** was opened, and
++**
++** 2) It finalizes the journal file, so that it is not used for hot
++** rollback at any point in the future.
++**
++** Finalization of the journal file (task 2) is only performed if the
++** rollback is successful.
++**
++** In WAL mode, all cache-entries containing data modified within the
++** current transaction are either expelled from the cache or reverted to
++** their pre-transaction state by re-reading data from the database or
++** WAL files. The WAL transaction is then closed.
+ */
+-SQLITE_PRIVATE int sqlite3PagerOpenWal(
+- Pager *pPager, /* Pager object */
+- int *pbOpen /* OUT: Set to true if call is a no-op */
+-){
+- int rc = SQLITE_OK; /* Return code */
++SQLITE_PRIVATE int sqlite3PagerRollback(Pager *pPager){
++ int rc = SQLITE_OK; /* Return code */
++ PAGERTRACE(("ROLLBACK %d\n", PAGERID(pPager)));
+
++ /* PagerRollback() is a no-op if called in READER or OPEN state. If
++ ** the pager is already in the ERROR state, the rollback is not
++ ** attempted here. Instead, the error code is returned to the caller.
++ */
+ assert( assert_pager_state(pPager) );
+- assert( pPager->eState==PAGER_OPEN || pbOpen );
+- assert( pPager->eState==PAGER_READER || !pbOpen );
+- assert( pbOpen==0 || *pbOpen==0 );
+- assert( pbOpen!=0 || (!pPager->tempFile && !pPager->pWal) );
+-
+- if( !pPager->tempFile && !pPager->pWal ){
+- if( !sqlite3PagerWalSupported(pPager) ) return SQLITE_CANTOPEN;
+-
+- /* Close any rollback journal previously open */
+- sqlite3OsClose(pPager->jfd);
++ if( pPager->eState==PAGER_ERROR ) return pPager->errCode;
++ if( pPager->eState<=PAGER_READER ) return SQLITE_OK;
+
+- rc = pagerOpenWal(pPager);
+- if( rc==SQLITE_OK ){
+- pPager->journalMode = PAGER_JOURNALMODE_WAL;
+- pPager->eState = PAGER_OPEN;
++ if( pagerUseWal(pPager) ){
++ int rc2;
++ rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, -1);
++ rc2 = pager_end_transaction(pPager, pPager->setMaster, 0);
++ if( rc==SQLITE_OK ) rc = rc2;
++ }else if( !isOpen(pPager->jfd) || pPager->eState==PAGER_WRITER_LOCKED ){
++ int eState = pPager->eState;
++ rc = pager_end_transaction(pPager, 0, 0);
++ if( !MEMDB && eState>PAGER_WRITER_LOCKED ){
++ /* This can happen using journal_mode=off. Move the pager to the error
++ ** state to indicate that the contents of the cache may not be trusted.
++ ** Any active readers will get SQLITE_ABORT.
++ */
++ pPager->errCode = SQLITE_ABORT;
++ pPager->eState = PAGER_ERROR;
++ return rc;
+ }
+ }else{
+- *pbOpen = 1;
++ rc = pager_playback(pPager, 0);
+ }
+
+- return rc;
++ assert( pPager->eState==PAGER_READER || rc!=SQLITE_OK );
++ assert( rc==SQLITE_OK || rc==SQLITE_FULL || rc==SQLITE_CORRUPT
++ || rc==SQLITE_NOMEM || (rc&0xFF)==SQLITE_IOERR
++ || rc==SQLITE_CANTOPEN
++ );
++
++ /* If an error occurs during a ROLLBACK, we can no longer trust the pager
++ ** cache. So call pager_error() on the way out to make any error persistent.
++ */
++ return pager_error(pPager, rc);
+ }
+
+ /*
+-** This function is called to close the connection to the log file prior
+-** to switching from WAL to rollback mode.
+-**
+-** Before closing the log file, this function attempts to take an
+-** EXCLUSIVE lock on the database file. If this cannot be obtained, an
+-** error (SQLITE_BUSY) is returned and the log connection is not closed.
+-** If successful, the EXCLUSIVE lock is not released before returning.
++** Return TRUE if the database file is opened read-only. Return FALSE
++** if the database is (in theory) writable.
+ */
+-SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager){
+- int rc = SQLITE_OK;
++SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager *pPager){
++ return pPager->readOnly;
++}
+
+- assert( pPager->journalMode==PAGER_JOURNALMODE_WAL );
++/*
++** Return the number of references to the pager.
++*/
++SQLITE_PRIVATE int sqlite3PagerRefcount(Pager *pPager){
++ return sqlite3PcacheRefCount(pPager->pPCache);
++}
+
+- /* If the log file is not already open, but does exist in the file-system,
+- ** it may need to be checkpointed before the connection can switch to
+- ** rollback mode. Open it now so this can happen.
+- */
+- if( !pPager->pWal ){
+- int logexists = 0;
+- rc = pagerLockDb(pPager, SHARED_LOCK);
+- if( rc==SQLITE_OK ){
+- rc = sqlite3OsAccess(
+- pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &logexists
+- );
+- }
+- if( rc==SQLITE_OK && logexists ){
+- rc = pagerOpenWal(pPager);
+- }
+- }
+-
+- /* Checkpoint and close the log. Because an EXCLUSIVE lock is held on
+- ** the database file, the log and log-summary files will be deleted.
+- */
+- if( rc==SQLITE_OK && pPager->pWal ){
+- rc = pagerExclusiveLock(pPager);
+- if( rc==SQLITE_OK ){
+- rc = sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags,
+- pPager->pageSize, (u8*)pPager->pTmpSpace);
+- pPager->pWal = 0;
+- pagerFixMaplimit(pPager);
+- }
+- }
+- return rc;
++/*
++** Return the approximate number of bytes of memory currently
++** used by the pager and its associated cache.
++*/
++SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager *pPager){
++ int perPageSize = pPager->pageSize + pPager->nExtra + sizeof(PgHdr)
++ + 5*sizeof(void*);
++ return perPageSize*sqlite3PcachePagecount(pPager->pPCache)
++ + sqlite3MallocSize(pPager)
++ + pPager->pageSize;
+ }
+
+-#endif /* !SQLITE_OMIT_WAL */
++/*
++** Return the number of references to the specified page.
++*/
++SQLITE_PRIVATE int sqlite3PagerPageRefcount(DbPage *pPage){
++ return sqlite3PcachePageRefcount(pPage);
++}
+
+-#ifdef SQLITE_ENABLE_ZIPVFS
++#ifdef SQLITE_TEST
+ /*
+-** A read-lock must be held on the pager when this function is called. If
+-** the pager is in WAL mode and the WAL file currently contains one or more
+-** frames, return the size in bytes of the page images stored within the
+-** WAL frames. Otherwise, if this is not a WAL database or the WAL file
+-** is empty, return 0.
++** This routine is used for testing and analysis only.
+ */
+-SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
+- assert( pPager->eState>=PAGER_READER );
+- return sqlite3WalFramesize(pPager->pWal);
++SQLITE_PRIVATE int *sqlite3PagerStats(Pager *pPager){
++ static int a[11];
++ a[0] = sqlite3PcacheRefCount(pPager->pPCache);
++ a[1] = sqlite3PcachePagecount(pPager->pPCache);
++ a[2] = sqlite3PcacheGetCachesize(pPager->pPCache);
++ a[3] = pPager->eState==PAGER_OPEN ? -1 : (int) pPager->dbSize;
++ a[4] = pPager->eState;
++ a[5] = pPager->errCode;
++ a[6] = pPager->aStat[PAGER_STAT_HIT];
++ a[7] = pPager->aStat[PAGER_STAT_MISS];
++ a[8] = 0; /* Used to be pPager->nOvfl */
++ a[9] = pPager->nRead;
++ a[10] = pPager->aStat[PAGER_STAT_WRITE];
++ return a;
+ }
+ #endif
+
+-
+-#endif /* SQLITE_OMIT_DISKIO */
+-
+-/************** End of pager.c ***********************************************/
+-/************** Begin file wal.c *********************************************/
+ /*
+-** 2010 February 1
+-**
+-** The author disclaims copyright to this source code. In place of
+-** a legal notice, here is a blessing:
+-**
+-** May you do good and not evil.
+-** May you find forgiveness for yourself and forgive others.
+-** May you share freely, never taking more than you give.
+-**
+-*************************************************************************
+-**
+-** This file contains the implementation of a write-ahead log (WAL) used in
+-** "journal_mode=WAL" mode.
+-**
+-** WRITE-AHEAD LOG (WAL) FILE FORMAT
+-**
+-** A WAL file consists of a header followed by zero or more "frames".
+-** Each frame records the revised content of a single page from the
+-** database file. All changes to the database are recorded by writing
+-** frames into the WAL. Transactions commit when a frame is written that
+-** contains a commit marker. A single WAL can and usually does record
+-** multiple transactions. Periodically, the content of the WAL is
+-** transferred back into the database file in an operation called a
+-** "checkpoint".
+-**
+-** A single WAL file can be used multiple times. In other words, the
+-** WAL can fill up with frames and then be checkpointed and then new
+-** frames can overwrite the old ones. A WAL always grows from beginning
+-** toward the end. Checksums and counters attached to each frame are
+-** used to determine which frames within the WAL are valid and which
+-** are leftovers from prior checkpoints.
+-**
+-** The WAL header is 32 bytes in size and consists of the following eight
+-** big-endian 32-bit unsigned integer values:
+-**
+-** 0: Magic number. 0x377f0682 or 0x377f0683
+-** 4: File format version. Currently 3007000
+-** 8: Database page size. Example: 1024
+-** 12: Checkpoint sequence number
+-** 16: Salt-1, random integer incremented with each checkpoint
+-** 20: Salt-2, a different random integer changing with each ckpt
+-** 24: Checksum-1 (first part of checksum for first 24 bytes of header).
+-** 28: Checksum-2 (second part of checksum for first 24 bytes of header).
+-**
+-** Immediately following the wal-header are zero or more frames. Each
+-** frame consists of a 24-byte frame-header followed by a <page-size> bytes
+-** of page data. The frame-header is six big-endian 32-bit unsigned
+-** integer values, as follows:
+-**
+-** 0: Page number.
+-** 4: For commit records, the size of the database image in pages
+-** after the commit. For all other records, zero.
+-** 8: Salt-1 (copied from the header)
+-** 12: Salt-2 (copied from the header)
+-** 16: Checksum-1.
+-** 20: Checksum-2.
+-**
+-** A frame is considered valid if and only if the following conditions are
+-** true:
+-**
+-** (1) The salt-1 and salt-2 values in the frame-header match
+-** salt values in the wal-header
+-**
+-** (2) The checksum values in the final 8 bytes of the frame-header
+-** exactly match the checksum computed consecutively on the
+-** WAL header and the first 8 bytes and the content of all frames
+-** up to and including the current frame.
+-**
+-** The checksum is computed using 32-bit big-endian integers if the
+-** magic number in the first 4 bytes of the WAL is 0x377f0683 and it
+-** is computed using little-endian if the magic number is 0x377f0682.
+-** The checksum values are always stored in the frame header in a
+-** big-endian format regardless of which byte order is used to compute
+-** the checksum. The checksum is computed by interpreting the input as
+-** an even number of unsigned 32-bit integers: x[0] through x[N]. The
+-** algorithm used for the checksum is as follows:
+-**
+-** for i from 0 to n-1 step 2:
+-** s0 += x[i] + s1;
+-** s1 += x[i+1] + s0;
+-** endfor
+-**
+-** Note that s0 and s1 are both weighted checksums using fibonacci weights
+-** in reverse order (the largest fibonacci weight occurs on the first element
+-** of the sequence being summed.) The s1 value spans all 32-bit
+-** terms of the sequence whereas s0 omits the final term.
+-**
+-** On a checkpoint, the WAL is first VFS.xSync-ed, then valid content of the
+-** WAL is transferred into the database, then the database is VFS.xSync-ed.
+-** The VFS.xSync operations serve as write barriers - all writes launched
+-** before the xSync must complete before any write that launches after the
+-** xSync begins.
+-**
+-** After each checkpoint, the salt-1 value is incremented and the salt-2
+-** value is randomized. This prevents old and new frames in the WAL from
+-** being considered valid at the same time and being checkpointing together
+-** following a crash.
+-**
+-** READER ALGORITHM
+-**
+-** To read a page from the database (call it page number P), a reader
+-** first checks the WAL to see if it contains page P. If so, then the
+-** last valid instance of page P that is a followed by a commit frame
+-** or is a commit frame itself becomes the value read. If the WAL
+-** contains no copies of page P that are valid and which are a commit
+-** frame or are followed by a commit frame, then page P is read from
+-** the database file.
+-**
+-** To start a read transaction, the reader records the index of the last
+-** valid frame in the WAL. The reader uses this recorded "mxFrame" value
+-** for all subsequent read operations. New transactions can be appended
+-** to the WAL, but as long as the reader uses its original mxFrame value
+-** and ignores the newly appended content, it will see a consistent snapshot
+-** of the database from a single point in time. This technique allows
+-** multiple concurrent readers to view different versions of the database
+-** content simultaneously.
+-**
+-** The reader algorithm in the previous paragraphs works correctly, but
+-** because frames for page P can appear anywhere within the WAL, the
+-** reader has to scan the entire WAL looking for page P frames. If the
+-** WAL is large (multiple megabytes is typical) that scan can be slow,
+-** and read performance suffers. To overcome this problem, a separate
+-** data structure called the wal-index is maintained to expedite the
+-** search for frames of a particular page.
+-**
+-** WAL-INDEX FORMAT
+-**
+-** Conceptually, the wal-index is shared memory, though VFS implementations
+-** might choose to implement the wal-index using a mmapped file. Because
+-** the wal-index is shared memory, SQLite does not support journal_mode=WAL
+-** on a network filesystem. All users of the database must be able to
+-** share memory.
+-**
+-** The wal-index is transient. After a crash, the wal-index can (and should
+-** be) reconstructed from the original WAL file. In fact, the VFS is required
+-** to either truncate or zero the header of the wal-index when the last
+-** connection to it closes. Because the wal-index is transient, it can
+-** use an architecture-specific format; it does not have to be cross-platform.
+-** Hence, unlike the database and WAL file formats which store all values
+-** as big endian, the wal-index can store multi-byte values in the native
+-** byte order of the host computer.
+-**
+-** The purpose of the wal-index is to answer this question quickly: Given
+-** a page number P and a maximum frame index M, return the index of the
+-** last frame in the wal before frame M for page P in the WAL, or return
+-** NULL if there are no frames for page P in the WAL prior to M.
+-**
+-** The wal-index consists of a header region, followed by an one or
+-** more index blocks.
+-**
+-** The wal-index header contains the total number of frames within the WAL
+-** in the mxFrame field.
+-**
+-** Each index block except for the first contains information on
+-** HASHTABLE_NPAGE frames. The first index block contains information on
+-** HASHTABLE_NPAGE_ONE frames. The values of HASHTABLE_NPAGE_ONE and
+-** HASHTABLE_NPAGE are selected so that together the wal-index header and
+-** first index block are the same size as all other index blocks in the
+-** wal-index.
+-**
+-** Each index block contains two sections, a page-mapping that contains the
+-** database page number associated with each wal frame, and a hash-table
+-** that allows readers to query an index block for a specific page number.
+-** The page-mapping is an array of HASHTABLE_NPAGE (or HASHTABLE_NPAGE_ONE
+-** for the first index block) 32-bit page numbers. The first entry in the
+-** first index-block contains the database page number corresponding to the
+-** first frame in the WAL file. The first entry in the second index block
+-** in the WAL file corresponds to the (HASHTABLE_NPAGE_ONE+1)th frame in
+-** the log, and so on.
+-**
+-** The last index block in a wal-index usually contains less than the full
+-** complement of HASHTABLE_NPAGE (or HASHTABLE_NPAGE_ONE) page-numbers,
+-** depending on the contents of the WAL file. This does not change the
+-** allocated size of the page-mapping array - the page-mapping array merely
+-** contains unused entries.
+-**
+-** Even without using the hash table, the last frame for page P
+-** can be found by scanning the page-mapping sections of each index block
+-** starting with the last index block and moving toward the first, and
+-** within each index block, starting at the end and moving toward the
+-** beginning. The first entry that equals P corresponds to the frame
+-** holding the content for that page.
+-**
+-** The hash table consists of HASHTABLE_NSLOT 16-bit unsigned integers.
+-** HASHTABLE_NSLOT = 2*HASHTABLE_NPAGE, and there is one entry in the
+-** hash table for each page number in the mapping section, so the hash
+-** table is never more than half full. The expected number of collisions
+-** prior to finding a match is 1. Each entry of the hash table is an
+-** 1-based index of an entry in the mapping section of the same
+-** index block. Let K be the 1-based index of the largest entry in
+-** the mapping section. (For index blocks other than the last, K will
+-** always be exactly HASHTABLE_NPAGE (4096) and for the last index block
+-** K will be (mxFrame%HASHTABLE_NPAGE).) Unused slots of the hash table
+-** contain a value of 0.
++** Parameter eStat must be either SQLITE_DBSTATUS_CACHE_HIT or
++** SQLITE_DBSTATUS_CACHE_MISS. Before returning, *pnVal is incremented by the
++** current cache hit or miss count, according to the value of eStat. If the
++** reset parameter is non-zero, the cache hit or miss count is zeroed before
++** returning.
++*/
++SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, int *pnVal){
++
++ assert( eStat==SQLITE_DBSTATUS_CACHE_HIT
++ || eStat==SQLITE_DBSTATUS_CACHE_MISS
++ || eStat==SQLITE_DBSTATUS_CACHE_WRITE
++ );
++
++ assert( SQLITE_DBSTATUS_CACHE_HIT+1==SQLITE_DBSTATUS_CACHE_MISS );
++ assert( SQLITE_DBSTATUS_CACHE_HIT+2==SQLITE_DBSTATUS_CACHE_WRITE );
++ assert( PAGER_STAT_HIT==0 && PAGER_STAT_MISS==1 && PAGER_STAT_WRITE==2 );
++
++ *pnVal += pPager->aStat[eStat - SQLITE_DBSTATUS_CACHE_HIT];
++ if( reset ){
++ pPager->aStat[eStat - SQLITE_DBSTATUS_CACHE_HIT] = 0;
++ }
++}
++
++/*
++** Return true if this is an in-memory pager.
++*/
++SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager *pPager){
++ return MEMDB;
++}
++
++/*
++** Check that there are at least nSavepoint savepoints open. If there are
++** currently less than nSavepoints open, then open one or more savepoints
++** to make up the difference. If the number of savepoints is already
++** equal to nSavepoint, then this function is a no-op.
+ **
+-** To look for page P in the hash table, first compute a hash iKey on
+-** P as follows:
++** If a memory allocation fails, SQLITE_NOMEM is returned. If an error
++** occurs while opening the sub-journal file, then an IO error code is
++** returned. Otherwise, SQLITE_OK.
++*/
++SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int nSavepoint){
++ int rc = SQLITE_OK; /* Return code */
++ int nCurrent = pPager->nSavepoint; /* Current number of savepoints */
++
++ assert( pPager->eState>=PAGER_WRITER_LOCKED );
++ assert( assert_pager_state(pPager) );
++
++ if( nSavepoint>nCurrent && pPager->useJournal ){
++ int ii; /* Iterator variable */
++ PagerSavepoint *aNew; /* New Pager.aSavepoint array */
++
++ /* Grow the Pager.aSavepoint array using realloc(). Return SQLITE_NOMEM
++ ** if the allocation fails. Otherwise, zero the new portion in case a
++ ** malloc failure occurs while populating it in the for(...) loop below.
++ */
++ aNew = (PagerSavepoint *)sqlite3Realloc(
++ pPager->aSavepoint, sizeof(PagerSavepoint)*nSavepoint
++ );
++ if( !aNew ){
++ return SQLITE_NOMEM;
++ }
++ memset(&aNew[nCurrent], 0, (nSavepoint-nCurrent) * sizeof(PagerSavepoint));
++ pPager->aSavepoint = aNew;
++
++ /* Populate the PagerSavepoint structures just allocated. */
++ for(ii=nCurrent; ii<nSavepoint; ii++){
++ aNew[ii].nOrig = pPager->dbSize;
++ if( isOpen(pPager->jfd) && pPager->journalOff>0 ){
++ aNew[ii].iOffset = pPager->journalOff;
++ }else{
++ aNew[ii].iOffset = JOURNAL_HDR_SZ(pPager);
++ }
++ aNew[ii].iSubRec = pPager->nSubRec;
++ aNew[ii].pInSavepoint = sqlite3BitvecCreate(pPager->dbSize);
++ if( !aNew[ii].pInSavepoint ){
++ return SQLITE_NOMEM;
++ }
++ if( pagerUseWal(pPager) ){
++ sqlite3WalSavepoint(pPager->pWal, aNew[ii].aWalData);
++ }
++ pPager->nSavepoint = ii+1;
++ }
++ assert( pPager->nSavepoint==nSavepoint );
++ assertTruncateConstraint(pPager);
++ }
++
++ return rc;
++}
++
++/*
++** This function is called to rollback or release (commit) a savepoint.
++** The savepoint to release or rollback need not be the most recently
++** created savepoint.
+ **
+-** iKey = (P * 383) % HASHTABLE_NSLOT
++** Parameter op is always either SAVEPOINT_ROLLBACK or SAVEPOINT_RELEASE.
++** If it is SAVEPOINT_RELEASE, then release and destroy the savepoint with
++** index iSavepoint. If it is SAVEPOINT_ROLLBACK, then rollback all changes
++** that have occurred since the specified savepoint was created.
+ **
+-** Then start scanning entries of the hash table, starting with iKey
+-** (wrapping around to the beginning when the end of the hash table is
+-** reached) until an unused hash slot is found. Let the first unused slot
+-** be at index iUnused. (iUnused might be less than iKey if there was
+-** wrap-around.) Because the hash table is never more than half full,
+-** the search is guaranteed to eventually hit an unused entry. Let
+-** iMax be the value between iKey and iUnused, closest to iUnused,
+-** where aHash[iMax]==P. If there is no iMax entry (if there exists
+-** no hash slot such that aHash[i]==p) then page P is not in the
+-** current index block. Otherwise the iMax-th mapping entry of the
+-** current index block corresponds to the last entry that references
+-** page P.
++** The savepoint to rollback or release is identified by parameter
++** iSavepoint. A value of 0 means to operate on the outermost savepoint
++** (the first created). A value of (Pager.nSavepoint-1) means operate
++** on the most recently created savepoint. If iSavepoint is greater than
++** (Pager.nSavepoint-1), then this function is a no-op.
+ **
+-** A hash search begins with the last index block and moves toward the
+-** first index block, looking for entries corresponding to page P. On
+-** average, only two or three slots in each index block need to be
+-** examined in order to either find the last entry for page P, or to
+-** establish that no such entry exists in the block. Each index block
+-** holds over 4000 entries. So two or three index blocks are sufficient
+-** to cover a typical 10 megabyte WAL file, assuming 1K pages. 8 or 10
+-** comparisons (on average) suffice to either locate a frame in the
+-** WAL or to establish that the frame does not exist in the WAL. This
+-** is much faster than scanning the entire 10MB WAL.
++** If a negative value is passed to this function, then the current
++** transaction is rolled back. This is different to calling
++** sqlite3PagerRollback() because this function does not terminate
++** the transaction or unlock the database, it just restores the
++** contents of the database to its original state.
+ **
+-** Note that entries are added in order of increasing K. Hence, one
+-** reader might be using some value K0 and a second reader that started
+-** at a later time (after additional transactions were added to the WAL
+-** and to the wal-index) might be using a different value K1, where K1>K0.
+-** Both readers can use the same hash table and mapping section to get
+-** the correct result. There may be entries in the hash table with
+-** K>K0 but to the first reader, those entries will appear to be unused
-** slots in the hash table and so the first reader will get an answer as
-** if no values greater than K0 had ever been inserted into the hash table
-** in the first place - which is what reader one wants. Meanwhile, the
-** second reader using K1 will see additional values that were inserted
-** later, which is exactly what reader two wants.
--**
++** In any case, all savepoints with an index greater than iSavepoint
++** are destroyed. If this is a release operation (op==SAVEPOINT_RELEASE),
++** then savepoint iSavepoint is also destroyed.
+ **
-** When a rollback occurs, the value of K is decreased. Hash table entries
-** that correspond to frames greater than the new K value are removed
-** from the hash table at this point.
-*/
-#ifndef SQLITE_OMIT_WAL
--
--
--/*
++** This function may return SQLITE_NOMEM if a memory allocation fails,
++** or an IO error code if an IO error occurs while rolling back a
++** savepoint. If no errors occur, SQLITE_OK is returned.
++*/
++SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
++ int rc = pPager->errCode; /* Return code */
++
++ assert( op==SAVEPOINT_RELEASE || op==SAVEPOINT_ROLLBACK );
++ assert( iSavepoint>=0 || op==SAVEPOINT_ROLLBACK );
++
++ if( rc==SQLITE_OK && iSavepoint<pPager->nSavepoint ){
++ int ii; /* Iterator variable */
++ int nNew; /* Number of remaining savepoints after this op. */
++
++ /* Figure out how many savepoints will still be active after this
++ ** operation. Store this value in nNew. Then free resources associated
++ ** with any savepoints that are destroyed by this operation.
++ */
++ nNew = iSavepoint + (( op==SAVEPOINT_RELEASE ) ? 0 : 1);
++ for(ii=nNew; ii<pPager->nSavepoint; ii++){
++ sqlite3BitvecDestroy(pPager->aSavepoint[ii].pInSavepoint);
++ }
++ pPager->nSavepoint = nNew;
++
++ /* If this is a release of the outermost savepoint, truncate
++ ** the sub-journal to zero bytes in size. */
++ if( op==SAVEPOINT_RELEASE ){
++ if( nNew==0 && isOpen(pPager->sjfd) ){
++ /* Only truncate if it is an in-memory sub-journal. */
++ if( sqlite3IsMemJournal(pPager->sjfd) ){
++ rc = sqlite3OsTruncate(pPager->sjfd, 0);
++ assert( rc==SQLITE_OK );
++ }
++ pPager->nSubRec = 0;
++ }
++ }
++ /* Else this is a rollback operation, playback the specified savepoint.
++ ** If this is a temp-file, it is possible that the journal file has
++ ** not yet been opened. In this case there have been no changes to
++ ** the database file, so the playback operation can be skipped.
++ */
++ else if( pagerUseWal(pPager) || isOpen(pPager->jfd) ){
++ PagerSavepoint *pSavepoint = (nNew==0)?0:&pPager->aSavepoint[nNew-1];
++ rc = pagerPlaybackSavepoint(pPager, pSavepoint);
++ assert(rc!=SQLITE_DONE);
++ }
++ }
+
++ return rc;
++}
+
+ /*
-** Trace output macros
--*/
++** Return the full pathname of the database file.
++**
++** Except, if the pager is in-memory only, then return an empty string if
++** nullIfMemDb is true. This routine is called with nullIfMemDb==1 when
++** used to report the filename to the user, for compatibility with legacy
++** behavior. But when the Btree needs to know the filename for matching to
++** shared cache, it uses nullIfMemDb==0 so that in-memory databases can
++** participate in shared-cache.
+ */
-#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
-SQLITE_PRIVATE int sqlite3WalTrace = 0;
-# define WALTRACE(X) if(sqlite3WalTrace) sqlite3DebugPrintf X
-#else
-# define WALTRACE(X)
-#endif
--
--/*
++SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager *pPager, int nullIfMemDb){
++ return (nullIfMemDb && pPager->memDb) ? "" : pPager->zFilename;
++}
+
+ /*
-** The maximum (and only) versions of the wal and wal-index formats
-** that may be interpreted by this version of SQLite.
-**
@@ -4144,38 +36943,86 @@
-** checksum test is successful) and finds that the version field is not
-** WALINDEX_MAX_VERSION, then no read-transaction is opened and SQLite
-** returns SQLITE_CANTOPEN.
--*/
++** Return the VFS structure for the pager.
+ */
-#define WAL_MAX_VERSION 3007000
-#define WALINDEX_MAX_VERSION 3007000
--
--/*
++SQLITE_PRIVATE const sqlite3_vfs *sqlite3PagerVfs(Pager *pPager){
++ return pPager->pVfs;
++}
+
+ /*
-** Indices of various locking bytes. WAL_NREADER is the number
-** of available reader locks and should be at least 3.
--*/
++** Return the file handle for the database file associated
++** with the pager. This might return NULL if the file has
++** not yet been opened.
+ */
-#define WAL_WRITE_LOCK 0
-#define WAL_ALL_BUT_WRITE 1
-#define WAL_CKPT_LOCK 1
-#define WAL_RECOVER_LOCK 2
-#define WAL_READ_LOCK(I) (3+(I))
-#define WAL_NREADER (SQLITE_SHM_NLOCK-3)
--
--
++SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager *pPager){
++ return pPager->fd;
++}
+
++/*
++** Return the full pathname of the journal file.
++*/
++SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager *pPager){
++ return pPager->zJournal;
++}
+
-/* Object declarations */
-typedef struct WalIndexHdr WalIndexHdr;
-typedef struct WalIterator WalIterator;
-typedef struct WalCkptInfo WalCkptInfo;
--
--
--/*
++/*
++** Return true if fsync() calls are disabled for this pager. Return FALSE
++** if fsync()s are executed normally.
++*/
++SQLITE_PRIVATE int sqlite3PagerNosync(Pager *pPager){
++ return pPager->noSync;
++}
+
++#ifdef SQLITE_HAS_CODEC
++/*
++** Set or retrieve the codec for this pager
++*/
++SQLITE_PRIVATE void sqlite3PagerSetCodec(
++ Pager *pPager,
++ void *(*xCodec)(void*,void*,Pgno,int),
++ void (*xCodecSizeChng)(void*,int,int),
++ void (*xCodecFree)(void*),
++ void *pCodec
++){
++ if( pPager->xCodecFree ) pPager->xCodecFree(pPager->pCodec);
++ pPager->xCodec = pPager->memDb ? 0 : xCodec;
++ pPager->xCodecSizeChng = xCodecSizeChng;
++ pPager->xCodecFree = xCodecFree;
++ pPager->pCodec = pCodec;
++ pagerReportSize(pPager);
++}
++SQLITE_PRIVATE void *sqlite3PagerGetCodec(Pager *pPager){
++ return pPager->pCodec;
++}
+
+ /*
-** The following object holds a copy of the wal-index header content.
-**
-** The actual header in the wal-index consists of two copies of this
-** object.
--**
++** This function is called by the wal module when writing page content
++** into the log file.
+ **
-** The szPage value can be any power of 2 between 512 and 32768, inclusive.
-** Or it can be 1 to represent a 65536-byte page. The latter case was
-** added in 3.7.1 when support for 64K pages was added.
--*/
++** This function returns a pointer to a buffer containing the encrypted
++** page content. If a malloc fails, this function may return NULL.
+ */
-struct WalIndexHdr {
- u32 iVersion; /* Wal-index version */
- u32 unused; /* Unused (padding) field */
@@ -4189,8 +37036,13 @@
- u32 aSalt[2]; /* Two salt values copied from WAL header */
- u32 aCksum[2]; /* Checksum over all prior fields */
-};
--
--/*
++SQLITE_PRIVATE void *sqlite3PagerCodec(PgHdr *pPg){
++ void *aData = 0;
++ CODEC2(pPg->pPager, pPg->pData, pPg->pgno, 6, return 0, aData);
++ return aData;
++}
+
+ /*
-** A copy of the following object occurs in the wal-index immediately
-** following the second copy of the WalIndexHdr. This object stores
-** information used by checkpoint.
@@ -4202,7 +37054,17 @@
-** holding the WAL_CKPT_LOCK lock (which includes a recovery thread).
-** However, a WAL_WRITE_LOCK thread can move the value of nBackfill from
-** mxFrame back to zero when the WAL is reset.
--**
++** Return the current pager state
++*/
++SQLITE_PRIVATE int sqlite3PagerState(Pager *pPager){
++ return pPager->eState;
++}
++#endif /* SQLITE_HAS_CODEC */
++
++#ifndef SQLITE_OMIT_AUTOVACUUM
++/*
++** Move the page pPg to location pgno in the file.
+ **
-** There is one entry in aReadMark[] for each reader lock. If a reader
-** holds read-lock K, then the value in aReadMark[K] is no greater than
-** the mxFrame for that reader. The value READMARK_NOT_USED (0xffffffff)
@@ -4211,12 +37073,19 @@
-** to avoid having to offset aReadMark[] indexs by one. Readers holding
-** WAL_READ_LOCK(0) always ignore the entire WAL and read all content
-** directly from the database.
--**
++** There must be no references to the page previously located at
++** pgno (which we call pPgOld) though that page is allowed to be
++** in cache. If the page previously located at pgno is not already
++** in the rollback journal, it is not put there by by this routine.
+ **
-** The value of aReadMark[K] may only be changed by a thread that
-** is holding an exclusive lock on WAL_READ_LOCK(K). Thus, the value of
-** aReadMark[K] cannot changed while there is a reader is using that mark
-** since the reader will be holding a shared lock on WAL_READ_LOCK(K).
--**
++** References to the page pPg remain valid. Updating any
++** meta-data associated with pPg (i.e. data stored in the nExtra bytes
++** allocated along with the page) is the responsibility of the caller.
+ **
-** The checkpointer may only transfer frames from WAL to database where
-** the frame numbers are less than or equal to every aReadMark[] that is
-** in use (that is, every aReadMark[j] for which there is a corresponding
@@ -4228,24 +37097,44 @@
-** will choose aReadMark[0] which has value 0 and hence such reader will
-** get all their all content directly from the database file and ignore
-** the WAL.
--**
++** A transaction must be active when this routine is called. It used to be
++** required that a statement transaction was not active, but this restriction
++** has been removed (CREATE INDEX needs to move a page when a statement
++** transaction is active).
+ **
-** Writers normally append new frames to the end of the WAL. However,
-** if nBackfill equals mxFrame (meaning that all WAL content has been
-** written back into the database) and if no readers are using the WAL
-** (in other words, if there are no WAL_READ_LOCK(i) where i>0) then
-** the writer will first "reset" the WAL back to the beginning and start
-** writing new content beginning at frame 1.
--**
++** If the fourth argument, isCommit, is non-zero, then this page is being
++** moved as part of a database reorganization just before the transaction
++** is being committed. In this case, it is guaranteed that the database page
++** pPg refers to will not be written to again within this transaction.
+ **
-** We assume that 32-bit loads are atomic and so no locks are needed in
-** order to read from any aReadMark[] entries.
--*/
++** This function may return SQLITE_NOMEM or an IO error code if an error
++** occurs. Otherwise, it returns SQLITE_OK.
+ */
-struct WalCkptInfo {
- u32 nBackfill; /* Number of WAL frames backfilled into DB */
- u32 aReadMark[WAL_NREADER]; /* Reader marks */
-};
-#define READMARK_NOT_USED 0xffffffff
--
--
++SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
++ PgHdr *pPgOld; /* The page being overwritten. */
++ Pgno needSyncPgno = 0; /* Old value of pPg->pgno, if sync is required */
++ int rc; /* Return code */
++ Pgno origPgno; /* The original page number */
+
++ assert( pPg->nRef>0 );
++ assert( pPager->eState==PAGER_WRITER_CACHEMOD
++ || pPager->eState==PAGER_WRITER_DBMOD
++ );
++ assert( assert_pager_state(pPager) );
+
-/* A block of WALINDEX_LOCK_RESERVED bytes beginning at
-** WALINDEX_LOCK_OFFSET is reserved for locks. Since some systems
-** only support mandatory file-locks, we do not read or write data
@@ -4254,14 +37143,48 @@
-#define WALINDEX_LOCK_OFFSET (sizeof(WalIndexHdr)*2 + sizeof(WalCkptInfo))
-#define WALINDEX_LOCK_RESERVED 16
-#define WALINDEX_HDR_SIZE (WALINDEX_LOCK_OFFSET+WALINDEX_LOCK_RESERVED)
--
++ /* In order to be able to rollback, an in-memory database must journal
++ ** the page we are moving from.
++ */
++ if( MEMDB ){
++ rc = sqlite3PagerWrite(pPg);
++ if( rc ) return rc;
++ }
+
-/* Size of header before each frame in wal */
-#define WAL_FRAME_HDRSIZE 24
--
++ /* If the page being moved is dirty and has not been saved by the latest
++ ** savepoint, then save the current contents of the page into the
++ ** sub-journal now. This is required to handle the following scenario:
++ **
++ ** BEGIN;
++ ** <journal page X, then modify it in memory>
++ ** SAVEPOINT one;
++ ** <Move page X to location Y>
++ ** ROLLBACK TO one;
++ **
++ ** If page X were not written to the sub-journal here, it would not
++ ** be possible to restore its contents when the "ROLLBACK TO one"
++ ** statement were is processed.
++ **
++ ** subjournalPage() may need to allocate space to store pPg->pgno into
++ ** one or more savepoint bitvecs. This is the reason this function
++ ** may return SQLITE_NOMEM.
++ */
++ if( pPg->flags&PGHDR_DIRTY
++ && subjRequiresPage(pPg)
++ && SQLITE_OK!=(rc = subjournalPage(pPg))
++ ){
++ return rc;
++ }
+
-/* Size of write ahead log header, including checksum. */
-/* #define WAL_HDRSIZE 24 */
-#define WAL_HDRSIZE 32
--
++ PAGERTRACE(("MOVE %d page %d (needSync=%d) moves to %d\n",
++ PAGERID(pPager), pPg->pgno, (pPg->flags&PGHDR_NEED_SYNC)?1:0, pgno));
++ IOTRACE(("MOVE %p %d %d\n", pPager, pPg->pgno, pgno))
+
-/* WAL magic value. Either this value, or the same value with the least
-** significant bit also set (WAL_MAGIC | 0x00000001) is stored in 32-bit
-** big-endian format in the first 4 bytes of a WAL file.
@@ -4272,7 +37195,82 @@
-** all data as 32-bit little-endian words.
-*/
-#define WAL_MAGIC 0x377f0682
--
++ /* If the journal needs to be sync()ed before page pPg->pgno can
++ ** be written to, store pPg->pgno in local variable needSyncPgno.
++ **
++ ** If the isCommit flag is set, there is no need to remember that
++ ** the journal needs to be sync()ed before database page pPg->pgno
++ ** can be written to. The caller has already promised not to write to it.
++ */
++ if( (pPg->flags&PGHDR_NEED_SYNC) && !isCommit ){
++ needSyncPgno = pPg->pgno;
++ assert( pPager->journalMode==PAGER_JOURNALMODE_OFF ||
++ pageInJournal(pPager, pPg) || pPg->pgno>pPager->dbOrigSize );
++ assert( pPg->flags&PGHDR_DIRTY );
++ }
++
++ /* If the cache contains a page with page-number pgno, remove it
++ ** from its hash chain. Also, if the PGHDR_NEED_SYNC flag was set for
++ ** page pgno before the 'move' operation, it needs to be retained
++ ** for the page moved there.
++ */
++ pPg->flags &= ~PGHDR_NEED_SYNC;
++ pPgOld = sqlite3PagerLookup(pPager, pgno);
++ assert( !pPgOld || pPgOld->nRef==1 );
++ if( pPgOld ){
++ pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC);
++ if( MEMDB ){
++ /* Do not discard pages from an in-memory database since we might
++ ** need to rollback later. Just move the page out of the way. */
++ sqlite3PcacheMove(pPgOld, pPager->dbSize+1);
++ }else{
++ sqlite3PcacheDrop(pPgOld);
++ }
++ }
++
++ origPgno = pPg->pgno;
++ sqlite3PcacheMove(pPg, pgno);
++ sqlite3PcacheMakeDirty(pPg);
++
++ /* For an in-memory database, make sure the original page continues
++ ** to exist, in case the transaction needs to roll back. Use pPgOld
++ ** as the original page since it has already been allocated.
++ */
++ if( MEMDB ){
++ assert( pPgOld );
++ sqlite3PcacheMove(pPgOld, origPgno);
++ sqlite3PagerUnrefNotNull(pPgOld);
++ }
++
++ if( needSyncPgno ){
++ /* If needSyncPgno is non-zero, then the journal file needs to be
++ ** sync()ed before any data is written to database file page needSyncPgno.
++ ** Currently, no such page exists in the page-cache and the
++ ** "is journaled" bitvec flag has been set. This needs to be remedied by
++ ** loading the page into the pager-cache and setting the PGHDR_NEED_SYNC
++ ** flag.
++ **
++ ** If the attempt to load the page into the page-cache fails, (due
++ ** to a malloc() or IO failure), clear the bit in the pInJournal[]
++ ** array. Otherwise, if the page is loaded and written again in
++ ** this transaction, it may be written to the database file before
++ ** it is synced into the journal file. This way, it may end up in
++ ** the journal file twice, but that is not a problem.
++ */
++ PgHdr *pPgHdr;
++ rc = sqlite3PagerGet(pPager, needSyncPgno, &pPgHdr);
++ if( rc!=SQLITE_OK ){
++ if( needSyncPgno<=pPager->dbOrigSize ){
++ assert( pPager->pTmpSpace!=0 );
++ sqlite3BitvecClear(pPager->pInJournal, needSyncPgno, pPager->pTmpSpace);
++ }
++ return rc;
++ }
++ pPgHdr->flags |= PGHDR_NEED_SYNC;
++ sqlite3PcacheMakeDirty(pPgHdr);
++ sqlite3PagerUnrefNotNull(pPgHdr);
++ }
+
-/*
-** Return the offset of frame iFrame in the write-ahead log file,
-** assuming a database page size of szPage bytes. The offset returned
@@ -4281,11 +37279,18 @@
-#define walFrameOffset(iFrame, szPage) ( \
- WAL_HDRSIZE + ((iFrame)-1)*(i64)((szPage)+WAL_FRAME_HDRSIZE) \
-)
--
--/*
++ return SQLITE_OK;
++}
++#endif
+
+ /*
-** An open write-ahead log file is represented by an instance of the
-** following object.
--*/
++** The page handle passed as the first argument refers to a dirty page
++** with a page number other than iNew. This function changes the page's
++** page number to iNew and sets the value of the PgHdr.flags field to
++** the value passed as the third parameter.
+ */
-struct Wal {
- sqlite3_vfs *pVfs; /* The VFS used to create pDbFd */
- sqlite3_file *pDbFd; /* File handle for the database file */
@@ -4312,40 +37317,84 @@
- u8 lockError; /* True if a locking error has occurred */
-#endif
-};
--
--/*
++SQLITE_PRIVATE void sqlite3PagerRekey(DbPage *pPg, Pgno iNew, u16 flags){
++ assert( pPg->pgno!=iNew );
++ pPg->flags = flags;
++ sqlite3PcacheMove(pPg, iNew);
++}
+
+ /*
-** Candidate values for Wal.exclusiveMode.
--*/
++** Return a pointer to the data for the specified page.
+ */
-#define WAL_NORMAL_MODE 0
-#define WAL_EXCLUSIVE_MODE 1
-#define WAL_HEAPMEMORY_MODE 2
--
--/*
++SQLITE_PRIVATE void *sqlite3PagerGetData(DbPage *pPg){
++ assert( pPg->nRef>0 || pPg->pPager->memDb );
++ return pPg->pData;
++}
+
+ /*
-** Possible values for WAL.readOnly
--*/
++** Return a pointer to the Pager.nExtra bytes of "extra" space
++** allocated along with the specified page.
+ */
-#define WAL_RDWR 0 /* Normal read/write connection */
-#define WAL_RDONLY 1 /* The WAL file is readonly */
-#define WAL_SHM_RDONLY 2 /* The SHM file is readonly */
--
--/*
++SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *pPg){
++ return pPg->pExtra;
++}
+
+ /*
-** Each page of the wal-index mapping contains a hash-table made up of
-** an array of HASHTABLE_NSLOT elements of the following type.
--*/
++** Get/set the locking-mode for this pager. Parameter eMode must be one
++** of PAGER_LOCKINGMODE_QUERY, PAGER_LOCKINGMODE_NORMAL or
++** PAGER_LOCKINGMODE_EXCLUSIVE. If the parameter is not _QUERY, then
++** the locking-mode is set to the value specified.
++**
++** The returned value is either PAGER_LOCKINGMODE_NORMAL or
++** PAGER_LOCKINGMODE_EXCLUSIVE, indicating the current (possibly updated)
++** locking-mode.
+ */
-typedef u16 ht_slot;
--
--/*
++SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *pPager, int eMode){
++ assert( eMode==PAGER_LOCKINGMODE_QUERY
++ || eMode==PAGER_LOCKINGMODE_NORMAL
++ || eMode==PAGER_LOCKINGMODE_EXCLUSIVE );
++ assert( PAGER_LOCKINGMODE_QUERY<0 );
++ assert( PAGER_LOCKINGMODE_NORMAL>=0 && PAGER_LOCKINGMODE_EXCLUSIVE>=0 );
++ assert( pPager->exclusiveMode || 0==sqlite3WalHeapMemory(pPager->pWal) );
++ if( eMode>=0 && !pPager->tempFile && !sqlite3WalHeapMemory(pPager->pWal) ){
++ pPager->exclusiveMode = (u8)eMode;
++ }
++ return (int)pPager->exclusiveMode;
++}
+
+ /*
-** This structure is used to implement an iterator that loops through
-** all frames in the WAL in database page order. Where two or more frames
-** correspond to the same database page, the iterator visits only the
-** frame most recently written to the WAL (in other words, the frame with
-** the largest index).
--**
++** Set the journal-mode for this pager. Parameter eMode must be one of:
+ **
-** The internals of this structure are only accessed by:
--**
++** PAGER_JOURNALMODE_DELETE
++** PAGER_JOURNALMODE_TRUNCATE
++** PAGER_JOURNALMODE_PERSIST
++** PAGER_JOURNALMODE_OFF
++** PAGER_JOURNALMODE_MEMORY
++** PAGER_JOURNALMODE_WAL
+ **
-** walIteratorInit() - Create a new iterator,
-** walIteratorNext() - Step an iterator,
-** walIteratorFree() - Free an iterator.
--**
++** The journalmode is set to the value specified if the change is allowed.
++** The change may be disallowed for the following reasons:
+ **
-** This functionality is used by the checkpoint code (see walCheckpoint()).
-*/
-struct WalIterator {
@@ -4364,26 +37413,38 @@
-** Define the parameters of the hash tables in the wal-index file. There
-** is a hash-table following every HASHTABLE_NPAGE page numbers in the
-** wal-index.
--**
++** * An in-memory database can only have its journal_mode set to _OFF
++** or _MEMORY.
+ **
-** Changing any of these constants will alter the wal-index format and
-** create incompatibilities.
--*/
++** * Temporary databases cannot have _WAL journalmode.
++**
++** The returned indicate the current (possibly updated) journal-mode.
+ */
-#define HASHTABLE_NPAGE 4096 /* Must be power of 2 */
-#define HASHTABLE_HASH_1 383 /* Should be prime */
-#define HASHTABLE_NSLOT (HASHTABLE_NPAGE*2) /* Must be a power of 2 */
--
++SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){
++ u8 eOld = pPager->journalMode; /* Prior journalmode */
+
-/*
-** The block of page numbers associated with the first hash-table in a
-** wal-index is smaller than usual. This is so that there is a complete
-** hash-table on each aligned 32KB page of the wal-index.
-*/
-#define HASHTABLE_NPAGE_ONE (HASHTABLE_NPAGE - (WALINDEX_HDR_SIZE/sizeof(u32)))
--
++#ifdef SQLITE_DEBUG
++ /* The print_pager_state() routine is intended to be used by the debugger
++ ** only. We invoke it once here to suppress a compiler warning. */
++ print_pager_state(pPager);
++#endif
+
-/* The wal-index is divided into pages of WALINDEX_PGSZ bytes each. */
-#define WALINDEX_PGSZ ( \
- sizeof(ht_slot)*HASHTABLE_NSLOT + HASHTABLE_NPAGE*sizeof(u32) \
-)
--
+
-/*
-** 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
@@ -4395,22 +37456,42 @@
-*/
-static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){
- int rc = SQLITE_OK;
--
++ /* The eMode parameter is always valid */
++ assert( eMode==PAGER_JOURNALMODE_DELETE
++ || eMode==PAGER_JOURNALMODE_TRUNCATE
++ || eMode==PAGER_JOURNALMODE_PERSIST
++ || eMode==PAGER_JOURNALMODE_OFF
++ || eMode==PAGER_JOURNALMODE_WAL
++ || eMode==PAGER_JOURNALMODE_MEMORY );
+
- /* Enlarge the pWal->apWiData[] array if required */
- if( pWal->nWiData<=iPage ){
- int nByte = sizeof(u32*)*(iPage+1);
- volatile u32 **apNew;
-- apNew = (volatile u32 **)sqlite3_realloc((void *)pWal->apWiData, nByte);
+- apNew = (volatile u32 **)sqlite3_realloc64((void *)pWal->apWiData, nByte);
- if( !apNew ){
- *ppPage = 0;
- return SQLITE_NOMEM;
-- }
++ /* This routine is only called from the OP_JournalMode opcode, and
++ ** the logic there will never allow a temporary file to be changed
++ ** to WAL mode.
++ */
++ assert( pPager->tempFile==0 || eMode!=PAGER_JOURNALMODE_WAL );
++
++ /* Do allow the journalmode of an in-memory database to be set to
++ ** anything other than MEMORY or OFF
++ */
++ if( MEMDB ){
++ assert( eOld==PAGER_JOURNALMODE_MEMORY || eOld==PAGER_JOURNALMODE_OFF );
++ if( eMode!=PAGER_JOURNALMODE_MEMORY && eMode!=PAGER_JOURNALMODE_OFF ){
++ eMode = eOld;
+ }
- memset((void*)&apNew[pWal->nWiData], 0,
- sizeof(u32*)*(iPage+1-pWal->nWiData));
- pWal->apWiData = apNew;
- pWal->nWiData = iPage+1;
-- }
--
+ }
+
- /* Request a pointer to the required page from the VFS */
- if( pWal->apWiData[iPage]==0 ){
- if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){
@@ -4423,36 +37504,102 @@
- if( rc==SQLITE_READONLY ){
- pWal->readOnly |= WAL_SHM_RDONLY;
- rc = SQLITE_OK;
-- }
-- }
-- }
--
++ if( eMode!=eOld ){
++
++ /* Change the journal mode. */
++ assert( pPager->eState!=PAGER_ERROR );
++ pPager->journalMode = (u8)eMode;
++
++ /* When transistioning from TRUNCATE or PERSIST to any other journal
++ ** mode except WAL, unless the pager is in locking_mode=exclusive mode,
++ ** delete the journal file.
++ */
++ assert( (PAGER_JOURNALMODE_TRUNCATE & 5)==1 );
++ assert( (PAGER_JOURNALMODE_PERSIST & 5)==1 );
++ assert( (PAGER_JOURNALMODE_DELETE & 5)==0 );
++ assert( (PAGER_JOURNALMODE_MEMORY & 5)==4 );
++ assert( (PAGER_JOURNALMODE_OFF & 5)==0 );
++ assert( (PAGER_JOURNALMODE_WAL & 5)==5 );
++
++ assert( isOpen(pPager->fd) || pPager->exclusiveMode );
++ if( !pPager->exclusiveMode && (eOld & 5)==1 && (eMode & 1)==0 ){
++
++ /* In this case we would like to delete the journal file. If it is
++ ** not possible, then that is not a problem. Deleting the journal file
++ ** here is an optimization only.
++ **
++ ** Before deleting the journal file, obtain a RESERVED lock on the
++ ** database file. This ensures that the journal file is not deleted
++ ** while it is in use by some other client.
++ */
++ sqlite3OsClose(pPager->jfd);
++ if( pPager->eLock>=RESERVED_LOCK ){
++ sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
++ }else{
++ int rc = SQLITE_OK;
++ int state = pPager->eState;
++ assert( state==PAGER_OPEN || state==PAGER_READER );
++ if( state==PAGER_OPEN ){
++ rc = sqlite3PagerSharedLock(pPager);
++ }
++ if( pPager->eState==PAGER_READER ){
++ assert( rc==SQLITE_OK );
++ rc = pagerLockDb(pPager, RESERVED_LOCK);
++ }
++ if( rc==SQLITE_OK ){
++ sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
++ }
++ if( rc==SQLITE_OK && state==PAGER_READER ){
++ pagerUnlockDb(pPager, SHARED_LOCK);
++ }else if( state==PAGER_OPEN ){
++ pager_unlock(pPager);
++ }
++ assert( state==pPager->eState );
+ }
++ }else if( eMode==PAGER_JOURNALMODE_OFF ){
++ sqlite3OsClose(pPager->jfd);
+ }
+ }
+
- *ppPage = pWal->apWiData[iPage];
- assert( iPage==0 || *ppPage || rc!=SQLITE_OK );
- return rc;
--}
--
--/*
++ /* Return the new journal mode */
++ return (int)pPager->journalMode;
+ }
+
+ /*
-** Return a pointer to the WalCkptInfo structure in the wal-index.
--*/
++** Return the current journal mode.
+ */
-static volatile WalCkptInfo *walCkptInfo(Wal *pWal){
- assert( pWal->nWiData>0 && pWal->apWiData[0] );
- return (volatile WalCkptInfo*)&(pWal->apWiData[0][sizeof(WalIndexHdr)/2]);
--}
--
--/*
++SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager *pPager){
++ return (int)pPager->journalMode;
+ }
+
+ /*
-** Return a pointer to the WalIndexHdr structure in the wal-index.
--*/
++** Return TRUE if the pager is in a state where it is OK to change the
++** journalmode. Journalmode changes can only happen when the database
++** is unmodified.
+ */
-static volatile WalIndexHdr *walIndexHdr(Wal *pWal){
- assert( pWal->nWiData>0 && pWal->apWiData[0] );
- return (volatile WalIndexHdr*)pWal->apWiData[0];
--}
--
--/*
++SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager *pPager){
++ assert( assert_pager_state(pPager) );
++ if( pPager->eState>=PAGER_WRITER_CACHEMOD ) return 0;
++ if( NEVER(isOpen(pPager->jfd) && pPager->journalOff>0) ) return 0;
++ return 1;
+ }
+
+ /*
-** The argument to this macro must be of type u32. On a little-endian
-** architecture, it returns the u32 value that results from interpreting
-** the 4 bytes as a big-endian value. On a big-endian architecture, it
--** returns the value that would be produced by intepreting the 4 bytes
+-** returns the value that would be produced by interpreting the 4 bytes
-** of the input value as a little-endian integer.
-*/
-#define BYTESWAP32(x) ( \
@@ -4466,9 +37613,12 @@
-** initial values of 0 and 0 if aIn==NULL).
-**
-** The checksum is written back into aOut[] before returning.
--**
++** Get/set the size-limit used for persistent journal files.
+ **
-** nByte must be a positive multiple of 8.
--*/
++** Setting the size limit to -1 means no limit is enforced.
++** An attempt to set a limit smaller than -1 is a no-op.
+ */
-static void walChecksumBytes(
- int nativeCksum, /* True for native byte-order, false for non-native */
- u8 *a, /* Content to be checksummed */
@@ -4510,14 +37660,23 @@
-static void walShmBarrier(Wal *pWal){
- if( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE ){
- sqlite3OsShmBarrier(pWal->pDbFd);
-- }
--}
--
--/*
++SQLITE_PRIVATE i64 sqlite3PagerJournalSizeLimit(Pager *pPager, i64 iLimit){
++ if( iLimit>=-1 ){
++ pPager->journalSizeLimit = iLimit;
++ sqlite3WalLimit(pPager->pWal, iLimit);
+ }
++ return pPager->journalSizeLimit;
+ }
+
+ /*
-** Write the header information in pWal->hdr into the wal-index.
-**
-** The checksum on pWal->hdr is updated before it is written.
--*/
++** Return a pointer to the pPager->pBackup variable. The backup module
++** in backup.c maintains the content of this variable. This module
++** uses it opaquely as an argument to sqlite3BackupRestart() and
++** sqlite3BackupUpdate() only.
+ */
-static void walIndexWriteHdr(Wal *pWal){
- volatile WalIndexHdr *aHdr = walIndexHdr(pWal);
- const int nCksum = offsetof(WalIndexHdr, aCksum);
@@ -4529,9 +37688,12 @@
- memcpy((void *)&aHdr[1], (void *)&pWal->hdr, sizeof(WalIndexHdr));
- walShmBarrier(pWal);
- memcpy((void *)&aHdr[0], (void *)&pWal->hdr, sizeof(WalIndexHdr));
--}
--
--/*
++SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager *pPager){
++ return &pPager->pBackup;
+ }
+
++#ifndef SQLITE_OMIT_VACUUM
+ /*
-** This function encodes a single frame header and writes it to a buffer
-** supplied by the caller. A frame-header is made up of a series of
-** 4-byte big-endian integers, as follows:
@@ -4543,7 +37705,8 @@
-** 12: Salt-2 (copied from the wal-header)
-** 16: Checksum-1.
-** 20: Checksum-2.
--*/
++** Unless this is an in-memory or temporary database, clear the pager cache.
+ */
-static void walEncodeFrame(
- Wal *pWal, /* The write-ahead log */
- u32 iPage, /* Database page number for frame */
@@ -4564,13 +37727,22 @@
-
- sqlite3Put4byte(&aFrame[16], aCksum[0]);
- sqlite3Put4byte(&aFrame[20], aCksum[1]);
--}
--
--/*
++SQLITE_PRIVATE void sqlite3PagerClearCache(Pager *pPager){
++ if( !MEMDB && pPager->tempFile==0 ) pager_reset(pPager);
+ }
++#endif
+
++#ifndef SQLITE_OMIT_WAL
+ /*
-** Check to see if the frame with header in aFrame[] and content
-** in aData[] is valid. If it is a valid frame, fill *piPage and
-** *pnTruncate and return true. Return if the frame is not valid.
--*/
++** This function is called when the user invokes "PRAGMA wal_checkpoint",
++** "PRAGMA wal_blocking_checkpoint" or calls the sqlite3_wal_checkpoint()
++** or wal_blocking_checkpoint() API functions.
++**
++** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART.
+ */
-static int walDecodeFrame(
- Wal *pWal, /* The write-ahead log */
- u32 *piPage, /* OUT: Database page number for frame */
@@ -4610,7 +37782,16 @@
- ){
- /* Checksum failed. */
- return 0;
-- }
++SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, int eMode, int *pnLog, int *pnCkpt){
++ int rc = SQLITE_OK;
++ if( pPager->pWal ){
++ rc = sqlite3WalCheckpoint(pPager->pWal, eMode,
++ (eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler),
++ pPager->pBusyHandlerArg,
++ pPager->ckptSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
++ pnLog, pnCkpt
++ );
+ }
-
- /* If we reach this point, the frame is valid. Return the page number
- ** and the new database size.
@@ -4618,26 +37799,15 @@
- *piPage = pgno;
- *pnTruncate = sqlite3Get4byte(&aFrame[4]);
- return 1;
--}
-+** slots in the hash table and so the first reader will get an answer as
-+** if no values greater than K0 had ever been inserted into the hash table
-+** in the first place - which is what reader one wants. Meanwhile, the
-+** second reader using K1 will see additional values that were inserted
-+** later, which is exactly what reader two wants.
-+**
-+** When a rollback occurs, the value of K is decreased. Hash table entries
-+** that correspond to frames greater than the new K value are removed
-+** from the hash table at this point.
-+*/
-+#ifndef SQLITE_OMIT_WAL
-
++ return rc;
+ }
+-
-#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
- /*
+-/*
-** Names of locks. This routine is used to provide debugging output and is not
-** a part of an ordinary build.
-+** Trace output macros
- */
+-*/
-static const char *walLockName(int lockIdx){
- if( lockIdx==WAL_WRITE_LOCK ){
- return "WRITE-LOCK";
@@ -4651,32 +37821,20 @@
- lockIdx-WAL_READ_LOCK(0));
- return zName;
- }
--}
++SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager){
++ return sqlite3WalCallback(pPager->pWal);
+ }
-#endif /*defined(SQLITE_TEST) || defined(SQLITE_DEBUG) */
-
-+#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
-+SQLITE_PRIVATE int sqlite3WalTrace = 0;
-+# define WALTRACE(X) if(sqlite3WalTrace) sqlite3DebugPrintf X
-+#else
-+# define WALTRACE(X)
-+#endif
/*
-** Set or release locks on the WAL. Locks are either shared or exclusive.
-** A lock cannot be moved directly between shared and exclusive - it must go
-** through the unlocked state first.
-+** The maximum (and only) versions of the wal and wal-index formats
-+** that may be interpreted by this version of SQLite.
- **
+-**
-** In locking_mode=EXCLUSIVE, all of these routines become no-ops.
-+** If a client begins recovering a WAL file and finds that (a) the checksum
-+** values in the wal-header are correct and (b) the version field is not
-+** WAL_MAX_VERSION, recovery fails and SQLite returns SQLITE_CANTOPEN.
-+**
-+** Similarly, if a client successfully reads a wal-index header (i.e. the
-+** checksum test is successful) and finds that the version field is not
-+** WALINDEX_MAX_VERSION, then no read-transaction is opened and SQLite
-+** returns SQLITE_CANTOPEN.
++** Return true if the underlying VFS for the given pager supports the
++** primitives necessary for write-ahead logging.
*/
-static int walLockShared(Wal *pWal, int lockIdx){
- int rc;
@@ -4693,17 +37851,37 @@
- (void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1,
- SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED);
- WALTRACE(("WAL%p: release SHARED-%s\n", pWal, walLockName(lockIdx)));
--}
--static int walLockExclusive(Wal *pWal, int lockIdx, int n){
++SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager){
++ const sqlite3_io_methods *pMethods = pPager->fd->pMethods;
++ return pPager->exclusiveMode || (pMethods->iVersion>=2 && pMethods->xShmMap);
+ }
+-static int walLockExclusive(Wal *pWal, int lockIdx, int n, int fBlock){
- int rc;
- if( pWal->exclusiveMode ) return SQLITE_OK;
+- if( fBlock ) sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_WAL_BLOCK, 0);
- rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
- SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE);
- 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!=SQLITE_BUSY); )
-- return rc;
--}
++
++/*
++** Attempt to take an exclusive lock on the database file. If a PENDING lock
++** is obtained instead, immediately release it.
++*/
++static int pagerExclusiveLock(Pager *pPager){
++ int rc; /* Return code */
++
++ assert( pPager->eLock==SHARED_LOCK || pPager->eLock==EXCLUSIVE_LOCK );
++ rc = pagerLockDb(pPager, EXCLUSIVE_LOCK);
++ if( rc!=SQLITE_OK ){
++ /* If the attempt to grab the exclusive lock failed, release the
++ ** pending lock that may have been obtained instead. */
++ pagerUnlockDb(pPager, SHARED_LOCK);
++ }
++
+ return rc;
+ }
-static void walUnlockExclusive(Wal *pWal, int lockIdx, int n){
- if( pWal->exclusiveMode ) return;
- (void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
@@ -4711,14 +37889,16 @@
- WALTRACE(("WAL%p: release EXCLUSIVE-%s cnt=%d\n", pWal,
- walLockName(lockIdx), n));
-}
-+#define WAL_MAX_VERSION 3007000
-+#define WALINDEX_MAX_VERSION 3007000
/*
-** Compute a hash on a page number. The resulting hash value must land
-** between 0 and (HASHTABLE_NSLOT-1). The walHashNext() function advances
-** the hash to the next value in the event of a collision.
--*/
++** Call sqlite3WalOpen() to open the WAL handle. If the pager is in
++** exclusive-locking mode when this function is called, take an EXCLUSIVE
++** lock on the database file and use heap-memory to store the wal-index
++** in. Otherwise, use the normal shared-memory.
+ */
-static int walHash(u32 iPage){
- assert( iPage>0 );
- assert( (HASHTABLE_NSLOT & (HASHTABLE_NSLOT-1))==0 );
@@ -4726,23 +37906,61 @@
-}
-static int walNextHash(int iPriorHash){
- return (iPriorHash+1)&(HASHTABLE_NSLOT-1);
--}
--
++static int pagerOpenWal(Pager *pPager){
++ int rc = SQLITE_OK;
++
++ assert( pPager->pWal==0 && pPager->tempFile==0 );
++ assert( pPager->eLock==SHARED_LOCK || pPager->eLock==EXCLUSIVE_LOCK );
++
++ /* If the pager is already in exclusive-mode, the WAL module will use
++ ** heap-memory for the wal-index instead of the VFS shared-memory
++ ** implementation. Take the exclusive lock now, before opening the WAL
++ ** file, to make sure this is safe.
++ */
++ if( pPager->exclusiveMode ){
++ rc = pagerExclusiveLock(pPager);
++ }
++
++ /* Open the connection to the log file. If this operation fails,
++ ** (e.g. due to malloc() failure), return an error code.
++ */
++ if( rc==SQLITE_OK ){
++ rc = sqlite3WalOpen(pPager->pVfs,
++ pPager->fd, pPager->zWal, pPager->exclusiveMode,
++ pPager->journalSizeLimit, &pPager->pWal
++ );
++ }
++ pagerFixMaplimit(pPager);
++
++ return rc;
+ }
+
-/*
-** Return pointers to the hash table and page number array stored on
-** page iHash of the wal-index. The wal-index is broken into 32KB pages
-** numbered starting from 0.
--**
++
++/*
++** The caller must be holding a SHARED lock on the database file to call
++** this function.
+ **
-** Set output variable *paHash to point to the start of the hash table
-** in the wal-index file. Set *piZero to one less than the frame
-** number of the first frame indexed by this hash table. If a
-** slot in the hash table is set to N, it refers to frame number
-** (*piZero+N) in the log.
--**
++** If the pager passed as the first argument is open on a real database
++** file (not a temp file or an in-memory database), and the WAL file
++** is not already open, make an attempt to open it now. If successful,
++** return SQLITE_OK. If an error occurs or the VFS used by the pager does
++** not support the xShmXXX() methods, return an error code. *pbOpen is
++** not modified in either case.
+ **
-** Finally, set *paPgno so that *paPgno[1] is the page number of the
-** first frame indexed by the hash table, frame (*piZero+1).
-+** Indices of various locking bytes. WAL_NREADER is the number
-+** of available reader locks and should be at least 3.
++** If the pager is open on a temp-file (or in-memory database), or if
++** the WAL file is already open, set *pbOpen to 1 and return SQLITE_OK
++** without doing anything.
*/
-static int walHashGet(
- Wal *pWal, /* WAL handle */
@@ -4750,22 +37968,27 @@
- volatile ht_slot **paHash, /* OUT: Pointer to hash index */
- volatile u32 **paPgno, /* OUT: Pointer to page number array */
- u32 *piZero /* OUT: Frame associated with *paPgno[0] */
--){
++SQLITE_PRIVATE int sqlite3PagerOpenWal(
++ Pager *pPager, /* Pager object */
++ int *pbOpen /* OUT: Set to true if call is a no-op */
+ ){
- int rc; /* Return code */
- volatile u32 *aPgno;
--
++ int rc = SQLITE_OK; /* Return code */
+
- rc = walIndexPage(pWal, iHash, &aPgno);
- assert( rc==SQLITE_OK || iHash>0 );
-+#define WAL_WRITE_LOCK 0
-+#define WAL_ALL_BUT_WRITE 1
-+#define WAL_CKPT_LOCK 1
-+#define WAL_RECOVER_LOCK 2
-+#define WAL_READ_LOCK(I) (3+(I))
-+#define WAL_NREADER (SQLITE_SHM_NLOCK-3)
++ assert( assert_pager_state(pPager) );
++ assert( pPager->eState==PAGER_OPEN || pbOpen );
++ assert( pPager->eState==PAGER_READER || !pbOpen );
++ assert( pbOpen==0 || *pbOpen==0 );
++ assert( pbOpen!=0 || (!pPager->tempFile && !pPager->pWal) );
- if( rc==SQLITE_OK ){
- u32 iZero;
- volatile ht_slot *aHash;
++ if( !pPager->tempFile && !pPager->pWal ){
++ if( !sqlite3PagerWalSupported(pPager) ) return SQLITE_CANTOPEN;
- aHash = (volatile ht_slot *)&aPgno[HASHTABLE_NPAGE];
- if( iHash==0 ){
@@ -4773,25 +37996,38 @@
- iZero = 0;
- }else{
- iZero = HASHTABLE_NPAGE_ONE + (iHash-1)*HASHTABLE_NPAGE;
-- }
++ /* Close any rollback journal previously open */
++ sqlite3OsClose(pPager->jfd);
++
++ rc = pagerOpenWal(pPager);
++ if( rc==SQLITE_OK ){
++ pPager->journalMode = PAGER_JOURNALMODE_WAL;
++ pPager->eState = PAGER_OPEN;
+ }
-
- *paPgno = &aPgno[-1];
- *paHash = aHash;
- *piZero = iZero;
-- }
-- return rc;
--}
-+/* Object declarations */
-+typedef struct WalIndexHdr WalIndexHdr;
-+typedef struct WalIterator WalIterator;
-+typedef struct WalCkptInfo WalCkptInfo;
++ }else{
++ *pbOpen = 1;
+ }
++
+ return rc;
+ }
--/*
+ /*
-** Return the number of the wal-index page that contains the hash-table
-** and page-number array that contain entries corresponding to WAL frame
-** iFrame. The wal-index is broken up into 32KB pages. Wal-index pages
-** are numbered starting from 0.
--*/
++** This function is called to close the connection to the log file prior
++** to switching from WAL to rollback mode.
++**
++** Before closing the log file, this function attempts to take an
++** EXCLUSIVE lock on the database file. If this cannot be obtained, an
++** error (SQLITE_BUSY) is returned and the log connection is not closed.
++** If successful, the EXCLUSIVE lock is not released before returning.
+ */
-static int walFramePage(u32 iFrame){
- int iHash = (iFrame+HASHTABLE_NPAGE-HASHTABLE_NPAGE_ONE-1) / HASHTABLE_NPAGE;
- assert( (iHash==0 || iFrame>HASHTABLE_NPAGE_ONE)
@@ -4802,95 +38038,70 @@
- );
- return iHash;
-}
++SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager){
++ int rc = SQLITE_OK;
- /*
+-/*
-** Return the page number associated with frame iFrame in this WAL.
-+** The following object holds a copy of the wal-index header content.
-+**
-+** The actual header in the wal-index consists of two copies of this
-+** object.
-+**
-+** The szPage value can be any power of 2 between 512 and 32768, inclusive.
-+** Or it can be 1 to represent a 65536-byte page. The latter case was
-+** added in 3.7.1 when support for 64K pages was added.
- */
+-*/
-static u32 walFramePgno(Wal *pWal, u32 iFrame){
- int iHash = walFramePage(iFrame);
- if( iHash==0 ){
- return pWal->apWiData[0][WALINDEX_HDR_SIZE/sizeof(u32) + iFrame - 1];
-- }
++ assert( pPager->journalMode==PAGER_JOURNALMODE_WAL );
++
++ /* If the log file is not already open, but does exist in the file-system,
++ ** it may need to be checkpointed before the connection can switch to
++ ** rollback mode. Open it now so this can happen.
++ */
++ if( !pPager->pWal ){
++ int logexists = 0;
++ rc = pagerLockDb(pPager, SHARED_LOCK);
++ if( rc==SQLITE_OK ){
++ rc = sqlite3OsAccess(
++ pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &logexists
++ );
++ }
++ if( rc==SQLITE_OK && logexists ){
++ rc = pagerOpenWal(pPager);
++ }
+ }
- return pWal->apWiData[iHash][(iFrame-1-HASHTABLE_NPAGE_ONE)%HASHTABLE_NPAGE];
--}
-+struct WalIndexHdr {
-+ u32 iVersion; /* Wal-index version */
-+ u32 unused; /* Unused (padding) field */
-+ u32 iChange; /* Counter incremented each transaction */
-+ u8 isInit; /* 1 when initialized */
-+ u8 bigEndCksum; /* True if checksums in WAL are big-endian */
-+ u16 szPage; /* Database page size in bytes. 1==64K */
-+ u32 mxFrame; /* Index of last valid frame in the WAL */
-+ u32 nPage; /* Size of database in pages */
-+ u32 aFrameCksum[2]; /* Checksum of last frame in log */
-+ u32 aSalt[2]; /* Two salt values copied from WAL header */
-+ u32 aCksum[2]; /* Checksum over all prior fields */
-+};
++
++ /* Checkpoint and close the log. Because an EXCLUSIVE lock is held on
++ ** the database file, the log and log-summary files will be deleted.
++ */
++ if( rc==SQLITE_OK && pPager->pWal ){
++ rc = pagerExclusiveLock(pPager);
++ if( rc==SQLITE_OK ){
++ rc = sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags,
++ pPager->pageSize, (u8*)pPager->pTmpSpace);
++ pPager->pWal = 0;
++ pagerFixMaplimit(pPager);
++ }
++ }
++ return rc;
+ }
++#endif /* !SQLITE_OMIT_WAL */
++
++#ifdef SQLITE_ENABLE_ZIPVFS
/*
-** Remove entries from the hash table that point to WAL slots greater
-** than pWal->hdr.mxFrame.
-+** A copy of the following object occurs in the wal-index immediately
-+** following the second copy of the WalIndexHdr. This object stores
-+** information used by checkpoint.
- **
+-**
-** This function is called whenever pWal->hdr.mxFrame is decreased due
-** to a rollback or savepoint.
-+** nBackfill is the number of frames in the WAL that have been written
-+** back into the database. (We call the act of moving content from WAL to
-+** database "backfilling".) The nBackfill number is never greater than
-+** WalIndexHdr.mxFrame. nBackfill can only be increased by threads
-+** holding the WAL_CKPT_LOCK lock (which includes a recovery thread).
-+** However, a WAL_WRITE_LOCK thread can move the value of nBackfill from
-+** mxFrame back to zero when the WAL is reset.
- **
+-**
-** At most only the hash table containing pWal->hdr.mxFrame needs to be
-** updated. Any later hash tables will be automatically cleared when
-** pWal->hdr.mxFrame advances to the point where those hash tables are
-** actually needed.
-+** There is one entry in aReadMark[] for each reader lock. If a reader
-+** holds read-lock K, then the value in aReadMark[K] is no greater than
-+** the mxFrame for that reader. The value READMARK_NOT_USED (0xffffffff)
-+** for any aReadMark[] means that entry is unused. aReadMark[0] is
-+** a special case; its value is never used and it exists as a place-holder
-+** to avoid having to offset aReadMark[] indexs by one. Readers holding
-+** WAL_READ_LOCK(0) always ignore the entire WAL and read all content
-+** directly from the database.
-+**
-+** The value of aReadMark[K] may only be changed by a thread that
-+** is holding an exclusive lock on WAL_READ_LOCK(K). Thus, the value of
-+** aReadMark[K] cannot changed while there is a reader is using that mark
-+** since the reader will be holding a shared lock on WAL_READ_LOCK(K).
-+**
-+** The checkpointer may only transfer frames from WAL to database where
-+** the frame numbers are less than or equal to every aReadMark[] that is
-+** in use (that is, every aReadMark[j] for which there is a corresponding
-+** WAL_READ_LOCK(j)). New readers (usually) pick the aReadMark[] with the
-+** largest value and will increase an unused aReadMark[] to mxFrame if there
-+** is not already an aReadMark[] equal to mxFrame. The exception to the
-+** previous sentence is when nBackfill equals mxFrame (meaning that everything
-+** in the WAL has been backfilled into the database) then new readers
-+** will choose aReadMark[0] which has value 0 and hence such reader will
-+** get all their all content directly from the database file and ignore
-+** the WAL.
-+**
-+** Writers normally append new frames to the end of the WAL. However,
-+** if nBackfill equals mxFrame (meaning that all WAL content has been
-+** written back into the database) and if no readers are using the WAL
-+** (in other words, if there are no WAL_READ_LOCK(i) where i>0) then
-+** the writer will first "reset" the WAL back to the beginning and start
-+** writing new content beginning at frame 1.
-+**
-+** We assume that 32-bit loads are atomic and so no locks are needed in
-+** order to read from any aReadMark[] entries.
++** A read-lock must be held on the pager when this function is called. If
++** the pager is in WAL mode and the WAL file currently contains one or more
++** frames, return the size in bytes of the page images stored within the
++** WAL frames. Otherwise, if this is not a WAL database or the WAL file
++** is empty, return 0.
*/
-static void walCleanupHash(Wal *pWal){
- volatile ht_slot *aHash = 0; /* Pointer to hash table to clear */
@@ -4899,11 +38110,11 @@
- int iLimit = 0; /* Zero values greater than this */
- int nByte; /* Number of bytes to zero in aPgno[] */
- int i; /* Used to iterate through aHash[] */
-+struct WalCkptInfo {
-+ u32 nBackfill; /* Number of WAL frames backfilled into DB */
-+ u32 aReadMark[WAL_NREADER]; /* Reader marks */
-+};
-+#define READMARK_NOT_USED 0xffffffff
++SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
++ assert( pPager->eState>=PAGER_READER );
++ return sqlite3WalFramesize(pPager->pWal);
++}
++#endif
- assert( pWal->writeLock );
- testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE-1 );
@@ -4911,14 +38122,7 @@
- testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE+1 );
- if( pWal->hdr.mxFrame==0 ) return;
-+/* A block of WALINDEX_LOCK_RESERVED bytes beginning at
-+** WALINDEX_LOCK_OFFSET is reserved for locks. Since some systems
-+** only support mandatory file-locks, we do not read or write data
-+** from the region of the file on which locks are applied.
-+*/
-+#define WALINDEX_LOCK_OFFSET (sizeof(WalIndexHdr)*2 + sizeof(WalCkptInfo))
-+#define WALINDEX_LOCK_RESERVED 16
-+#define WALINDEX_HDR_SIZE (WALINDEX_LOCK_OFFSET+WALINDEX_LOCK_RESERVED)
++#endif /* SQLITE_OMIT_DISKIO */
- /* Obtain pointers to the hash-table and page-number array containing
- ** the entry that corresponds to frame pWal->hdr.mxFrame. It is guaranteed
@@ -4927,8 +38131,11 @@
- assert( pWal->nWiData>walFramePage(pWal->hdr.mxFrame) );
- assert( pWal->apWiData[walFramePage(pWal->hdr.mxFrame)] );
- walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &aHash, &aPgno, &iZero);
-+/* Size of header before each frame in wal */
-+#define WAL_FRAME_HDRSIZE 24
++/* BEGIN SQLCIPHER */
++#ifdef SQLITE_HAS_CODEC
++SQLITE_PRIVATE void sqlite3pager_get_codec(Pager *pPager, void **ctx) {
++ *ctx = pPager->pCodec;
++}
- /* Zero all hash-table entries that correspond to frame numbers greater
- ** than pWal->hdr.mxFrame.
@@ -4946,9 +38153,9 @@
- */
- nByte = (int)((char *)aHash - (char *)&aPgno[iLimit+1]);
- memset((void *)&aPgno[iLimit+1], 0, nByte);
-+/* Size of write ahead log header, including checksum. */
-+/* #define WAL_HDRSIZE 24 */
-+#define WAL_HDRSIZE 32
++SQLITE_PRIVATE int sqlite3pager_is_mj_pgno(Pager *pPager, Pgno pgno) {
++ return (PAGER_MJ_PGNO(pPager) == pgno) ? 1 : 0;
++}
-#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
- /* Verify that the every entry in the mapping region is still reachable
@@ -4965,73 +38172,288 @@
- }
- }
-#endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */
--}
-+/* WAL magic value. Either this value, or the same value with the least
-+** significant bit also set (WAL_MAGIC | 0x00000001) is stored in 32-bit
-+** big-endian format in the first 4 bytes of a WAL file.
-+**
-+** If the LSB is set, then the checksums for each frame within the WAL
-+** file are calculated by treating all data as an array of 32-bit
-+** big-endian words. Otherwise, they are calculated by interpreting
-+** all data as 32-bit little-endian words.
-+*/
-+#define WAL_MAGIC 0x377f0682
++SQLITE_PRIVATE sqlite3_file *sqlite3Pager_get_fd(Pager *pPager) {
++ return (isOpen(pPager->fd)) ? pPager->fd : NULL;
++}
++
++SQLITE_PRIVATE void sqlite3pager_sqlite3PagerSetCodec(
++ Pager *pPager,
++ void *(*xCodec)(void*,void*,Pgno,int),
++ void (*xCodecSizeChng)(void*,int,int),
++ void (*xCodecFree)(void*),
++ void *pCodec
++){
++ sqlite3PagerSetCodec(pPager, xCodec, xCodecSizeChng, xCodecFree, pCodec);
++}
++
++SQLITE_PRIVATE void sqlite3pager_sqlite3PagerSetError( Pager *pPager, int error) {
++ pPager->errCode = error;
+ }
++#endif
++/* END SQLCIPHER */
++
++
++/************** End of pager.c ***********************************************/
++/************** Begin file wal.c *********************************************/
+/*
-+** Return the offset of frame iFrame in the write-ahead log file,
-+** assuming a database page size of szPage bytes. The offset returned
-+** is to the start of the write-ahead log frame-header.
++** 2010 February 1
++**
++** The author disclaims copyright to this source code. In place of
++** a legal notice, here is a blessing:
++**
++** May you do good and not evil.
++** May you find forgiveness for yourself and forgive others.
++** May you share freely, never taking more than you give.
++**
++*************************************************************************
++**
++** This file contains the implementation of a write-ahead log (WAL) used in
++** "journal_mode=WAL" mode.
++**
++** WRITE-AHEAD LOG (WAL) FILE FORMAT
++**
++** A WAL file consists of a header followed by zero or more "frames".
++** Each frame records the revised content of a single page from the
++** database file. All changes to the database are recorded by writing
++** frames into the WAL. Transactions commit when a frame is written that
++** contains a commit marker. A single WAL can and usually does record
++** multiple transactions. Periodically, the content of the WAL is
++** transferred back into the database file in an operation called a
++** "checkpoint".
++**
++** A single WAL file can be used multiple times. In other words, the
++** WAL can fill up with frames and then be checkpointed and then new
++** frames can overwrite the old ones. A WAL always grows from beginning
++** toward the end. Checksums and counters attached to each frame are
++** used to determine which frames within the WAL are valid and which
++** are leftovers from prior checkpoints.
++**
++** The WAL header is 32 bytes in size and consists of the following eight
++** big-endian 32-bit unsigned integer values:
++**
++** 0: Magic number. 0x377f0682 or 0x377f0683
++** 4: File format version. Currently 3007000
++** 8: Database page size. Example: 1024
++** 12: Checkpoint sequence number
++** 16: Salt-1, random integer incremented with each checkpoint
++** 20: Salt-2, a different random integer changing with each ckpt
++** 24: Checksum-1 (first part of checksum for first 24 bytes of header).
++** 28: Checksum-2 (second part of checksum for first 24 bytes of header).
++**
++** Immediately following the wal-header are zero or more frames. Each
++** frame consists of a 24-byte frame-header followed by a <page-size> bytes
++** of page data. The frame-header is six big-endian 32-bit unsigned
++** integer values, as follows:
++**
++** 0: Page number.
++** 4: For commit records, the size of the database image in pages
++** after the commit. For all other records, zero.
++** 8: Salt-1 (copied from the header)
++** 12: Salt-2 (copied from the header)
++** 16: Checksum-1.
++** 20: Checksum-2.
++**
++** A frame is considered valid if and only if the following conditions are
++** true:
++**
++** (1) The salt-1 and salt-2 values in the frame-header match
++** salt values in the wal-header
++**
++** (2) The checksum values in the final 8 bytes of the frame-header
++** exactly match the checksum computed consecutively on the
++** WAL header and the first 8 bytes and the content of all frames
++** up to and including the current frame.
++**
++** The checksum is computed using 32-bit big-endian integers if the
++** magic number in the first 4 bytes of the WAL is 0x377f0683 and it
++** is computed using little-endian if the magic number is 0x377f0682.
++** The checksum values are always stored in the frame header in a
++** big-endian format regardless of which byte order is used to compute
++** the checksum. The checksum is computed by interpreting the input as
++** an even number of unsigned 32-bit integers: x[0] through x[N]. The
++** algorithm used for the checksum is as follows:
++**
++** for i from 0 to n-1 step 2:
++** s0 += x[i] + s1;
++** s1 += x[i+1] + s0;
++** endfor
++**
++** Note that s0 and s1 are both weighted checksums using fibonacci weights
++** in reverse order (the largest fibonacci weight occurs on the first element
++** of the sequence being summed.) The s1 value spans all 32-bit
++** terms of the sequence whereas s0 omits the final term.
++**
++** On a checkpoint, the WAL is first VFS.xSync-ed, then valid content of the
++** WAL is transferred into the database, then the database is VFS.xSync-ed.
++** The VFS.xSync operations serve as write barriers - all writes launched
++** before the xSync must complete before any write that launches after the
++** xSync begins.
++**
++** After each checkpoint, the salt-1 value is incremented and the salt-2
++** value is randomized. This prevents old and new frames in the WAL from
++** being considered valid at the same time and being checkpointing together
++** following a crash.
++**
++** READER ALGORITHM
++**
++** To read a page from the database (call it page number P), a reader
++** first checks the WAL to see if it contains page P. If so, then the
++** last valid instance of page P that is a followed by a commit frame
++** or is a commit frame itself becomes the value read. If the WAL
++** contains no copies of page P that are valid and which are a commit
++** frame or are followed by a commit frame, then page P is read from
++** the database file.
++**
++** To start a read transaction, the reader records the index of the last
++** valid frame in the WAL. The reader uses this recorded "mxFrame" value
++** for all subsequent read operations. New transactions can be appended
++** to the WAL, but as long as the reader uses its original mxFrame value
++** and ignores the newly appended content, it will see a consistent snapshot
++** of the database from a single point in time. This technique allows
++** multiple concurrent readers to view different versions of the database
++** content simultaneously.
++**
++** The reader algorithm in the previous paragraphs works correctly, but
++** because frames for page P can appear anywhere within the WAL, the
++** reader has to scan the entire WAL looking for page P frames. If the
++** WAL is large (multiple megabytes is typical) that scan can be slow,
++** and read performance suffers. To overcome this problem, a separate
++** data structure called the wal-index is maintained to expedite the
++** search for frames of a particular page.
++**
++** WAL-INDEX FORMAT
++**
++** Conceptually, the wal-index is shared memory, though VFS implementations
++** might choose to implement the wal-index using a mmapped file. Because
++** the wal-index is shared memory, SQLite does not support journal_mode=WAL
++** on a network filesystem. All users of the database must be able to
++** share memory.
++**
++** The wal-index is transient. After a crash, the wal-index can (and should
++** be) reconstructed from the original WAL file. In fact, the VFS is required
++** to either truncate or zero the header of the wal-index when the last
++** connection to it closes. Because the wal-index is transient, it can
++** use an architecture-specific format; it does not have to be cross-platform.
++** Hence, unlike the database and WAL file formats which store all values
++** as big endian, the wal-index can store multi-byte values in the native
++** byte order of the host computer.
++**
++** The purpose of the wal-index is to answer this question quickly: Given
++** a page number P and a maximum frame index M, return the index of the
++** last frame in the wal before frame M for page P in the WAL, or return
++** NULL if there are no frames for page P in the WAL prior to M.
++**
++** The wal-index consists of a header region, followed by an one or
++** more index blocks.
++**
++** The wal-index header contains the total number of frames within the WAL
++** in the mxFrame field.
++**
++** Each index block except for the first contains information on
++** HASHTABLE_NPAGE frames. The first index block contains information on
++** HASHTABLE_NPAGE_ONE frames. The values of HASHTABLE_NPAGE_ONE and
++** HASHTABLE_NPAGE are selected so that together the wal-index header and
++** first index block are the same size as all other index blocks in the
++** wal-index.
++**
++** Each index block contains two sections, a page-mapping that contains the
++** database page number associated with each wal frame, and a hash-table
++** that allows readers to query an index block for a specific page number.
++** The page-mapping is an array of HASHTABLE_NPAGE (or HASHTABLE_NPAGE_ONE
++** for the first index block) 32-bit page numbers. The first entry in the
++** first index-block contains the database page number corresponding to the
++** first frame in the WAL file. The first entry in the second index block
++** in the WAL file corresponds to the (HASHTABLE_NPAGE_ONE+1)th frame in
++** the log, and so on.
++**
++** The last index block in a wal-index usually contains less than the full
++** complement of HASHTABLE_NPAGE (or HASHTABLE_NPAGE_ONE) page-numbers,
++** depending on the contents of the WAL file. This does not change the
++** allocated size of the page-mapping array - the page-mapping array merely
++** contains unused entries.
++**
++** Even without using the hash table, the last frame for page P
++** can be found by scanning the page-mapping sections of each index block
++** starting with the last index block and moving toward the first, and
++** within each index block, starting at the end and moving toward the
++** beginning. The first entry that equals P corresponds to the frame
++** holding the content for that page.
++**
++** The hash table consists of HASHTABLE_NSLOT 16-bit unsigned integers.
++** HASHTABLE_NSLOT = 2*HASHTABLE_NPAGE, and there is one entry in the
++** hash table for each page number in the mapping section, so the hash
++** table is never more than half full. The expected number of collisions
++** prior to finding a match is 1. Each entry of the hash table is an
++** 1-based index of an entry in the mapping section of the same
++** index block. Let K be the 1-based index of the largest entry in
++** the mapping section. (For index blocks other than the last, K will
++** always be exactly HASHTABLE_NPAGE (4096) and for the last index block
++** K will be (mxFrame%HASHTABLE_NPAGE).) Unused slots of the hash table
++** contain a value of 0.
++**
++** To look for page P in the hash table, first compute a hash iKey on
++** P as follows:
++**
++** iKey = (P * 383) % HASHTABLE_NSLOT
++**
++** Then start scanning entries of the hash table, starting with iKey
++** (wrapping around to the beginning when the end of the hash table is
++** reached) until an unused hash slot is found. Let the first unused slot
++** be at index iUnused. (iUnused might be less than iKey if there was
++** wrap-around.) Because the hash table is never more than half full,
++** the search is guaranteed to eventually hit an unused entry. Let
++** iMax be the value between iKey and iUnused, closest to iUnused,
++** where aHash[iMax]==P. If there is no iMax entry (if there exists
++** no hash slot such that aHash[i]==p) then page P is not in the
++** current index block. Otherwise the iMax-th mapping entry of the
++** current index block corresponds to the last entry that references
++** page P.
++**
++** A hash search begins with the last index block and moves toward the
++** first index block, looking for entries corresponding to page P. On
++** average, only two or three slots in each index block need to be
++** examined in order to either find the last entry for page P, or to
++** establish that no such entry exists in the block. Each index block
++** holds over 4000 entries. So two or three index blocks are sufficient
++** to cover a typical 10 megabyte WAL file, assuming 1K pages. 8 or 10
++** comparisons (on average) suffice to either locate a frame in the
++** WAL or to establish that the frame does not exist in the WAL. This
++** is much faster than scanning the entire 10MB WAL.
++**
++** Note that entries are added in order of increasing K. Hence, one
++** reader might be using some value K0 and a second reader that started
++** at a later time (after additional transactions were added to the WAL
++** and to the wal-index) might be using a different value K1, where K1>K0.
++** Both readers can use the same hash table and mapping section to get
++** the correct result. There may be entries in the hash table with
++** K>K0 but to the first reader, those entries will appear to be unused
++** slots in the hash table and so the first reader will get an answer as
++** if no values greater than K0 had ever been inserted into the hash table
++** in the first place - which is what reader one wants. Meanwhile, the
++** second reader using K1 will see additional values that were inserted
++** later, which is exactly what reader two wants.
++**
++** When a rollback occurs, the value of K is decreased. Hash table entries
++** that correspond to frames greater than the new K value are removed
++** from the hash table at this point.
+*/
-+#define walFrameOffset(iFrame, szPage) ( \
-+ WAL_HDRSIZE + ((iFrame)-1)*(i64)((szPage)+WAL_FRAME_HDRSIZE) \
-+)
++#ifndef SQLITE_OMIT_WAL
++
/*
-** Set an entry in the wal-index that will map database page number
-** pPage into WAL frame iFrame.
-+** An open write-ahead log file is represented by an instance of the
-+** following object.
++** Trace output macros
*/
-static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
- int rc; /* Return code */
- u32 iZero = 0; /* One less than frame number of aPgno[1] */
- volatile u32 *aPgno = 0; /* Page number array */
- volatile ht_slot *aHash = 0; /* Hash table */
-+struct Wal {
-+ sqlite3_vfs *pVfs; /* The VFS used to create pDbFd */
-+ sqlite3_file *pDbFd; /* File handle for the database file */
-+ sqlite3_file *pWalFd; /* File handle for WAL file */
-+ u32 iCallback; /* Value to pass to log callback (or 0) */
-+ i64 mxWalSize; /* Truncate WAL to this size upon reset */
-+ int nWiData; /* Size of array apWiData */
-+ int szFirstBlock; /* Size of first block written to WAL file */
-+ volatile u32 **apWiData; /* Pointer to wal-index content in memory */
-+ u32 szPage; /* Database page size */
-+ i16 readLock; /* Which read lock is being held. -1 for none */
-+ u8 syncFlags; /* Flags to use to sync header writes */
-+ u8 exclusiveMode; /* Non-zero if connection is in exclusive mode */
-+ u8 writeLock; /* True if in a write transaction */
-+ u8 ckptLock; /* True if holding a checkpoint lock */
-+ u8 readOnly; /* WAL_RDWR, WAL_RDONLY, or WAL_SHM_RDONLY */
-+ u8 truncateOnCommit; /* True to truncate WAL file on commit */
-+ u8 syncHeader; /* Fsync the WAL header if true */
-+ u8 padToSectorBoundary; /* Pad transactions out to the next sector */
-+ WalIndexHdr hdr; /* Wal-index header for current transaction */
-+ const char *zWalName; /* Name of WAL file */
-+ u32 nCkpt; /* Checkpoint sequence counter in the wal-header */
-+#ifdef SQLITE_DEBUG
-+ u8 lockError; /* True if a locking error has occurred */
-+#endif
-+};
-
+-
- rc = walHashGet(pWal, walFramePage(iFrame), &aHash, &aPgno, &iZero);
-+/*
-+** Candidate values for Wal.exclusiveMode.
-+*/
-+#define WAL_NORMAL_MODE 0
-+#define WAL_EXCLUSIVE_MODE 1
-+#define WAL_HEAPMEMORY_MODE 2
-
+-
- /* Assuming the wal-index file was successfully mapped, populate the
- ** page number array and hash table entry.
- */
@@ -5039,29 +38461,18 @@
- int iKey; /* Hash table key */
- int idx; /* Value to write to hash-table slot */
- int nCollide; /* Number of hash collisions */
-+/*
-+** Possible values for WAL.readOnly
-+*/
-+#define WAL_RDWR 0 /* Normal read/write connection */
-+#define WAL_RDONLY 1 /* The WAL file is readonly */
-+#define WAL_SHM_RDONLY 2 /* The SHM file is readonly */
-
+-
- idx = iFrame - iZero;
- assert( idx <= HASHTABLE_NSLOT/2 + 1 );
-
- /* If this is the first entry to be added to this hash-table, zero the
-- ** entire hash table and aPgno[] array before proceding.
+- ** entire hash table and aPgno[] array before proceeding.
- */
- if( idx==1 ){
- int nByte = (int)((u8 *)&aHash[HASHTABLE_NSLOT] - (u8 *)&aPgno[1]);
- memset((void*)&aPgno[1], 0, nByte);
- }
-+/*
-+** Each page of the wal-index mapping contains a hash-table made up of
-+** an array of HASHTABLE_NSLOT elements of the following type.
-+*/
-+typedef u16 ht_slot;
-
+-
- /* If the entry in aPgno[] is already set, then the previous writer
- ** must have exited unexpectedly in the middle of a transaction (after
- ** writing one or more dirty pages to the WAL to free up memory).
@@ -5072,33 +38483,7 @@
- walCleanupHash(pWal);
- assert( !aPgno[idx] );
- }
-+/*
-+** This structure is used to implement an iterator that loops through
-+** all frames in the WAL in database page order. Where two or more frames
-+** correspond to the same database page, the iterator visits only the
-+** frame most recently written to the WAL (in other words, the frame with
-+** the largest index).
-+**
-+** The internals of this structure are only accessed by:
-+**
-+** walIteratorInit() - Create a new iterator,
-+** walIteratorNext() - Step an iterator,
-+** walIteratorFree() - Free an iterator.
-+**
-+** This functionality is used by the checkpoint code (see walCheckpoint()).
-+*/
-+struct WalIterator {
-+ int iPrior; /* Last result returned from the iterator */
-+ int nSegment; /* Number of entries in aSegment[] */
-+ struct WalSegment {
-+ int iNext; /* Next slot in aIndex[] not yet returned */
-+ ht_slot *aIndex; /* i0, i1, i2... such that aPgno[iN] ascend */
-+ u32 *aPgno; /* Array of page numbers. */
-+ int nEntry; /* Nr. of entries in aPgno[] and aIndex[] */
-+ int iZero; /* Frame number associated with aPgno[0] */
-+ } aSegment[1]; /* One for every 32KB page in the wal-index */
-+};
-
+-
- /* Write the aPgno[] array entry and the hash-table slot. */
- nCollide = idx;
- for(iKey=walHash(iPage); aHash[iKey]; iKey=walNextHash(iKey)){
@@ -5106,18 +38491,7 @@
- }
- aPgno[idx] = iPage;
- aHash[iKey] = (ht_slot)idx;
-+/*
-+** Define the parameters of the hash tables in the wal-index file. There
-+** is a hash-table following every HASHTABLE_NPAGE page numbers in the
-+** wal-index.
-+**
-+** Changing any of these constants will alter the wal-index format and
-+** create incompatibilities.
-+*/
-+#define HASHTABLE_NPAGE 4096 /* Must be power of 2 */
-+#define HASHTABLE_HASH_1 383 /* Should be prime */
-+#define HASHTABLE_NSLOT (HASHTABLE_NPAGE*2) /* Must be a power of 2 */
-
+-
-#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
- /* Verify that the number of entries in the hash table exactly equals
- ** the number of entries in the mapping region.
@@ -5128,13 +38502,7 @@
- for(i=0; i<HASHTABLE_NSLOT; i++){ if( aHash[i] ) nEntry++; }
- assert( nEntry==idx );
- }
-+/*
-+** The block of page numbers associated with the first hash-table in a
-+** wal-index is smaller than usual. This is so that there is a complete
-+** hash-table on each aligned 32KB page of the wal-index.
-+*/
-+#define HASHTABLE_NPAGE_ONE (HASHTABLE_NPAGE - (WALINDEX_HDR_SIZE/sizeof(u32)))
-
+-
- /* Verify that the every entry in the mapping region is reachable
- ** via the hash table. This turns out to be a really, really expensive
- ** thing to check, so only do this occasionally - not on every
@@ -5148,78 +38516,40 @@
- }
- assert( aHash[iKey]==i );
- }
-+/* The wal-index is divided into pages of WALINDEX_PGSZ bytes each. */
-+#define WALINDEX_PGSZ ( \
-+ sizeof(ht_slot)*HASHTABLE_NSLOT + HASHTABLE_NPAGE*sizeof(u32) \
-+)
-+
-+/*
-+** 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
-+** numbered from zero.
-+**
-+** If this call is successful, *ppPage is set to point to the wal-index
-+** page and SQLITE_OK is returned. If an error (an OOM or VFS error) occurs,
-+** then an SQLite error code is returned and *ppPage is set to 0.
-+*/
-+static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){
-+ int rc = SQLITE_OK;
-+
-+ /* Enlarge the pWal->apWiData[] array if required */
-+ if( pWal->nWiData<=iPage ){
-+ int nByte = sizeof(u32*)*(iPage+1);
-+ volatile u32 **apNew;
-+ apNew = (volatile u32 **)sqlite3_realloc((void *)pWal->apWiData, nByte);
-+ if( !apNew ){
-+ *ppPage = 0;
-+ return SQLITE_NOMEM;
- }
+- }
-#endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */
-+ memset((void*)&apNew[pWal->nWiData], 0,
-+ sizeof(u32*)*(iPage+1-pWal->nWiData));
-+ pWal->apWiData = apNew;
-+ pWal->nWiData = iPage+1;
- }
-
-+ /* Request a pointer to the required page from the VFS */
-+ if( pWal->apWiData[iPage]==0 ){
-+ if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){
-+ pWal->apWiData[iPage] = (u32 volatile *)sqlite3MallocZero(WALINDEX_PGSZ);
-+ if( !pWal->apWiData[iPage] ) rc = SQLITE_NOMEM;
-+ }else{
-+ rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ,
-+ pWal->writeLock, (void volatile **)&pWal->apWiData[iPage]
-+ );
-+ if( rc==SQLITE_READONLY ){
-+ pWal->readOnly |= WAL_SHM_RDONLY;
-+ rc = SQLITE_OK;
-+ }
-+ }
-+ }
-
-+ *ppPage = pWal->apWiData[iPage];
-+ assert( iPage==0 || *ppPage || rc!=SQLITE_OK );
- return rc;
- }
-
-+/*
-+** Return a pointer to the WalCkptInfo structure in the wal-index.
-+*/
-+static volatile WalCkptInfo *walCkptInfo(Wal *pWal){
-+ assert( pWal->nWiData>0 && pWal->apWiData[0] );
-+ return (volatile WalCkptInfo*)&(pWal->apWiData[0][sizeof(WalIndexHdr)/2]);
-+}
+- }
+-
+-
+- return rc;
+-}
+-
++#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
++SQLITE_PRIVATE int sqlite3WalTrace = 0;
++# define WALTRACE(X) if(sqlite3WalTrace) sqlite3DebugPrintf X
++#else
++# define WALTRACE(X)
++#endif
/*
-** Recover the wal-index by reading the write-ahead log file.
--**
++** The maximum (and only) versions of the wal and wal-index formats
++** that may be interpreted by this version of SQLite.
+ **
-** This routine first tries to establish an exclusive lock on the
-** wal-index to prevent other threads/processes from doing anything
-** with the WAL or wal-index while recovery is running. The
-** WAL_RECOVER_LOCK is also held so that other threads will know
-** that this thread is running recovery. If unable to establish
-** the necessary locks, this routine returns SQLITE_BUSY.
-+** Return a pointer to the WalIndexHdr structure in the wal-index.
++** If a client begins recovering a WAL file and finds that (a) the checksum
++** values in the wal-header are correct and (b) the version field is not
++** WAL_MAX_VERSION, recovery fails and SQLite returns SQLITE_CANTOPEN.
++**
++** Similarly, if a client successfully reads a wal-index header (i.e. the
++** checksum test is successful) and finds that the version field is not
++** WALINDEX_MAX_VERSION, then no read-transaction is opened and SQLite
++** returns SQLITE_CANTOPEN.
*/
-static int walIndexRecover(Wal *pWal){
- int rc; /* Return Code */
@@ -5227,11 +38557,7 @@
- u32 aFrameCksum[2] = {0, 0};
- int iLock; /* Lock offset to lock for checkpoint */
- int nLock; /* Number of locks to hold */
-+static volatile WalIndexHdr *walIndexHdr(Wal *pWal){
-+ assert( pWal->nWiData>0 && pWal->apWiData[0] );
-+ return (volatile WalIndexHdr*)pWal->apWiData[0];
-+}
-
+-
- /* Obtain an exclusive lock on all byte in the locking range not already
- ** locked by the caller. The caller is guaranteed to have locked the
- ** WAL_WRITE_LOCK byte, and may have also locked the WAL_CKPT_LOCK byte.
@@ -5244,54 +38570,19 @@
- assert( pWal->writeLock );
- iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock;
- nLock = SQLITE_SHM_NLOCK - iLock;
-- rc = walLockExclusive(pWal, iLock, nLock);
+- rc = walLockExclusive(pWal, iLock, nLock, 0);
- if( rc ){
- return rc;
- }
- WALTRACE(("WAL%p: recovery begin...\n", pWal));
-+/*
-+** The argument to this macro must be of type u32. On a little-endian
-+** architecture, it returns the u32 value that results from interpreting
-+** the 4 bytes as a big-endian value. On a big-endian architecture, it
-+** returns the value that would be produced by intepreting the 4 bytes
-+** of the input value as a little-endian integer.
-+*/
-+#define BYTESWAP32(x) ( \
-+ (((x)&0x000000FF)<<24) + (((x)&0x0000FF00)<<8) \
-+ + (((x)&0x00FF0000)>>8) + (((x)&0xFF000000)>>24) \
-+)
-
+-
- memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
-+/*
-+** Generate or extend an 8 byte checksum based on the data in
-+** array aByte[] and the initial values of aIn[0] and aIn[1] (or
-+** initial values of 0 and 0 if aIn==NULL).
-+**
-+** The checksum is written back into aOut[] before returning.
-+**
-+** nByte must be a positive multiple of 8.
-+*/
-+static void walChecksumBytes(
-+ int nativeCksum, /* True for native byte-order, false for non-native */
-+ u8 *a, /* Content to be checksummed */
-+ int nByte, /* Bytes of content in a[]. Must be a multiple of 8. */
-+ const u32 *aIn, /* Initial checksum value input */
-+ u32 *aOut /* OUT: Final checksum value output */
-+){
-+ u32 s1, s2;
-+ u32 *aData = (u32 *)a;
-+ u32 *aEnd = (u32 *)&a[nByte];
-
+-
- rc = sqlite3OsFileSize(pWal->pWalFd, &nSize);
- if( rc!=SQLITE_OK ){
- goto recovery_error;
-+ if( aIn ){
-+ s1 = aIn[0];
-+ s2 = aIn[1];
-+ }else{
-+ s1 = s2 = 0;
- }
-
+- }
+-
- if( nSize>WAL_HDRSIZE ){
- u8 aBuf[WAL_HDRSIZE]; /* Buffer to load WAL header into */
- u8 *aFrame = 0; /* Malloc'd buffer to load entire frame */
@@ -5349,7 +38640,7 @@
-
- /* Malloc a buffer to read frames into. */
- szFrame = szPage + WAL_FRAME_HDRSIZE;
-- aFrame = (u8 *)sqlite3_malloc(szFrame);
+- aFrame = (u8 *)sqlite3_malloc64(szFrame);
- if( !aFrame ){
- rc = SQLITE_NOMEM;
- goto recovery_error;
@@ -5382,22 +38673,11 @@
- aFrameCksum[1] = pWal->hdr.aFrameCksum[1];
- }
- }
-+ assert( nByte>=8 );
-+ assert( (nByte&0x00000007)==0 );
-
+-
- sqlite3_free(aFrame);
-+ if( nativeCksum ){
-+ do {
-+ s1 += *aData++ + s2;
-+ s2 += *aData++ + s1;
-+ }while( aData<aEnd );
-+ }else{
-+ do {
-+ s1 += BYTESWAP32(aData[0]) + s2;
-+ s2 += BYTESWAP32(aData[1]) + s1;
-+ aData += 2;
-+ }while( aData<aEnd );
- }
+- }
++#define WAL_MAX_VERSION 3007000
++#define WALINDEX_MAX_VERSION 3007000
-finished:
- if( rc==SQLITE_OK ){
@@ -5406,7 +38686,17 @@
- pWal->hdr.aFrameCksum[0] = aFrameCksum[0];
- pWal->hdr.aFrameCksum[1] = aFrameCksum[1];
- walIndexWriteHdr(pWal);
--
++/*
++** Indices of various locking bytes. WAL_NREADER is the number
++** of available reader locks and should be at least 3.
++*/
++#define WAL_WRITE_LOCK 0
++#define WAL_ALL_BUT_WRITE 1
++#define WAL_CKPT_LOCK 1
++#define WAL_RECOVER_LOCK 2
++#define WAL_READ_LOCK(I) (3+(I))
++#define WAL_NREADER (SQLITE_SHM_NLOCK-3)
+
- /* Reset the checkpoint-header. This is safe because this thread is
- ** currently holding locks that exclude all other readers, writers and
- ** checkpointers.
@@ -5416,9 +38706,6 @@
- pInfo->aReadMark[0] = 0;
- for(i=1; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
- if( pWal->hdr.mxFrame ) pInfo->aReadMark[1] = pWal->hdr.mxFrame;
-+ aOut[0] = s1;
-+ aOut[1] = s2;
-+}
- /* If more than one frame was recovered from the log file, report an
- ** event via sqlite3_log(). This is to help with identifying performance
@@ -5431,22 +38718,28 @@
- pWal->hdr.mxFrame, pWal->zWalName
- );
- }
-+static void walShmBarrier(Wal *pWal){
-+ if( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE ){
-+ sqlite3OsShmBarrier(pWal->pDbFd);
- }
--
+- }
++/* Object declarations */
++typedef struct WalIndexHdr WalIndexHdr;
++typedef struct WalIterator WalIterator;
++typedef struct WalCkptInfo WalCkptInfo;
+
-recovery_error:
- WALTRACE(("WAL%p: recovery %s\n", pWal, rc ? "failed" : "ok"));
- walUnlockExclusive(pWal, iLock, nLock);
- return rc;
- }
+-}
/*
-** Close an open wal-index.
-+** Write the header information in pWal->hdr into the wal-index.
++** The following object holds a copy of the wal-index header content.
+**
-+** The checksum on pWal->hdr is updated before it is written.
++** The actual header in the wal-index consists of two copies of this
++** object.
++**
++** The szPage value can be any power of 2 between 512 and 32768, inclusive.
++** Or it can be 1 to represent a 65536-byte page. The latter case was
++** added in 3.7.1 when support for 64K pages was added.
*/
-static void walIndexClose(Wal *pWal, int isDelete){
- if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){
@@ -5458,44 +38751,81 @@
- }else{
- sqlite3OsShmUnmap(pWal->pDbFd, isDelete);
- }
-+static void walIndexWriteHdr(Wal *pWal){
-+ volatile WalIndexHdr *aHdr = walIndexHdr(pWal);
-+ const int nCksum = offsetof(WalIndexHdr, aCksum);
-+
-+ assert( pWal->writeLock );
-+ pWal->hdr.isInit = 1;
-+ pWal->hdr.iVersion = WALINDEX_MAX_VERSION;
-+ walChecksumBytes(1, (u8*)&pWal->hdr, nCksum, 0, pWal->hdr.aCksum);
-+ memcpy((void *)&aHdr[1], (void *)&pWal->hdr, sizeof(WalIndexHdr));
-+ walShmBarrier(pWal);
-+ memcpy((void *)&aHdr[0], (void *)&pWal->hdr, sizeof(WalIndexHdr));
- }
+-}
++struct WalIndexHdr {
++ u32 iVersion; /* Wal-index version */
++ u32 unused; /* Unused (padding) field */
++ u32 iChange; /* Counter incremented each transaction */
++ u8 isInit; /* 1 when initialized */
++ u8 bigEndCksum; /* True if checksums in WAL are big-endian */
++ u16 szPage; /* Database page size in bytes. 1==64K */
++ u32 mxFrame; /* Index of last valid frame in the WAL */
++ u32 nPage; /* Size of database in pages */
++ u32 aFrameCksum[2]; /* Checksum of last frame in log */
++ u32 aSalt[2]; /* Two salt values copied from WAL header */
++ u32 aCksum[2]; /* Checksum over all prior fields */
++};
-/*
-** Open a connection to the WAL file zWalName. The database file must
-** already be opened on connection pDbFd. The buffer that zWalName points
-** to must remain valid for the lifetime of the returned Wal* handle.
--**
++/*
++** A copy of the following object occurs in the wal-index immediately
++** following the second copy of the WalIndexHdr. This object stores
++** information used by checkpoint.
+ **
-** A SHARED lock should be held on the database file when this function
-** is called. The purpose of this SHARED lock is to prevent any other
-** client from unlinking the WAL or wal-index file. If another process
-** were to do this just after this client opened one of these files, the
-** system would be badly broken.
-+/*
-+** This function encodes a single frame header and writes it to a buffer
-+** supplied by the caller. A frame-header is made up of a series of
-+** 4-byte big-endian integers, as follows:
++** nBackfill is the number of frames in the WAL that have been written
++** back into the database. (We call the act of moving content from WAL to
++** database "backfilling".) The nBackfill number is never greater than
++** WalIndexHdr.mxFrame. nBackfill can only be increased by threads
++** holding the WAL_CKPT_LOCK lock (which includes a recovery thread).
++** However, a WAL_WRITE_LOCK thread can move the value of nBackfill from
++** mxFrame back to zero when the WAL is reset.
**
-** If the log file is successfully opened, SQLITE_OK is returned and
-** *ppWal is set to point to a new WAL handle. If an error occurs,
-** an SQLite error code is returned and *ppWal is left unmodified.
-+** 0: Page number.
-+** 4: For commit records, the size of the database image in pages
-+** after the commit. For all other records, zero.
-+** 8: Salt-1 (copied from the wal-header)
-+** 12: Salt-2 (copied from the wal-header)
-+** 16: Checksum-1.
-+** 20: Checksum-2.
++** There is one entry in aReadMark[] for each reader lock. If a reader
++** holds read-lock K, then the value in aReadMark[K] is no greater than
++** the mxFrame for that reader. The value READMARK_NOT_USED (0xffffffff)
++** for any aReadMark[] means that entry is unused. aReadMark[0] is
++** a special case; its value is never used and it exists as a place-holder
++** to avoid having to offset aReadMark[] indexs by one. Readers holding
++** WAL_READ_LOCK(0) always ignore the entire WAL and read all content
++** directly from the database.
++**
++** The value of aReadMark[K] may only be changed by a thread that
++** is holding an exclusive lock on WAL_READ_LOCK(K). Thus, the value of
++** aReadMark[K] cannot changed while there is a reader is using that mark
++** since the reader will be holding a shared lock on WAL_READ_LOCK(K).
++**
++** The checkpointer may only transfer frames from WAL to database where
++** the frame numbers are less than or equal to every aReadMark[] that is
++** in use (that is, every aReadMark[j] for which there is a corresponding
++** WAL_READ_LOCK(j)). New readers (usually) pick the aReadMark[] with the
++** largest value and will increase an unused aReadMark[] to mxFrame if there
++** is not already an aReadMark[] equal to mxFrame. The exception to the
++** previous sentence is when nBackfill equals mxFrame (meaning that everything
++** in the WAL has been backfilled into the database) then new readers
++** will choose aReadMark[0] which has value 0 and hence such reader will
++** get all their all content directly from the database file and ignore
++** the WAL.
++**
++** Writers normally append new frames to the end of the WAL. However,
++** if nBackfill equals mxFrame (meaning that all WAL content has been
++** written back into the database) and if no readers are using the WAL
++** (in other words, if there are no WAL_READ_LOCK(i) where i>0) then
++** the writer will first "reset" the WAL back to the beginning and start
++** writing new content beginning at frame 1.
++**
++** We assume that 32-bit loads are atomic and so no locks are needed in
++** order to read from any aReadMark[] entries.
*/
-SQLITE_PRIVATE int sqlite3WalOpen(
- sqlite3_vfs *pVfs, /* vfs module to open wal and wal-index */
@@ -5504,28 +38834,18 @@
- int bNoShm, /* True to run in heap-memory mode */
- i64 mxWalSize, /* Truncate WAL to this size on reset */
- Wal **ppWal /* OUT: Allocated Wal handle */
-+static void walEncodeFrame(
-+ Wal *pWal, /* The write-ahead log */
-+ u32 iPage, /* Database page number for frame */
-+ u32 nTruncate, /* New db size (or 0 for non-commit frames) */
-+ u8 *aData, /* Pointer to page data */
-+ u8 *aFrame /* OUT: Write encoded frame here */
- ){
+-){
- int rc; /* Return Code */
- Wal *pRet; /* Object to allocate and return */
- int flags; /* Flags passed to OsOpen() */
-+ int nativeCksum; /* True for native byte-order checksums */
-+ u32 *aCksum = pWal->hdr.aFrameCksum;
-+ assert( WAL_FRAME_HDRSIZE==24 );
-+ sqlite3Put4byte(&aFrame[0], iPage);
-+ sqlite3Put4byte(&aFrame[4], nTruncate);
-+ memcpy(&aFrame[8], pWal->hdr.aSalt, 8);
-
+-
- assert( zWalName && zWalName[0] );
- assert( pDbFd );
-+ nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN);
-+ walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum);
-+ walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum);
++struct WalCkptInfo {
++ u32 nBackfill; /* Number of WAL frames backfilled into DB */
++ u32 aReadMark[WAL_NREADER]; /* Reader marks */
++};
++#define READMARK_NOT_USED 0xffffffff
- /* In the amalgamation, the os_unix.c and os_win.c source files come before
- ** this source file. Verify that the #defines of the locking byte offsets
@@ -5537,38 +38857,24 @@
-#ifdef UNIX_SHM_BASE
- assert( UNIX_SHM_BASE==WALINDEX_LOCK_OFFSET );
-#endif
-+ sqlite3Put4byte(&aFrame[16], aCksum[0]);
-+ sqlite3Put4byte(&aFrame[20], aCksum[1]);
-+}
-+/*
-+** Check to see if the frame with header in aFrame[] and content
-+** in aData[] is valid. If it is a valid frame, fill *piPage and
-+** *pnTruncate and return true. Return if the frame is not valid.
++/* A block of WALINDEX_LOCK_RESERVED bytes beginning at
++** WALINDEX_LOCK_OFFSET is reserved for locks. Since some systems
++** only support mandatory file-locks, we do not read or write data
++** from the region of the file on which locks are applied.
+*/
-+static int walDecodeFrame(
-+ Wal *pWal, /* The write-ahead log */
-+ u32 *piPage, /* OUT: Database page number for frame */
-+ u32 *pnTruncate, /* OUT: New db size (or 0 if not commit) */
-+ u8 *aData, /* Pointer to page data (for checksum) */
-+ u8 *aFrame /* Frame data */
-+){
-+ int nativeCksum; /* True for native byte-order checksums */
-+ u32 *aCksum = pWal->hdr.aFrameCksum;
-+ u32 pgno; /* Page number of the frame */
-+ assert( WAL_FRAME_HDRSIZE==24 );
++#define WALINDEX_LOCK_OFFSET (sizeof(WalIndexHdr)*2 + sizeof(WalCkptInfo))
++#define WALINDEX_LOCK_RESERVED 16
++#define WALINDEX_HDR_SIZE (WALINDEX_LOCK_OFFSET+WALINDEX_LOCK_RESERVED)
- /* Allocate an instance of struct Wal to return. */
- *ppWal = 0;
- pRet = (Wal*)sqlite3MallocZero(sizeof(Wal) + pVfs->szOsFile);
- if( !pRet ){
- return SQLITE_NOMEM;
-+ /* A frame is only valid if the salt values in the frame-header
-+ ** match the salt values in the wal-header.
-+ */
-+ if( memcmp(&pWal->hdr.aSalt, &aFrame[8], 8)!=0 ){
-+ return 0;
- }
+- }
++/* Size of header before each frame in wal */
++#define WAL_FRAME_HDRSIZE 24
- pRet->pVfs = pVfs;
- pRet->pWalFd = (sqlite3_file *)&pRet[1];
@@ -5579,18 +38885,26 @@
- pRet->syncHeader = 1;
- pRet->padToSectorBoundary = 1;
- pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE);
--
++/* Size of write ahead log header, including checksum. */
++/* #define WAL_HDRSIZE 24 */
++#define WAL_HDRSIZE 32
+
- /* Open file handle on the write-ahead log file. */
- flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL);
- rc = sqlite3OsOpen(pVfs, zWalName, pRet->pWalFd, flags, &flags);
- if( rc==SQLITE_OK && flags&SQLITE_OPEN_READONLY ){
- pRet->readOnly = WAL_RDONLY;
-+ /* A frame is only valid if the page number is creater than zero.
-+ */
-+ pgno = sqlite3Get4byte(&aFrame[0]);
-+ if( pgno==0 ){
-+ return 0;
- }
+- }
++/* WAL magic value. Either this value, or the same value with the least
++** significant bit also set (WAL_MAGIC | 0x00000001) is stored in 32-bit
++** big-endian format in the first 4 bytes of a WAL file.
++**
++** If the LSB is set, then the checksums for each frame within the WAL
++** file are calculated by treating all data as an array of 32-bit
++** big-endian words. Otherwise, they are calculated by interpreting
++** all data as 32-bit little-endian words.
++*/
++#define WAL_MAGIC 0x377f0682
- if( rc!=SQLITE_OK ){
- walIndexClose(pRet, 0);
@@ -5604,55 +38918,52 @@
- }
- *ppWal = pRet;
- WALTRACE(("WAL%d: opened\n", pRet));
-+ /* A frame is only valid if a checksum of the WAL header,
-+ ** all prior frams, the first 16 bytes of this frame-header,
-+ ** and the frame-data matches the checksum in the last 8
-+ ** bytes of this frame-header.
-+ */
-+ nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN);
-+ walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum);
-+ walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum);
-+ if( aCksum[0]!=sqlite3Get4byte(&aFrame[16])
-+ || aCksum[1]!=sqlite3Get4byte(&aFrame[20])
-+ ){
-+ /* Checksum failed. */
-+ return 0;
- }
+- }
- return rc;
-+
-+ /* If we reach this point, the frame is valid. Return the page number
-+ ** and the new database size.
-+ */
-+ *piPage = pgno;
-+ *pnTruncate = sqlite3Get4byte(&aFrame[4]);
-+ return 1;
- }
+-}
++/*
++** Return the offset of frame iFrame in the write-ahead log file,
++** assuming a database page size of szPage bytes. The offset returned
++** is to the start of the write-ahead log frame-header.
++*/
++#define walFrameOffset(iFrame, szPage) ( \
++ WAL_HDRSIZE + ((iFrame)-1)*(i64)((szPage)+WAL_FRAME_HDRSIZE) \
++)
-+
-+#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
/*
-** Change the size to which the WAL file is trucated on each reset.
-+** Names of locks. This routine is used to provide debugging output and is not
-+** a part of an ordinary build.
++** An open write-ahead log file is represented by an instance of the
++** following object.
*/
-SQLITE_PRIVATE void sqlite3WalLimit(Wal *pWal, i64 iLimit){
- if( pWal ) pWal->mxWalSize = iLimit;
-+static const char *walLockName(int lockIdx){
-+ if( lockIdx==WAL_WRITE_LOCK ){
-+ return "WRITE-LOCK";
-+ }else if( lockIdx==WAL_CKPT_LOCK ){
-+ return "CKPT-LOCK";
-+ }else if( lockIdx==WAL_RECOVER_LOCK ){
-+ return "RECOVER-LOCK";
-+ }else{
-+ static char zName[15];
-+ sqlite3_snprintf(sizeof(zName), zName, "READ-LOCK[%d]",
-+ lockIdx-WAL_READ_LOCK(0));
-+ return zName;
-+ }
- }
-+#endif /*defined(SQLITE_TEST) || defined(SQLITE_DEBUG) */
-+
+-}
++struct Wal {
++ sqlite3_vfs *pVfs; /* The VFS used to create pDbFd */
++ sqlite3_file *pDbFd; /* File handle for the database file */
++ sqlite3_file *pWalFd; /* File handle for WAL file */
++ u32 iCallback; /* Value to pass to log callback (or 0) */
++ i64 mxWalSize; /* Truncate WAL to this size upon reset */
++ int nWiData; /* Size of array apWiData */
++ int szFirstBlock; /* Size of first block written to WAL file */
++ volatile u32 **apWiData; /* Pointer to wal-index content in memory */
++ u32 szPage; /* Database page size */
++ i16 readLock; /* Which read lock is being held. -1 for none */
++ u8 syncFlags; /* Flags to use to sync header writes */
++ u8 exclusiveMode; /* Non-zero if connection is in exclusive mode */
++ u8 writeLock; /* True if in a write transaction */
++ u8 ckptLock; /* True if holding a checkpoint lock */
++ u8 readOnly; /* WAL_RDWR, WAL_RDONLY, or WAL_SHM_RDONLY */
++ u8 truncateOnCommit; /* True to truncate WAL file on commit */
++ u8 syncHeader; /* Fsync the WAL header if true */
++ u8 padToSectorBoundary; /* Pad transactions out to the next sector */
++ WalIndexHdr hdr; /* Wal-index header for current transaction */
++ const char *zWalName; /* Name of WAL file */
++ u32 nCkpt; /* Checkpoint sequence counter in the wal-header */
++#ifdef SQLITE_DEBUG
++ u8 lockError; /* True if a locking error has occurred */
++#endif
++};
/*
-** Find the smallest page number out of all pages held in the WAL that
@@ -5660,13 +38971,10 @@
-** same WalIterator object. Write into *piFrame the frame index where
-** that page was last written into the WAL. Write into *piPage the page
-** number.
-+** Set or release locks on the WAL. Locks are either shared or exclusive.
-+** A lock cannot be moved directly between shared and exclusive - it must go
-+** through the unlocked state first.
- **
+-**
-** Return 0 on success. If there are no pages in the WAL with a page
-** number larger than *piPage, then return 1.
-+** In locking_mode=EXCLUSIVE, all of these routines become no-ops.
++** Candidate values for Wal.exclusiveMode.
*/
-static int walIteratorNext(
- WalIterator *p, /* Iterator */
@@ -5676,7 +38984,10 @@
- u32 iMin; /* Result pgno must be greater than iMin */
- u32 iRet = 0xFFFFFFFF; /* 0xffffffff is never a valid page number */
- int i; /* For looping through segments */
--
++#define WAL_NORMAL_MODE 0
++#define WAL_EXCLUSIVE_MODE 1
++#define WAL_HEAPMEMORY_MODE 2
+
- iMin = p->iPrior;
- assert( iMin<0xffffffff );
- for(i=p->nSegment-1; i>=0; i--){
@@ -5693,42 +39004,21 @@
- pSegment->iNext++;
- }
- }
--
++/*
++** Possible values for WAL.readOnly
++*/
++#define WAL_RDWR 0 /* Normal read/write connection */
++#define WAL_RDONLY 1 /* The WAL file is readonly */
++#define WAL_SHM_RDONLY 2 /* The SHM file is readonly */
+
- *piPage = p->iPrior = iRet;
- return (iRet==0xFFFFFFFF);
-+static int walLockShared(Wal *pWal, int lockIdx){
-+ int rc;
-+ if( pWal->exclusiveMode ) return SQLITE_OK;
-+ rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1,
-+ SQLITE_SHM_LOCK | SQLITE_SHM_SHARED);
-+ WALTRACE(("WAL%p: acquire SHARED-%s %s\n", pWal,
-+ walLockName(lockIdx), rc ? "failed" : "ok"));
-+ VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); )
-+ 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);
-+ WALTRACE(("WAL%p: release SHARED-%s\n", pWal, walLockName(lockIdx)));
-+}
-+static int walLockExclusive(Wal *pWal, int lockIdx, int n){
-+ int rc;
-+ if( pWal->exclusiveMode ) return SQLITE_OK;
-+ rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
-+ SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE);
-+ 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!=SQLITE_BUSY); )
-+ 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);
-+ WALTRACE(("WAL%p: release EXCLUSIVE-%s cnt=%d\n", pWal,
-+ walLockName(lockIdx), n));
- }
+-}
++/*
++** Each page of the wal-index mapping contains a hash-table made up of
++** an array of HASHTABLE_NSLOT elements of the following type.
++*/
++typedef u16 ht_slot;
/*
-** This function merges two sorted lists into a single sorted list.
@@ -5736,46 +39026,75 @@
-** aLeft[] and aRight[] are arrays of indices. The sort key is
-** aContent[aLeft[]] and aContent[aRight[]]. Upon entry, the following
-** is guaranteed for all J<K:
--**
++** This structure is used to implement an iterator that loops through
++** all frames in the WAL in database page order. Where two or more frames
++** correspond to the same database page, the iterator visits only the
++** frame most recently written to the WAL (in other words, the frame with
++** the largest index).
+ **
-** aContent[aLeft[J]] < aContent[aLeft[K]]
-** aContent[aRight[J]] < aContent[aRight[K]]
--**
++** The internals of this structure are only accessed by:
+ **
-** This routine overwrites aRight[] with a new (probably longer) sequence
-** of indices such that the aRight[] contains every index that appears in
-** either aLeft[] or the old aRight[] and such that the second condition
-** above is still met.
--**
++** walIteratorInit() - Create a new iterator,
++** walIteratorNext() - Step an iterator,
++** walIteratorFree() - Free an iterator.
+ **
-** The aContent[aLeft[X]] values will be unique for all X. And the
-** aContent[aRight[X]] values will be unique too. But there might be
-** one or more combinations of X and Y such that
-+** Compute a hash on a page number. The resulting hash value must land
-+** between 0 and (HASHTABLE_NSLOT-1). The walHashNext() function advances
-+** the hash to the next value in the event of a collision.
++** This functionality is used by the checkpoint code (see walCheckpoint()).
+*/
-+static int walHash(u32 iPage){
-+ assert( iPage>0 );
-+ assert( (HASHTABLE_NSLOT & (HASHTABLE_NSLOT-1))==0 );
-+ return (iPage*HASHTABLE_HASH_1) & (HASHTABLE_NSLOT-1);
-+}
-+static int walNextHash(int iPriorHash){
-+ return (iPriorHash+1)&(HASHTABLE_NSLOT-1);
-+}
++struct WalIterator {
++ int iPrior; /* Last result returned from the iterator */
++ int nSegment; /* Number of entries in aSegment[] */
++ struct WalSegment {
++ int iNext; /* Next slot in aIndex[] not yet returned */
++ ht_slot *aIndex; /* i0, i1, i2... such that aPgno[iN] ascend */
++ u32 *aPgno; /* Array of page numbers. */
++ int nEntry; /* Nr. of entries in aPgno[] and aIndex[] */
++ int iZero; /* Frame number associated with aPgno[0] */
++ } aSegment[1]; /* One for every 32KB page in the wal-index */
++};
+
-+/*
-+** Return pointers to the hash table and page number array stored on
-+** page iHash of the wal-index. The wal-index is broken into 32KB pages
-+** numbered starting from 0.
++/*
++** Define the parameters of the hash tables in the wal-index file. There
++** is a hash-table following every HASHTABLE_NPAGE page numbers in the
++** wal-index.
**
-** aLeft[X]!=aRight[Y] && aContent[aLeft[X]] == aContent[aRight[Y]]
-+** Set output variable *paHash to point to the start of the hash table
-+** in the wal-index file. Set *piZero to one less than the frame
-+** number of the first frame indexed by this hash table. If a
-+** slot in the hash table is set to N, it refers to frame number
-+** (*piZero+N) in the log.
++** Changing any of these constants will alter the wal-index format and
++** create incompatibilities.
++*/
++#define HASHTABLE_NPAGE 4096 /* Must be power of 2 */
++#define HASHTABLE_HASH_1 383 /* Should be prime */
++#define HASHTABLE_NSLOT (HASHTABLE_NPAGE*2) /* Must be a power of 2 */
++
++/*
++** The block of page numbers associated with the first hash-table in a
++** wal-index is smaller than usual. This is so that there is a complete
++** hash-table on each aligned 32KB page of the wal-index.
++*/
++#define HASHTABLE_NPAGE_ONE (HASHTABLE_NPAGE - (WALINDEX_HDR_SIZE/sizeof(u32)))
++
++/* The wal-index is divided into pages of WALINDEX_PGSZ bytes each. */
++#define WALINDEX_PGSZ ( \
++ sizeof(ht_slot)*HASHTABLE_NSLOT + HASHTABLE_NPAGE*sizeof(u32) \
++)
++
++/*
++** 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
++** numbered from zero.
**
-** When that happens, omit the aLeft[X] and use the aRight[Y] index.
-+** Finally, set *paPgno so that *paPgno[1] is the page number of the
-+** first frame indexed by the hash table, frame (*piZero+1).
++** If this call is successful, *ppPage is set to point to the wal-index
++** page and SQLITE_OK is returned. If an error (an OOM or VFS error) occurs,
++** then an SQLite error code is returned and *ppPage is set to 0.
*/
-static void walMerge(
- const u32 *aContent, /* Pages in wal - keys for the sort */
@@ -5784,87 +39103,83 @@
- ht_slot **paRight, /* IN/OUT: Right hand input list */
- int *pnRight, /* IN/OUT: Elements in *paRight */
- ht_slot *aTmp /* Temporary buffer */
-+static int walHashGet(
-+ Wal *pWal, /* WAL handle */
-+ int iHash, /* Find the iHash'th table */
-+ volatile ht_slot **paHash, /* OUT: Pointer to hash index */
-+ volatile u32 **paPgno, /* OUT: Pointer to page number array */
-+ u32 *piZero /* OUT: Frame associated with *paPgno[0] */
- ){
+-){
- int iLeft = 0; /* Current index in aLeft */
- int iRight = 0; /* Current index in aRight */
- int iOut = 0; /* Current index in output buffer */
- int nRight = *pnRight;
- ht_slot *aRight = *paRight;
-+ int rc; /* Return code */
-+ volatile u32 *aPgno;
++static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){
++ int rc = SQLITE_OK;
- assert( nLeft>0 && nRight>0 );
- while( iRight<nRight || iLeft<nLeft ){
- ht_slot logpage;
- Pgno dbpage;
-+ rc = walIndexPage(pWal, iHash, &aPgno);
-+ assert( rc==SQLITE_OK || iHash>0 );
++ /* Enlarge the pWal->apWiData[] array if required */
++ if( pWal->nWiData<=iPage ){
++ int nByte = sizeof(u32*)*(iPage+1);
++ volatile u32 **apNew;
++ apNew = (volatile u32 **)sqlite3_realloc64((void *)pWal->apWiData, nByte);
++ if( !apNew ){
++ *ppPage = 0;
++ return SQLITE_NOMEM;
++ }
++ memset((void*)&apNew[pWal->nWiData], 0,
++ sizeof(u32*)*(iPage+1-pWal->nWiData));
++ pWal->apWiData = apNew;
++ pWal->nWiData = iPage+1;
++ }
- if( (iLeft<nLeft)
- && (iRight>=nRight || aContent[aLeft[iLeft]]<aContent[aRight[iRight]])
- ){
- logpage = aLeft[iLeft++];
-+ if( rc==SQLITE_OK ){
-+ u32 iZero;
-+ volatile ht_slot *aHash;
-+
-+ aHash = (volatile ht_slot *)&aPgno[HASHTABLE_NPAGE];
-+ if( iHash==0 ){
-+ aPgno = &aPgno[WALINDEX_HDR_SIZE/sizeof(u32)];
-+ iZero = 0;
++ /* Request a pointer to the required page from the VFS */
++ if( pWal->apWiData[iPage]==0 ){
++ if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){
++ pWal->apWiData[iPage] = (u32 volatile *)sqlite3MallocZero(WALINDEX_PGSZ);
++ if( !pWal->apWiData[iPage] ) rc = SQLITE_NOMEM;
}else{
- logpage = aRight[iRight++];
-+ iZero = HASHTABLE_NPAGE_ONE + (iHash-1)*HASHTABLE_NPAGE;
++ rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ,
++ pWal->writeLock, (void volatile **)&pWal->apWiData[iPage]
++ );
++ if( rc==SQLITE_READONLY ){
++ pWal->readOnly |= WAL_SHM_RDONLY;
++ rc = SQLITE_OK;
++ }
}
- dbpage = aContent[logpage];
-+
-+ *paPgno = &aPgno[-1];
-+ *paHash = aHash;
-+ *piZero = iZero;
+ }
-+ return rc;
-+}
- aTmp[iOut++] = logpage;
- if( iLeft<nLeft && aContent[aLeft[iLeft]]==dbpage ) iLeft++;
-+/*
-+** Return the number of the wal-index page that contains the hash-table
-+** and page-number array that contain entries corresponding to WAL frame
-+** iFrame. The wal-index is broken up into 32KB pages. Wal-index pages
-+** are numbered starting from 0.
-+*/
-+static int walFramePage(u32 iFrame){
-+ int iHash = (iFrame+HASHTABLE_NPAGE-HASHTABLE_NPAGE_ONE-1) / HASHTABLE_NPAGE;
-+ assert( (iHash==0 || iFrame>HASHTABLE_NPAGE_ONE)
-+ && (iHash>=1 || iFrame<=HASHTABLE_NPAGE_ONE)
-+ && (iHash<=1 || iFrame>(HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE))
-+ && (iHash>=2 || iFrame<=HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE)
-+ && (iHash<=2 || iFrame>(HASHTABLE_NPAGE_ONE+2*HASHTABLE_NPAGE))
-+ );
-+ return iHash;
++ *ppPage = pWal->apWiData[iPage];
++ assert( iPage==0 || *ppPage || rc!=SQLITE_OK );
++ return rc;
+}
- assert( iLeft>=nLeft || aContent[aLeft[iLeft]]>dbpage );
- assert( iRight>=nRight || aContent[aRight[iRight]]>dbpage );
+- }
+/*
-+** Return the page number associated with frame iFrame in this WAL.
++** Return a pointer to the WalCkptInfo structure in the wal-index.
+*/
-+static u32 walFramePgno(Wal *pWal, u32 iFrame){
-+ int iHash = walFramePage(iFrame);
-+ if( iHash==0 ){
-+ return pWal->apWiData[0][WALINDEX_HDR_SIZE/sizeof(u32) + iFrame - 1];
- }
--
++static volatile WalCkptInfo *walCkptInfo(Wal *pWal){
++ assert( pWal->nWiData>0 && pWal->apWiData[0] );
++ return (volatile WalCkptInfo*)&(pWal->apWiData[0][sizeof(WalIndexHdr)/2]);
++}
+
- *paRight = aLeft;
- *pnRight = iOut;
- memcpy(aLeft, aTmp, sizeof(aTmp[0])*iOut);
-+ return pWal->apWiData[iHash][(iFrame-1-HASHTABLE_NPAGE_ONE)%HASHTABLE_NPAGE];
++/*
++** Return a pointer to the WalIndexHdr structure in the wal-index.
++*/
++static volatile WalIndexHdr *walIndexHdr(Wal *pWal){
++ assert( pWal->nWiData>0 && pWal->apWiData[0] );
++ return (volatile WalIndexHdr*)pWal->apWiData[0];
}
/*
@@ -5878,37 +39193,48 @@
-** aContent[aList[J]] < aContent[aList[K]]
-**
-** For any X and Y such that
-+** Remove entries from the hash table that point to WAL slots greater
-+** than pWal->hdr.mxFrame.
++** The argument to this macro must be of type u32. On a little-endian
++** architecture, it returns the u32 value that results from interpreting
++** the 4 bytes as a big-endian value. On a big-endian architecture, it
++** returns the value that would be produced by interpreting the 4 bytes
++** of the input value as a little-endian integer.
++*/
++#define BYTESWAP32(x) ( \
++ (((x)&0x000000FF)<<24) + (((x)&0x0000FF00)<<8) \
++ + (((x)&0x00FF0000)>>8) + (((x)&0xFF000000)>>24) \
++)
++
++/*
++** Generate or extend an 8 byte checksum based on the data in
++** array aByte[] and the initial values of aIn[0] and aIn[1] (or
++** initial values of 0 and 0 if aIn==NULL).
**
-** aContent[aList[X]] == aContent[aList[Y]]
-+** This function is called whenever pWal->hdr.mxFrame is decreased due
-+** to a rollback or savepoint.
++** The checksum is written back into aOut[] before returning.
**
-** Keep the larger of the two values aList[X] and aList[Y] and discard
-** the smaller.
-+** At most only the hash table containing pWal->hdr.mxFrame needs to be
-+** updated. Any later hash tables will be automatically cleared when
-+** pWal->hdr.mxFrame advances to the point where those hash tables are
-+** actually needed.
++** nByte must be a positive multiple of 8.
*/
-static void walMergesort(
- const u32 *aContent, /* Pages in wal */
- ht_slot *aBuffer, /* Buffer of at least *pnList items to use */
- ht_slot *aList, /* IN/OUT: List to sort */
- int *pnList /* IN/OUT: Number of elements in aList[] */
--){
++static void walChecksumBytes(
++ int nativeCksum, /* True for native byte-order, false for non-native */
++ u8 *a, /* Content to be checksummed */
++ int nByte, /* Bytes of content in a[]. Must be a multiple of 8. */
++ const u32 *aIn, /* Initial checksum value input */
++ u32 *aOut /* OUT: Final checksum value output */
+ ){
- struct Sublist {
- int nList; /* Number of elements in aList */
- ht_slot *aList; /* Pointer to sub-list content */
- };
-+static void walCleanupHash(Wal *pWal){
-+ volatile ht_slot *aHash = 0; /* Pointer to hash table to clear */
-+ volatile u32 *aPgno = 0; /* Page number array for hash table */
-+ u32 iZero = 0; /* frame == (aHash[x]+iZero) */
-+ int iLimit = 0; /* Zero values greater than this */
-+ int nByte; /* Number of bytes to zero in aPgno[] */
-+ int i; /* Used to iterate through aHash[] */
++ u32 s1, s2;
++ u32 *aData = (u32 *)a;
++ u32 *aEnd = (u32 *)&a[nByte];
- const int nList = *pnList; /* Size of input list */
- int nMerge = 0; /* Number of elements in list aMerge */
@@ -5916,15 +39242,18 @@
- int iList; /* Index into input list */
- int iSub = 0; /* Index into aSub array */
- struct Sublist aSub[13]; /* Array of sub-lists */
-+ assert( pWal->writeLock );
-+ testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE-1 );
-+ testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE );
-+ testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE+1 );
++ if( aIn ){
++ s1 = aIn[0];
++ s2 = aIn[1];
++ }else{
++ s1 = s2 = 0;
++ }
- memset(aSub, 0, sizeof(aSub));
- assert( nList<=HASHTABLE_NPAGE && nList>0 );
- assert( HASHTABLE_NPAGE==(1<<(ArraySize(aSub)-1)) );
-+ if( pWal->hdr.mxFrame==0 ) return;
++ assert( nByte>=8 );
++ assert( (nByte&0x00000007)==0 );
- for(iList=0; iList<nList; iList++){
- nMerge = 1;
@@ -5937,14 +39266,18 @@
- }
- aSub[iSub].aList = aMerge;
- aSub[iSub].nList = nMerge;
-- }
-+ /* Obtain pointers to the hash-table and page-number array containing
-+ ** the entry that corresponds to frame pWal->hdr.mxFrame. It is guaranteed
-+ ** that the page said hash-table and array reside on is already mapped.
-+ */
-+ assert( pWal->nWiData>walFramePage(pWal->hdr.mxFrame) );
-+ assert( pWal->apWiData[walFramePage(pWal->hdr.mxFrame)] );
-+ walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &aHash, &aPgno, &iZero);
++ if( nativeCksum ){
++ do {
++ s1 += *aData++ + s2;
++ s2 += *aData++ + s1;
++ }while( aData<aEnd );
++ }else{
++ do {
++ s1 += BYTESWAP32(aData[0]) + s2;
++ s2 += BYTESWAP32(aData[1]) + s1;
++ aData += 2;
++ }while( aData<aEnd );
+ }
- for(iSub++; iSub<ArraySize(aSub); iSub++){
- if( nList & (1<<iSub) ){
@@ -5952,54 +39285,48 @@
- assert( p->nList<=(1<<iSub) );
- assert( p->aList==&aList[nList&~((2<<iSub)-1)] );
- walMerge(aContent, p->aList, p->nList, &aMerge, &nMerge, aBuffer);
-+ /* Zero all hash-table entries that correspond to frame numbers greater
-+ ** than pWal->hdr.mxFrame.
-+ */
-+ iLimit = pWal->hdr.mxFrame - iZero;
-+ assert( iLimit>0 );
-+ for(i=0; i<HASHTABLE_NSLOT; i++){
-+ if( aHash[i]>iLimit ){
-+ aHash[i] = 0;
- }
- }
+- }
+- }
- assert( aMerge==aList );
- *pnList = nMerge;
-+
-+ /* Zero the entries in the aPgno array that correspond to frames with
-+ ** frame numbers greater than pWal->hdr.mxFrame.
-+ */
-+ nByte = (int)((char *)aHash - (char *)&aPgno[iLimit+1]);
-+ memset((void *)&aPgno[iLimit+1], 0, nByte);
++ aOut[0] = s1;
++ aOut[1] = s2;
++}
-#ifdef SQLITE_DEBUG
- {
- int i;
- for(i=1; i<*pnList; i++){
- assert( aContent[aList[i]] > aContent[aList[i-1]] );
-+#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
-+ /* Verify that the every entry in the mapping region is still reachable
-+ ** via the hash table even after the cleanup.
-+ */
-+ if( iLimit ){
-+ int i; /* Loop counter */
-+ int iKey; /* Hash key */
-+ for(i=1; i<=iLimit; i++){
-+ for(iKey=walHash(aPgno[i]); aHash[iKey]; iKey=walNextHash(iKey)){
-+ if( aHash[iKey]==i ) break;
-+ }
-+ assert( aHash[iKey]==i );
- }
+- }
++static void walShmBarrier(Wal *pWal){
++ if( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE ){
++ sqlite3OsShmBarrier(pWal->pDbFd);
}
-#endif
-+#endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */
}
-/*
-** Free an iterator allocated by walIteratorInit().
--*/
++/*
++** Write the header information in pWal->hdr into the wal-index.
++**
++** The checksum on pWal->hdr is updated before it is written.
+ */
-static void walIteratorFree(WalIterator *p){
-- sqlite3ScratchFree(p);
--}
+- sqlite3_free(p);
++static void walIndexWriteHdr(Wal *pWal){
++ volatile WalIndexHdr *aHdr = walIndexHdr(pWal);
++ const int nCksum = offsetof(WalIndexHdr, aCksum);
++
++ assert( pWal->writeLock );
++ pWal->hdr.isInit = 1;
++ pWal->hdr.iVersion = WALINDEX_MAX_VERSION;
++ walChecksumBytes(1, (u8*)&pWal->hdr, nCksum, 0, pWal->hdr.aCksum);
++ memcpy((void *)&aHdr[1], (void *)&pWal->hdr, sizeof(WalIndexHdr));
++ walShmBarrier(pWal);
++ memcpy((void *)&aHdr[0], (void *)&pWal->hdr, sizeof(WalIndexHdr));
+ }
/*
-** Construct a WalInterator object that can be used to loop over all
@@ -6009,11 +39336,19 @@
-** On success, make *pp point to the newly allocated WalInterator object
-** return SQLITE_OK. Otherwise, return an error code. If this routine
-** returns an error, the value of *pp is undefined.
--**
++** This function encodes a single frame header and writes it to a buffer
++** supplied by the caller. A frame-header is made up of a series of
++** 4-byte big-endian integers, as follows:
+ **
-** The calling routine should invoke walIteratorFree() to destroy the
-** WalIterator object when it has finished with it.
-+** Set an entry in the wal-index that will map database page number
-+** pPage into WAL frame iFrame.
++** 0: Page number.
++** 4: For commit records, the size of the database image in pages
++** after the commit. For all other records, zero.
++** 8: Salt-1 (copied from the wal-header)
++** 12: Salt-2 (copied from the wal-header)
++** 16: Checksum-1.
++** 20: Checksum-2.
*/
-static int walIteratorInit(Wal *pWal, WalIterator **pp){
- WalIterator *p; /* Return value */
@@ -6023,95 +39358,112 @@
- int i; /* Iterator variable */
- ht_slot *aTmp; /* Temp space used by merge-sort */
- int rc = SQLITE_OK; /* Return Code */
-+static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
-+ int rc; /* Return code */
-+ u32 iZero = 0; /* One less than frame number of aPgno[1] */
-+ volatile u32 *aPgno = 0; /* Page number array */
-+ volatile ht_slot *aHash = 0; /* Hash table */
++static void walEncodeFrame(
++ Wal *pWal, /* The write-ahead log */
++ u32 iPage, /* Database page number for frame */
++ u32 nTruncate, /* New db size (or 0 for non-commit frames) */
++ u8 *aData, /* Pointer to page data */
++ u8 *aFrame /* OUT: Write encoded frame here */
++){
++ int nativeCksum; /* True for native byte-order checksums */
++ u32 *aCksum = pWal->hdr.aFrameCksum;
++ assert( WAL_FRAME_HDRSIZE==24 );
++ sqlite3Put4byte(&aFrame[0], iPage);
++ sqlite3Put4byte(&aFrame[4], nTruncate);
++ memcpy(&aFrame[8], pWal->hdr.aSalt, 8);
- /* This routine only runs while holding the checkpoint lock. And
- ** it only runs if there is actually content in the log (mxFrame>0).
-+ rc = walHashGet(pWal, walFramePage(iFrame), &aHash, &aPgno, &iZero);
-+
-+ /* Assuming the wal-index file was successfully mapped, populate the
-+ ** page number array and hash table entry.
- */
+- */
- assert( pWal->ckptLock && pWal->hdr.mxFrame>0 );
- iLast = pWal->hdr.mxFrame;
-+ if( rc==SQLITE_OK ){
-+ int iKey; /* Hash table key */
-+ int idx; /* Value to write to hash-table slot */
-+ int nCollide; /* Number of hash collisions */
++ nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN);
++ walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum);
++ walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum);
- /* Allocate space for the WalIterator object. */
- nSegment = walFramePage(iLast) + 1;
- nByte = sizeof(WalIterator)
- + (nSegment-1)*sizeof(struct WalSegment)
- + iLast*sizeof(ht_slot);
-- p = (WalIterator *)sqlite3ScratchMalloc(nByte);
+- p = (WalIterator *)sqlite3_malloc64(nByte);
- if( !p ){
- return SQLITE_NOMEM;
-- }
++ sqlite3Put4byte(&aFrame[16], aCksum[0]);
++ sqlite3Put4byte(&aFrame[20], aCksum[1]);
++}
++
++/*
++** Check to see if the frame with header in aFrame[] and content
++** in aData[] is valid. If it is a valid frame, fill *piPage and
++** *pnTruncate and return true. Return if the frame is not valid.
++*/
++static int walDecodeFrame(
++ Wal *pWal, /* The write-ahead log */
++ u32 *piPage, /* OUT: Database page number for frame */
++ u32 *pnTruncate, /* OUT: New db size (or 0 if not commit) */
++ u8 *aData, /* Pointer to page data (for checksum) */
++ u8 *aFrame /* Frame data */
++){
++ int nativeCksum; /* True for native byte-order checksums */
++ u32 *aCksum = pWal->hdr.aFrameCksum;
++ u32 pgno; /* Page number of the frame */
++ assert( WAL_FRAME_HDRSIZE==24 );
++
++ /* A frame is only valid if the salt values in the frame-header
++ ** match the salt values in the wal-header.
++ */
++ if( memcmp(&pWal->hdr.aSalt, &aFrame[8], 8)!=0 ){
++ return 0;
+ }
- memset(p, 0, nByte);
- p->nSegment = nSegment;
-+ idx = iFrame - iZero;
-+ assert( idx <= HASHTABLE_NSLOT/2 + 1 );
-+
-+ /* If this is the first entry to be added to this hash-table, zero the
-+ ** entire hash table and aPgno[] array before proceding.
-+ */
-+ if( idx==1 ){
-+ int nByte = (int)((u8 *)&aHash[HASHTABLE_NSLOT] - (u8 *)&aPgno[1]);
-+ memset((void*)&aPgno[1], 0, nByte);
-+ }
- /* Allocate temporary space used by the merge-sort routine. This block
- ** of memory will be freed before this function returns.
-- */
-- aTmp = (ht_slot *)sqlite3ScratchMalloc(
++ /* A frame is only valid if the page number is creater than zero.
+ */
+- aTmp = (ht_slot *)sqlite3_malloc64(
- sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast)
- );
- if( !aTmp ){
- rc = SQLITE_NOMEM;
-- }
-+ /* If the entry in aPgno[] is already set, then the previous writer
-+ ** must have exited unexpectedly in the middle of a transaction (after
-+ ** writing one or more dirty pages to the WAL to free up memory).
-+ ** Remove the remnants of that writers uncommitted transaction from
-+ ** the hash-table before writing any new entries.
-+ */
-+ if( aPgno[idx] ){
-+ walCleanupHash(pWal);
-+ assert( !aPgno[idx] );
-+ }
++ pgno = sqlite3Get4byte(&aFrame[0]);
++ if( pgno==0 ){
++ return 0;
+ }
- for(i=0; rc==SQLITE_OK && i<nSegment; i++){
- volatile ht_slot *aHash;
- u32 iZero;
- volatile u32 *aPgno;
-+ /* Write the aPgno[] array entry and the hash-table slot. */
-+ nCollide = idx;
-+ for(iKey=walHash(iPage); aHash[iKey]; iKey=walNextHash(iKey)){
-+ if( (nCollide--)==0 ) return SQLITE_CORRUPT_BKPT;
-+ }
-+ aPgno[idx] = iPage;
-+ aHash[iKey] = (ht_slot)idx;
++ /* A frame is only valid if a checksum of the WAL header,
++ ** all prior frams, the first 16 bytes of this frame-header,
++ ** and the frame-data matches the checksum in the last 8
++ ** bytes of this frame-header.
++ */
++ nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN);
++ walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum);
++ walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum);
++ if( aCksum[0]!=sqlite3Get4byte(&aFrame[16])
++ || aCksum[1]!=sqlite3Get4byte(&aFrame[20])
++ ){
++ /* Checksum failed. */
++ return 0;
++ }
- rc = walHashGet(pWal, i, &aHash, &aPgno, &iZero);
- if( rc==SQLITE_OK ){
- int j; /* Counter variable */
- int nEntry; /* Number of entries in this segment */
- ht_slot *aIndex; /* Sorted index for this segment */
-+#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
-+ /* Verify that the number of entries in the hash table exactly equals
-+ ** the number of entries in the mapping region.
-+ */
-+ {
-+ int i; /* Loop counter */
-+ int nEntry = 0; /* Number of entries in the hash table */
-+ for(i=0; i<HASHTABLE_NSLOT; i++){ if( aHash[i] ) nEntry++; }
-+ assert( nEntry==idx );
-+ }
++ /* If we reach this point, the frame is valid. Return the page number
++ ** and the new database size.
++ */
++ *piPage = pgno;
++ *pnTruncate = sqlite3Get4byte(&aFrame[4]);
++ return 1;
++}
- aPgno++;
- if( (i+1)==nSegment ){
@@ -6124,42 +39476,53 @@
-
- for(j=0; j<nEntry; j++){
- aIndex[j] = (ht_slot)j;
-+ /* Verify that the every entry in the mapping region is reachable
-+ ** via the hash table. This turns out to be a really, really expensive
-+ ** thing to check, so only do this occasionally - not on every
-+ ** iteration.
-+ */
-+ if( (idx&0x3ff)==0 ){
-+ int i; /* Loop counter */
-+ for(i=1; i<=idx; i++){
-+ for(iKey=walHash(aPgno[i]); aHash[iKey]; iKey=walNextHash(iKey)){
-+ if( aHash[iKey]==i ) break;
-+ }
-+ assert( aHash[iKey]==i );
- }
+- }
- walMergesort((u32 *)aPgno, aTmp, aIndex, &nEntry);
- p->aSegment[i].iZero = iZero;
- p->aSegment[i].nEntry = nEntry;
- p->aSegment[i].aIndex = aIndex;
- p->aSegment[i].aPgno = (u32 *)aPgno;
- }
-+#endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */
- }
-- sqlite3ScratchFree(aTmp);
+- }
+- }
+- sqlite3_free(aTmp);
- if( rc!=SQLITE_OK ){
- walIteratorFree(p);
-- }
++#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
++/*
++** Names of locks. This routine is used to provide debugging output and is not
++** a part of an ordinary build.
++*/
++static const char *walLockName(int lockIdx){
++ if( lockIdx==WAL_WRITE_LOCK ){
++ return "WRITE-LOCK";
++ }else if( lockIdx==WAL_CKPT_LOCK ){
++ return "CKPT-LOCK";
++ }else if( lockIdx==WAL_RECOVER_LOCK ){
++ return "RECOVER-LOCK";
++ }else{
++ static char zName[15];
++ sqlite3_snprintf(sizeof(zName), zName, "READ-LOCK[%d]",
++ lockIdx-WAL_READ_LOCK(0));
++ return zName;
+ }
- *pp = p;
- return rc;
--}
+ }
++#endif /*defined(SQLITE_TEST) || defined(SQLITE_DEBUG) */
++
--/*
+ /*
-** Attempt to obtain the exclusive WAL lock defined by parameters lockIdx and
-** n. If the attempt fails and parameter xBusy is not NULL, then it is a
-** busy-handler function. Invoke it and retry the lock until either the
-** lock is successfully obtained or the busy-handler returns 0.
--*/
++** Set or release locks on the WAL. Locks are either shared or exclusive.
++** A lock cannot be moved directly between shared and exclusive - it must go
++** through the unlocked state first.
++**
++** In locking_mode=EXCLUSIVE, all of these routines become no-ops.
+ */
-static int walBusyLock(
- Wal *pWal, /* WAL connection */
- int (*xBusy)(void*), /* Function to call when busy */
@@ -6167,22 +39530,94 @@
- int lockIdx, /* Offset of first byte to lock */
- int n /* Number of bytes to lock */
-){
-- int rc;
++static int walLockShared(Wal *pWal, int lockIdx){
+ int rc;
- do {
-- rc = walLockExclusive(pWal, lockIdx, n);
+- rc = walLockExclusive(pWal, lockIdx, n, 0);
- }while( xBusy && rc==SQLITE_BUSY && xBusy(pBusyArg) );
++ if( pWal->exclusiveMode ) return SQLITE_OK;
++ rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1,
++ SQLITE_SHM_LOCK | SQLITE_SHM_SHARED);
++ WALTRACE(("WAL%p: acquire SHARED-%s %s\n", pWal,
++ walLockName(lockIdx), rc ? "failed" : "ok"));
++ VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); )
return rc;
}
-
+-
-/*
-** The cache of the wal-index header must be valid to call this function.
-** Return the page-size in bytes used by the database.
-*/
-static int walPagesize(Wal *pWal){
- return (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16);
--}
++static void walUnlockShared(Wal *pWal, int lockIdx){
++ if( pWal->exclusiveMode ) return;
++ (void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1,
++ SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED);
++ WALTRACE(("WAL%p: release SHARED-%s\n", pWal, walLockName(lockIdx)));
++}
++static int walLockExclusive(Wal *pWal, int lockIdx, int n, int fBlock){
++ int rc;
++ if( pWal->exclusiveMode ) return SQLITE_OK;
++ if( fBlock ) sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_WAL_BLOCK, 0);
++ rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
++ SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE);
++ 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!=SQLITE_BUSY); )
++ 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);
++ WALTRACE(("WAL%p: release EXCLUSIVE-%s cnt=%d\n", pWal,
++ walLockName(lockIdx), n));
+ }
/*
+-** The following is guaranteed when this function is called:
+-**
+-** a) the WRITER lock is held,
+-** b) the entire log file has been checkpointed, and
+-** c) any existing readers are reading exclusively from the database
+-** file - there are no readers that may attempt to read a frame from
+-** the log file.
+-**
+-** This function updates the shared-memory structures so that the next
+-** client to write to the database (which may be this one) does so by
+-** writing frames into the start of the log file.
+-**
+-** The value of parameter salt1 is used as the aSalt[1] value in the
+-** new wal-index header. It should be passed a pseudo-random value (i.e.
+-** one obtained from sqlite3_randomness()).
++** Compute a hash on a page number. The resulting hash value must land
++** between 0 and (HASHTABLE_NSLOT-1). The walHashNext() function advances
++** the hash to the next value in the event of a collision.
+ */
+-static void walRestartHdr(Wal *pWal, u32 salt1){
+- volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
+- int i; /* Loop counter */
+- u32 *aSalt = pWal->hdr.aSalt; /* Big-endian salt values */
+- pWal->nCkpt++;
+- pWal->hdr.mxFrame = 0;
+- sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0]));
+- memcpy(&pWal->hdr.aSalt[1], &salt1, 4);
+- walIndexWriteHdr(pWal);
+- pInfo->nBackfill = 0;
+- pInfo->aReadMark[1] = 0;
+- for(i=2; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
+- assert( pInfo->aReadMark[0]==0 );
++static int walHash(u32 iPage){
++ assert( iPage>0 );
++ assert( (HASHTABLE_NSLOT & (HASHTABLE_NSLOT-1))==0 );
++ return (iPage*HASHTABLE_HASH_1) & (HASHTABLE_NSLOT-1);
++}
++static int walNextHash(int iPriorHash){
++ return (iPriorHash+1)&(HASHTABLE_NSLOT-1);
+ }
+
+-/*
-** Copy as much content as we can from the WAL back into the database file
-** in response to an sqlite3_wal_checkpoint() request or the equivalent.
-**
@@ -6203,32 +39638,42 @@
-** WAL content is copied into the database file. This second fsync makes
-** it safe to delete the WAL since the new content will persist in the
-** database file.
--**
++/*
++** Return pointers to the hash table and page number array stored on
++** page iHash of the wal-index. The wal-index is broken into 32KB pages
++** numbered starting from 0.
+ **
-** This routine uses and updates the nBackfill field of the wal-index header.
--** This is the only routine tha will increase the value of nBackfill.
+-** This is the only routine that will increase the value of nBackfill.
-** (A WAL reset or recovery will revert nBackfill to zero, but not increase
-** its value.)
-+** Recover the wal-index by reading the write-ahead log file.
++** Set output variable *paHash to point to the start of the hash table
++** in the wal-index file. Set *piZero to one less than the frame
++** number of the first frame indexed by this hash table. If a
++** slot in the hash table is set to N, it refers to frame number
++** (*piZero+N) in the log.
**
-** The caller must be holding sufficient locks to ensure that no other
-** checkpoint is running (in any other thread or process) at the same
-** time.
-+** This routine first tries to establish an exclusive lock on the
-+** wal-index to prevent other threads/processes from doing anything
-+** with the WAL or wal-index while recovery is running. The
-+** WAL_RECOVER_LOCK is also held so that other threads will know
-+** that this thread is running recovery. If unable to establish
-+** the necessary locks, this routine returns SQLITE_BUSY.
++** Finally, set *paPgno so that *paPgno[1] is the page number of the
++** first frame indexed by the hash table, frame (*piZero+1).
*/
-static int walCheckpoint(
- Wal *pWal, /* Wal connection */
- int eMode, /* One of PASSIVE, FULL or RESTART */
-- int (*xBusyCall)(void*), /* Function to call when busy */
+- int (*xBusy)(void*), /* Function to call when busy */
- void *pBusyArg, /* Context argument for xBusyHandler */
- int sync_flags, /* Flags for OsSync() (or 0) */
- u8 *zBuf /* Temporary buffer to use */
--){
-- int rc; /* Return code */
++static int walHashGet(
++ Wal *pWal, /* WAL handle */
++ int iHash, /* Find the iHash'th table */
++ volatile ht_slot **paHash, /* OUT: Pointer to hash index */
++ volatile u32 **paPgno, /* OUT: Pointer to page number array */
++ u32 *piZero /* OUT: Frame associated with *paPgno[0] */
+ ){
+- int rc = SQLITE_OK; /* Return code */
- int szPage; /* Database page-size */
- WalIterator *pIter = 0; /* Wal iterator context */
- u32 iDbpage = 0; /* Next database page to write */
@@ -6237,270 +39682,267 @@
- u32 mxPage; /* Max database page to write */
- int i; /* Loop counter */
- volatile WalCkptInfo *pInfo; /* The checkpoint status information */
-- int (*xBusy)(void*) = 0; /* Function to call when waiting for locks */
-
- szPage = walPagesize(pWal);
- testcase( szPage<=32768 );
- testcase( szPage>=65536 );
- pInfo = walCkptInfo(pWal);
-- if( pInfo->nBackfill>=pWal->hdr.mxFrame ) return SQLITE_OK;
-+static int walIndexRecover(Wal *pWal){
-+ int rc; /* Return Code */
-+ i64 nSize; /* Size of log file */
-+ u32 aFrameCksum[2] = {0, 0};
-+ int iLock; /* Lock offset to lock for checkpoint */
-+ int nLock; /* Number of locks to hold */
+- if( pInfo->nBackfill<pWal->hdr.mxFrame ){
++ int rc; /* Return code */
++ volatile u32 *aPgno;
-- /* Allocate the iterator */
-- rc = walIteratorInit(pWal, &pIter);
-- if( rc!=SQLITE_OK ){
-+ /* Obtain an exclusive lock on all byte in the locking range not already
-+ ** locked by the caller. The caller is guaranteed to have locked the
-+ ** WAL_WRITE_LOCK byte, and may have also locked the WAL_CKPT_LOCK byte.
-+ ** If successful, the same bytes that are locked here are unlocked before
-+ ** this function returns.
-+ */
-+ assert( pWal->ckptLock==1 || pWal->ckptLock==0 );
-+ assert( WAL_ALL_BUT_WRITE==WAL_WRITE_LOCK+1 );
-+ assert( WAL_CKPT_LOCK==WAL_ALL_BUT_WRITE );
-+ assert( pWal->writeLock );
-+ iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock;
-+ nLock = SQLITE_SHM_NLOCK - iLock;
-+ rc = walLockExclusive(pWal, iLock, nLock);
-+ if( rc ){
- return rc;
- }
-- assert( pIter );
--
-- if( eMode!=SQLITE_CHECKPOINT_PASSIVE ) xBusy = xBusyCall;
--
-- /* Compute in mxSafeFrame the index of the last frame of the WAL that is
-- ** safe to write into the database. Frames beyond mxSafeFrame might
-- ** overwrite database pages that are in use by active readers and thus
-- ** cannot be backfilled from the WAL.
-- */
-- mxSafeFrame = pWal->hdr.mxFrame;
-- mxPage = pWal->hdr.nPage;
-- for(i=1; i<WAL_NREADER; i++){
-- u32 y = pInfo->aReadMark[i];
-- if( mxSafeFrame>y ){
-- assert( y<=pWal->hdr.mxFrame );
-- rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
-- if( rc==SQLITE_OK ){
-- pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
-- walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
-- }else if( rc==SQLITE_BUSY ){
-- mxSafeFrame = y;
-- xBusy = 0;
-- }else{
-- goto walcheckpoint_out;
-- }
+- /* Allocate the iterator */
+- rc = walIteratorInit(pWal, &pIter);
+- if( rc!=SQLITE_OK ){
+- return rc;
- }
-+ WALTRACE(("WAL%p: recovery begin...\n", pWal));
-+
-+ memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
-+
-+ rc = sqlite3OsFileSize(pWal->pWalFd, &nSize);
-+ if( rc!=SQLITE_OK ){
-+ goto recovery_error;
- }
+- assert( pIter );
++ rc = walIndexPage(pWal, iHash, &aPgno);
++ assert( rc==SQLITE_OK || iHash>0 );
-- if( pInfo->nBackfill<mxSafeFrame
-- && (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0), 1))==SQLITE_OK
-- ){
-- i64 nSize; /* Current size of database file */
-- u32 nBackfill = pInfo->nBackfill;
-+ if( nSize>WAL_HDRSIZE ){
-+ u8 aBuf[WAL_HDRSIZE]; /* Buffer to load WAL header into */
-+ u8 *aFrame = 0; /* Malloc'd buffer to load entire frame */
-+ int szFrame; /* Number of bytes in buffer aFrame[] */
-+ u8 *aData; /* Pointer to data part of aFrame buffer */
-+ int iFrame; /* Index of last frame read */
-+ i64 iOffset; /* Next offset to read from log file */
-+ int szPage; /* Page size according to the log */
-+ u32 magic; /* Magic value read from WAL header */
-+ u32 version; /* Magic value read from WAL header */
-+ int isValid; /* True if this frame is valid */
+- /* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked
+- ** in the SQLITE_CHECKPOINT_PASSIVE mode. */
+- assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 );
++ if( rc==SQLITE_OK ){
++ u32 iZero;
++ volatile ht_slot *aHash;
-- /* Sync the WAL to disk */
-- if( sync_flags ){
-- rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
-+ /* Read in the WAL header. */
-+ rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0);
-+ if( rc!=SQLITE_OK ){
-+ goto recovery_error;
+- /* Compute in mxSafeFrame the index of the last frame of the WAL that is
+- ** safe to write into the database. Frames beyond mxSafeFrame might
+- ** overwrite database pages that are in use by active readers and thus
+- ** cannot be backfilled from the WAL.
+- */
+- mxSafeFrame = pWal->hdr.mxFrame;
+- mxPage = pWal->hdr.nPage;
+- for(i=1; i<WAL_NREADER; i++){
+- /* Thread-sanitizer reports that the following is an unsafe read,
+- ** as some other thread may be in the process of updating the value
+- ** of the aReadMark[] slot. The assumption here is that if that is
+- ** happening, the other client may only be increasing the value,
+- ** not decreasing it. So assuming either that either the "old" or
+- ** "new" version of the value is read, and not some arbitrary value
+- ** that would never be written by a real client, things are still
+- ** safe. */
+- u32 y = pInfo->aReadMark[i];
+- if( mxSafeFrame>y ){
+- assert( y<=pWal->hdr.mxFrame );
+- rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
+- if( rc==SQLITE_OK ){
+- pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
+- walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
+- }else if( rc==SQLITE_BUSY ){
+- mxSafeFrame = y;
+- xBusy = 0;
+- }else{
+- goto walcheckpoint_out;
+- }
+- }
++ aHash = (volatile ht_slot *)&aPgno[HASHTABLE_NPAGE];
++ if( iHash==0 ){
++ aPgno = &aPgno[WALINDEX_HDR_SIZE/sizeof(u32)];
++ iZero = 0;
++ }else{
++ iZero = HASHTABLE_NPAGE_ONE + (iHash-1)*HASHTABLE_NPAGE;
}
++
++ *paPgno = &aPgno[-1];
++ *paHash = aHash;
++ *piZero = iZero;
++ }
++ return rc;
++}
-- /* If the database may grow as a result of this checkpoint, hint
-- ** about the eventual size of the db file to the VFS layer.
-+ /* If the database page size is not a power of two, or is greater than
-+ ** SQLITE_MAX_PAGE_SIZE, conclude that the WAL file contains no valid
-+ ** data. Similarly, if the 'magic' value is invalid, ignore the whole
-+ ** WAL file.
- */
-- if( rc==SQLITE_OK ){
-- i64 nReq = ((i64)mxPage * szPage);
-- rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
-- if( rc==SQLITE_OK && nSize<nReq ){
-- sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
+- if( pInfo->nBackfill<mxSafeFrame
+- && (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0),1))==SQLITE_OK
+- ){
+- i64 nSize; /* Current size of database file */
+- u32 nBackfill = pInfo->nBackfill;
+-
+- /* Sync the WAL to disk */
+- if( sync_flags ){
+- rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
- }
-+ magic = sqlite3Get4byte(&aBuf[0]);
-+ szPage = sqlite3Get4byte(&aBuf[8]);
-+ if( (magic&0xFFFFFFFE)!=WAL_MAGIC
-+ || szPage&(szPage-1)
-+ || szPage>SQLITE_MAX_PAGE_SIZE
-+ || szPage<512
-+ ){
-+ goto finished;
- }
-+ pWal->hdr.bigEndCksum = (u8)(magic&0x00000001);
-+ pWal->szPage = szPage;
-+ pWal->nCkpt = sqlite3Get4byte(&aBuf[12]);
-+ memcpy(&pWal->hdr.aSalt, &aBuf[16], 8);
++/*
++** Return the number of the wal-index page that contains the hash-table
++** and page-number array that contain entries corresponding to WAL frame
++** iFrame. The wal-index is broken up into 32KB pages. Wal-index pages
++** are numbered starting from 0.
++*/
++static int walFramePage(u32 iFrame){
++ int iHash = (iFrame+HASHTABLE_NPAGE-HASHTABLE_NPAGE_ONE-1) / HASHTABLE_NPAGE;
++ assert( (iHash==0 || iFrame>HASHTABLE_NPAGE_ONE)
++ && (iHash>=1 || iFrame<=HASHTABLE_NPAGE_ONE)
++ && (iHash<=1 || iFrame>(HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE))
++ && (iHash>=2 || iFrame<=HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE)
++ && (iHash<=2 || iFrame>(HASHTABLE_NPAGE_ONE+2*HASHTABLE_NPAGE))
++ );
++ return iHash;
++}
-+ /* Verify that the WAL header checksum is correct */
-+ walChecksumBytes(pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN,
-+ aBuf, WAL_HDRSIZE-2*4, 0, pWal->hdr.aFrameCksum
-+ );
-+ if( pWal->hdr.aFrameCksum[0]!=sqlite3Get4byte(&aBuf[24])
-+ || pWal->hdr.aFrameCksum[1]!=sqlite3Get4byte(&aBuf[28])
-+ ){
-+ goto finished;
-+ }
+- /* If the database may grow as a result of this checkpoint, hint
+- ** about the eventual size of the db file to the VFS layer.
+- */
+- if( rc==SQLITE_OK ){
+- i64 nReq = ((i64)mxPage * szPage);
+- rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
+- if( rc==SQLITE_OK && nSize<nReq ){
+- sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
+- }
+- }
++/*
++** Return the page number associated with frame iFrame in this WAL.
++*/
++static u32 walFramePgno(Wal *pWal, u32 iFrame){
++ int iHash = walFramePage(iFrame);
++ if( iHash==0 ){
++ return pWal->apWiData[0][WALINDEX_HDR_SIZE/sizeof(u32) + iFrame - 1];
++ }
++ return pWal->apWiData[iHash][(iFrame-1-HASHTABLE_NPAGE_ONE)%HASHTABLE_NPAGE];
++}
-- /* Iterate through the contents of the WAL, copying data to the db file. */
-- while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
-- i64 iOffset;
-- assert( walFramePgno(pWal, iFrame)==iDbpage );
-- if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ) continue;
-- iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE;
-- /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
-- rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset);
-+ /* Verify that the version number on the WAL format is one that
-+ ** are able to understand */
-+ version = sqlite3Get4byte(&aBuf[4]);
-+ if( version!=WAL_MAX_VERSION ){
-+ rc = SQLITE_CANTOPEN_BKPT;
-+ goto finished;
-+ }
-+
-+ /* Malloc a buffer to read frames into. */
-+ szFrame = szPage + WAL_FRAME_HDRSIZE;
-+ aFrame = (u8 *)sqlite3_malloc(szFrame);
-+ if( !aFrame ){
-+ rc = SQLITE_NOMEM;
-+ goto recovery_error;
-+ }
-+ aData = &aFrame[WAL_FRAME_HDRSIZE];
-+
-+ /* Read all frames from the log file. */
-+ iFrame = 0;
-+ for(iOffset=WAL_HDRSIZE; (iOffset+szFrame)<=nSize; iOffset+=szFrame){
-+ u32 pgno; /* Database page number for frame */
-+ u32 nTruncate; /* dbsize field from frame header */
-+
-+ /* Read and decode the next log frame. */
-+ iFrame++;
-+ rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset);
- if( rc!=SQLITE_OK ) break;
-- iOffset = (iDbpage-1)*(i64)szPage;
-- testcase( IS_BIG_INT(iOffset) );
-- rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset);
-+ isValid = walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame);
-+ if( !isValid ) break;
-+ rc = walIndexAppend(pWal, iFrame, pgno);
- if( rc!=SQLITE_OK ) break;
-- }
++/*
++** Remove entries from the hash table that point to WAL slots greater
++** than pWal->hdr.mxFrame.
++**
++** This function is called whenever pWal->hdr.mxFrame is decreased due
++** to a rollback or savepoint.
++**
++** At most only the hash table containing pWal->hdr.mxFrame needs to be
++** updated. Any later hash tables will be automatically cleared when
++** pWal->hdr.mxFrame advances to the point where those hash tables are
++** actually needed.
++*/
++static void walCleanupHash(Wal *pWal){
++ volatile ht_slot *aHash = 0; /* Pointer to hash table to clear */
++ volatile u32 *aPgno = 0; /* Page number array for hash table */
++ u32 iZero = 0; /* frame == (aHash[x]+iZero) */
++ int iLimit = 0; /* Zero values greater than this */
++ int nByte; /* Number of bytes to zero in aPgno[] */
++ int i; /* Used to iterate through aHash[] */
-- /* If work was actually accomplished... */
-- if( rc==SQLITE_OK ){
-- if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
-- i64 szDb = pWal->hdr.nPage*(i64)szPage;
-- testcase( IS_BIG_INT(szDb) );
-- rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
-- if( rc==SQLITE_OK && sync_flags ){
-- rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
+- /* Iterate through the contents of the WAL, copying data to the db file */
+- while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
+- i64 iOffset;
+- assert( walFramePgno(pWal, iFrame)==iDbpage );
+- if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ){
+- continue;
- }
+- iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE;
+- /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
+- rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset);
+- if( rc!=SQLITE_OK ) break;
+- iOffset = (iDbpage-1)*(i64)szPage;
+- testcase( IS_BIG_INT(iOffset) );
+- rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset);
+- if( rc!=SQLITE_OK ) break;
- }
++ assert( pWal->writeLock );
++ testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE-1 );
++ testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE );
++ testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE+1 );
+
+- /* If work was actually accomplished... */
- if( rc==SQLITE_OK ){
-- pInfo->nBackfill = mxSafeFrame;
-+ /* If nTruncate is non-zero, this is a commit record. */
-+ if( nTruncate ){
-+ pWal->hdr.mxFrame = iFrame;
-+ pWal->hdr.nPage = nTruncate;
-+ pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
-+ testcase( szPage<=32768 );
-+ testcase( szPage>=65536 );
-+ aFrameCksum[0] = pWal->hdr.aFrameCksum[0];
-+ aFrameCksum[1] = pWal->hdr.aFrameCksum[1];
- }
- }
+- if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
+- i64 szDb = pWal->hdr.nPage*(i64)szPage;
+- testcase( IS_BIG_INT(szDb) );
+- rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
+- if( rc==SQLITE_OK && sync_flags ){
+- rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
+- }
+- }
+- if( rc==SQLITE_OK ){
+- pInfo->nBackfill = mxSafeFrame;
+- }
+- }
++ if( pWal->hdr.mxFrame==0 ) return;
-- /* Release the reader lock held while backfilling */
-- walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
-+ sqlite3_free(aFrame);
- }
+- /* Release the reader lock held while backfilling */
+- walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
+- }
++ /* Obtain pointers to the hash-table and page-number array containing
++ ** the entry that corresponds to frame pWal->hdr.mxFrame. It is guaranteed
++ ** that the page said hash-table and array reside on is already mapped.
++ */
++ assert( pWal->nWiData>walFramePage(pWal->hdr.mxFrame) );
++ assert( pWal->apWiData[walFramePage(pWal->hdr.mxFrame)] );
++ walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &aHash, &aPgno, &iZero);
-- if( rc==SQLITE_BUSY ){
-- /* Reset the return code so as not to report a checkpoint failure
-- ** just because there are active readers. */
-- rc = SQLITE_OK;
-- }
-+finished:
-+ if( rc==SQLITE_OK ){
-+ volatile WalCkptInfo *pInfo;
-+ int i;
-+ pWal->hdr.aFrameCksum[0] = aFrameCksum[0];
-+ pWal->hdr.aFrameCksum[1] = aFrameCksum[1];
-+ walIndexWriteHdr(pWal);
+- if( rc==SQLITE_BUSY ){
+- /* Reset the return code so as not to report a checkpoint failure
+- ** just because there are active readers. */
+- rc = SQLITE_OK;
++ /* Zero all hash-table entries that correspond to frame numbers greater
++ ** than pWal->hdr.mxFrame.
++ */
++ iLimit = pWal->hdr.mxFrame - iZero;
++ assert( iLimit>0 );
++ for(i=0; i<HASHTABLE_NSLOT; i++){
++ if( aHash[i]>iLimit ){
++ aHash[i] = 0;
+ }
+ }
++
++ /* Zero the entries in the aPgno array that correspond to frames with
++ ** frame numbers greater than pWal->hdr.mxFrame.
++ */
++ nByte = (int)((char *)aHash - (char *)&aPgno[iLimit+1]);
++ memset((void *)&aPgno[iLimit+1], 0, nByte);
-- /* If this is an SQLITE_CHECKPOINT_RESTART operation, and the entire wal
-- ** file has been copied into the database file, then block until all
-- ** readers have finished using the wal file. This ensures that the next
-- ** process to write to the database restarts the wal file.
-- */
+- /* If this is an SQLITE_CHECKPOINT_RESTART or TRUNCATE operation, and the
+- ** entire wal file has been copied into the database file, then block
+- ** until all readers have finished using the wal file. This ensures that
+- ** the next process to write to the database restarts the wal file.
++#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
++ /* Verify that the every entry in the mapping region is still reachable
++ ** via the hash table even after the cleanup.
+ */
- if( rc==SQLITE_OK && eMode!=SQLITE_CHECKPOINT_PASSIVE ){
- assert( pWal->writeLock );
- if( pInfo->nBackfill<pWal->hdr.mxFrame ){
- rc = SQLITE_BUSY;
-- }else if( eMode==SQLITE_CHECKPOINT_RESTART ){
-- assert( mxSafeFrame==pWal->hdr.mxFrame );
+- }else if( eMode>=SQLITE_CHECKPOINT_RESTART ){
+- u32 salt1;
+- sqlite3_randomness(4, &salt1);
+- assert( pInfo->nBackfill==pWal->hdr.mxFrame );
- rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(1), WAL_NREADER-1);
- if( rc==SQLITE_OK ){
+- if( eMode==SQLITE_CHECKPOINT_TRUNCATE ){
+- /* IMPLEMENTATION-OF: R-44699-57140 This mode works the same way as
+- ** SQLITE_CHECKPOINT_RESTART with the addition that it also
+- ** truncates the log file to zero bytes just prior to a
+- ** successful return.
+- **
+- ** In theory, it might be safe to do this without updating the
+- ** wal-index header in shared memory, as all subsequent reader or
+- ** writer clients should see that the entire log file has been
+- ** checkpointed and behave accordingly. This seems unsafe though,
+- ** as it would leave the system in a state where the contents of
+- ** the wal-index header do not match the contents of the
+- ** file-system. To avoid this, update the wal-index header to
+- ** indicate that the log file contains zero valid frames. */
+- walRestartHdr(pWal, salt1);
+- rc = sqlite3OsTruncate(pWal->pWalFd, 0);
+- }
- walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
-- }
-+ /* Reset the checkpoint-header. This is safe because this thread is
-+ ** currently holding locks that exclude all other readers, writers and
-+ ** checkpointers.
-+ */
-+ pInfo = walCkptInfo(pWal);
-+ pInfo->nBackfill = 0;
-+ pInfo->aReadMark[0] = 0;
-+ for(i=1; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
-+ if( pWal->hdr.mxFrame ) pInfo->aReadMark[1] = pWal->hdr.mxFrame;
-+
-+ /* If more than one frame was recovered from the log file, report an
-+ ** event via sqlite3_log(). This is to help with identifying performance
-+ ** problems caused by applications routinely shutting down without
-+ ** checkpointing the log file.
-+ */
-+ if( pWal->hdr.nPage ){
-+ sqlite3_log(SQLITE_NOTICE_RECOVER_WAL,
-+ "recovered %d frames from WAL file %s",
-+ pWal->hdr.mxFrame, pWal->zWalName
-+ );
++ if( iLimit ){
++ int i; /* Loop counter */
++ int iKey; /* Hash key */
++ for(i=1; i<=iLimit; i++){
++ for(iKey=walHash(aPgno[i]); aHash[iKey]; iKey=walNextHash(iKey)){
++ if( aHash[iKey]==i ) break;
+ }
++ assert( aHash[iKey]==i );
}
}
-
+-
- walcheckpoint_out:
- walIteratorFree(pIter);
-+recovery_error:
-+ WALTRACE(("WAL%p: recovery %s\n", pWal, rc ? "failed" : "ok"));
-+ walUnlockExclusive(pWal, iLock, nLock);
- return rc;
+- return rc;
++#endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */
}
- /*
+-/*
-** If the WAL file is currently larger than nMax bytes in size, truncate
-** it to exactly nMax bytes. If an error occurs while doing so, ignore it.
-*/
@@ -6517,10 +39959,11 @@
- sqlite3_log(rx, "cannot limit WAL size: %s", pWal->zWalName);
- }
-}
--
--/*
+
+ /*
-** Close a connection to a log file.
-+** Close an open wal-index.
++** Set an entry in the wal-index that will map database page number
++** pPage into WAL frame iFrame.
*/
-SQLITE_PRIVATE int sqlite3WalClose(
- Wal *pWal, /* Wal to close */
@@ -6531,7 +39974,12 @@
- int rc = SQLITE_OK;
- if( pWal ){
- int isDelete = 0; /* True to unlink wal and wal-index files */
--
++static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
++ int rc; /* Return code */
++ u32 iZero = 0; /* One less than frame number of aPgno[1] */
++ volatile u32 *aPgno = 0; /* Page number array */
++ volatile ht_slot *aHash = 0; /* Hash table */
+
- /* 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
@@ -6539,7 +39987,22 @@
- ** the wal and wal-index files.
- **
- ** The EXCLUSIVE lock is not released before returning.
-- */
++ rc = walHashGet(pWal, walFramePage(iFrame), &aHash, &aPgno, &iZero);
++
++ /* Assuming the wal-index file was successfully mapped, populate the
++ ** page number array and hash table entry.
++ */
++ if( rc==SQLITE_OK ){
++ int iKey; /* Hash table key */
++ int idx; /* Value to write to hash-table slot */
++ int nCollide; /* Number of hash collisions */
++
++ idx = iFrame - iZero;
++ assert( idx <= HASHTABLE_NSLOT/2 + 1 );
++
++ /* If this is the first entry to be added to this hash-table, zero the
++ ** entire hash table and aPgno[] array before proceeding.
+ */
- rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE);
- if( rc==SQLITE_OK ){
- if( pWal->exclusiveMode==WAL_NORMAL_MODE ){
@@ -6568,31 +40031,73 @@
- walLimitSize(pWal, 0);
- }
- }
-- }
--
++ if( idx==1 ){
++ int nByte = (int)((u8 *)&aHash[HASHTABLE_NSLOT] - (u8 *)&aPgno[1]);
++ memset((void*)&aPgno[1], 0, nByte);
++ }
++
++ /* If the entry in aPgno[] is already set, then the previous writer
++ ** must have exited unexpectedly in the middle of a transaction (after
++ ** writing one or more dirty pages to the WAL to free up memory).
++ ** Remove the remnants of that writers uncommitted transaction from
++ ** the hash-table before writing any new entries.
++ */
++ if( aPgno[idx] ){
++ walCleanupHash(pWal);
++ assert( !aPgno[idx] );
++ }
++
++ /* Write the aPgno[] array entry and the hash-table slot. */
++ nCollide = idx;
++ for(iKey=walHash(iPage); aHash[iKey]; iKey=walNextHash(iKey)){
++ if( (nCollide--)==0 ) return SQLITE_CORRUPT_BKPT;
+ }
++ aPgno[idx] = iPage;
++ aHash[iKey] = (ht_slot)idx;
+
- walIndexClose(pWal, isDelete);
- sqlite3OsClose(pWal->pWalFd);
- if( isDelete ){
- sqlite3BeginBenignMalloc();
- sqlite3OsDelete(pWal->pVfs, pWal->zWalName, 0);
- sqlite3EndBenignMalloc();
-+static void walIndexClose(Wal *pWal, int isDelete){
-+ if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){
-+ int i;
-+ for(i=0; i<pWal->nWiData; i++){
-+ sqlite3_free((void *)pWal->apWiData[i]);
-+ pWal->apWiData[i] = 0;
++#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
++ /* Verify that the number of entries in the hash table exactly equals
++ ** the number of entries in the mapping region.
++ */
++ {
++ int i; /* Loop counter */
++ int nEntry = 0; /* Number of entries in the hash table */
++ for(i=0; i<HASHTABLE_NSLOT; i++){ if( aHash[i] ) nEntry++; }
++ assert( nEntry==idx );
}
- WALTRACE(("WAL%p: closed\n", pWal));
- sqlite3_free((void *)pWal->apWiData);
- sqlite3_free(pWal);
-+ }else{
-+ sqlite3OsShmUnmap(pWal->pDbFd, isDelete);
++
++ /* Verify that the every entry in the mapping region is reachable
++ ** via the hash table. This turns out to be a really, really expensive
++ ** thing to check, so only do this occasionally - not on every
++ ** iteration.
++ */
++ if( (idx&0x3ff)==0 ){
++ int i; /* Loop counter */
++ for(i=1; i<=idx; i++){
++ for(iKey=walHash(aPgno[i]); aHash[iKey]; iKey=walNextHash(iKey)){
++ if( aHash[iKey]==i ) break;
++ }
++ assert( aHash[iKey]==i );
++ }
++ }
++#endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */
}
-- return rc;
++
++
+ return rc;
}
--/*
++
+ /*
-** Try to read the wal-index header. Return 0 on success and 1 if
-** there is a problem.
-**
@@ -6601,46 +40106,34 @@
-** read it, which might result in inconsistency. A dirty read is detected
-** by verifying that both copies of the header are the same and also by
-** a checksum on the header.
-+/*
-+** Open a connection to the WAL file zWalName. The database file must
-+** already be opened on connection pDbFd. The buffer that zWalName points
-+** to must remain valid for the lifetime of the returned Wal* handle.
- **
+-**
-** If and only if the read is consistent and the header is different from
-** pWal->hdr, then pWal->hdr is updated to the content of the new header
-** and *pChanged is set to 1.
-+** A SHARED lock should be held on the database file when this function
-+** is called. The purpose of this SHARED lock is to prevent any other
-+** client from unlinking the WAL or wal-index file. If another process
-+** were to do this just after this client opened one of these files, the
-+** system would be badly broken.
++** Recover the wal-index by reading the write-ahead log file.
**
-** If the checksum cannot be verified return non-zero. If the header
-** is read successfully and the checksum verified, return zero.
-+** If the log file is successfully opened, SQLITE_OK is returned and
-+** *ppWal is set to point to a new WAL handle. If an error occurs,
-+** an SQLite error code is returned and *ppWal is left unmodified.
++** This routine first tries to establish an exclusive lock on the
++** wal-index to prevent other threads/processes from doing anything
++** with the WAL or wal-index while recovery is running. The
++** WAL_RECOVER_LOCK is also held so that other threads will know
++** that this thread is running recovery. If unable to establish
++** the necessary locks, this routine returns SQLITE_BUSY.
*/
-static int walIndexTryHdr(Wal *pWal, int *pChanged){
- u32 aCksum[2]; /* Checksum on the header content */
- WalIndexHdr h1, h2; /* Two copies of the header content */
- WalIndexHdr volatile *aHdr; /* Header in shared memory */
-+SQLITE_PRIVATE int sqlite3WalOpen(
-+ sqlite3_vfs *pVfs, /* vfs module to open wal and wal-index */
-+ sqlite3_file *pDbFd, /* The open database file */
-+ const char *zWalName, /* Name of the WAL file */
-+ int bNoShm, /* True to run in heap-memory mode */
-+ i64 mxWalSize, /* Truncate WAL to this size on reset */
-+ Wal **ppWal /* OUT: Allocated Wal handle */
-+){
-+ int rc; /* Return Code */
-+ Wal *pRet; /* Object to allocate and return */
-+ int flags; /* Flags passed to OsOpen() */
-
+-
- /* The first page of the wal-index must be mapped at this point. */
- assert( pWal->nWiData>0 && pWal->apWiData[0] );
-+ assert( zWalName && zWalName[0] );
-+ assert( pDbFd );
++static int walIndexRecover(Wal *pWal){
++ int rc; /* Return Code */
++ i64 nSize; /* Size of log file */
++ u32 aFrameCksum[2] = {0, 0};
++ int iLock; /* Lock offset to lock for checkpoint */
++ int nLock; /* Number of locks to hold */
- /* Read the header. This might happen concurrently with a write to the
- ** same area of shared memory on a different CPU in a SMP,
@@ -6651,53 +40144,37 @@
- ** When reading, read [0] first then [1]. Writes are in the reverse order.
- ** Memory barriers are used to prevent the compiler or the hardware from
- ** reordering the reads and writes.
-+ /* In the amalgamation, the os_unix.c and os_win.c source files come before
-+ ** this source file. Verify that the #defines of the locking byte offsets
-+ ** in os_unix.c and os_win.c agree with the WALINDEX_LOCK_OFFSET value.
++ /* Obtain an exclusive lock on all byte in the locking range not already
++ ** locked by the caller. The caller is guaranteed to have locked the
++ ** WAL_WRITE_LOCK byte, and may have also locked the WAL_CKPT_LOCK byte.
++ ** If successful, the same bytes that are locked here are unlocked before
++ ** this function returns.
*/
- aHdr = walIndexHdr(pWal);
- memcpy(&h1, (void *)&aHdr[0], sizeof(h1));
- walShmBarrier(pWal);
- memcpy(&h2, (void *)&aHdr[1], sizeof(h2));
-+#ifdef WIN_SHM_BASE
-+ assert( WIN_SHM_BASE==WALINDEX_LOCK_OFFSET );
-+#endif
-+#ifdef UNIX_SHM_BASE
-+ assert( UNIX_SHM_BASE==WALINDEX_LOCK_OFFSET );
-+#endif
-
+-
- if( memcmp(&h1, &h2, sizeof(h1))!=0 ){
- return 1; /* Dirty read */
- }
- if( h1.isInit==0 ){
- return 1; /* Malformed header - probably all zeros */
-+
-+ /* Allocate an instance of struct Wal to return. */
-+ *ppWal = 0;
-+ pRet = (Wal*)sqlite3MallocZero(sizeof(Wal) + pVfs->szOsFile);
-+ if( !pRet ){
-+ return SQLITE_NOMEM;
- }
+- }
- walChecksumBytes(1, (u8*)&h1, sizeof(h1)-sizeof(h1.aCksum), 0, aCksum);
- if( aCksum[0]!=h1.aCksum[0] || aCksum[1]!=h1.aCksum[1] ){
- return 1; /* Checksum does not match */
-+
-+ pRet->pVfs = pVfs;
-+ pRet->pWalFd = (sqlite3_file *)&pRet[1];
-+ pRet->pDbFd = pDbFd;
-+ pRet->readLock = -1;
-+ pRet->mxWalSize = mxWalSize;
-+ pRet->zWalName = zWalName;
-+ pRet->syncHeader = 1;
-+ pRet->padToSectorBoundary = 1;
-+ pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE);
-+
-+ /* Open file handle on the write-ahead log file. */
-+ flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL);
-+ rc = sqlite3OsOpen(pVfs, zWalName, pRet->pWalFd, flags, &flags);
-+ if( rc==SQLITE_OK && flags&SQLITE_OPEN_READONLY ){
-+ pRet->readOnly = WAL_RDONLY;
++ assert( pWal->ckptLock==1 || pWal->ckptLock==0 );
++ assert( WAL_ALL_BUT_WRITE==WAL_WRITE_LOCK+1 );
++ assert( WAL_CKPT_LOCK==WAL_ALL_BUT_WRITE );
++ assert( pWal->writeLock );
++ iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock;
++ nLock = SQLITE_SHM_NLOCK - iLock;
++ rc = walLockExclusive(pWal, iLock, nLock, 0);
++ if( rc ){
++ return rc;
}
++ WALTRACE(("WAL%p: recovery begin...\n", pWal));
- if( memcmp(&pWal->hdr, &h1, sizeof(WalIndexHdr)) ){
- *pChanged = 1;
@@ -6705,55 +40182,50 @@
- pWal->szPage = (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16);
- testcase( pWal->szPage<=32768 );
- testcase( pWal->szPage>=65536 );
++ memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
++
++ rc = sqlite3OsFileSize(pWal->pWalFd, &nSize);
+ if( rc!=SQLITE_OK ){
-+ walIndexClose(pRet, 0);
-+ sqlite3OsClose(pRet->pWalFd);
-+ sqlite3_free(pRet);
-+ }else{
-+ int iDC = sqlite3OsDeviceCharacteristics(pDbFd);
-+ if( iDC & SQLITE_IOCAP_SEQUENTIAL ){ pRet->syncHeader = 0; }
-+ if( iDC & SQLITE_IOCAP_POWERSAFE_OVERWRITE ){
-+ pRet->padToSectorBoundary = 0;
-+ }
-+ *ppWal = pRet;
-+ WALTRACE(("WAL%d: opened\n", pRet));
++ goto recovery_error;
}
-+ return rc;
-+}
- /* The header was successfully read. Return zero. */
- return 0;
-+/*
-+** Change the size to which the WAL file is trucated on each reset.
-+*/
-+SQLITE_PRIVATE void sqlite3WalLimit(Wal *pWal, i64 iLimit){
-+ if( pWal ) pWal->mxWalSize = iLimit;
- }
+-}
++ if( nSize>WAL_HDRSIZE ){
++ u8 aBuf[WAL_HDRSIZE]; /* Buffer to load WAL header into */
++ u8 *aFrame = 0; /* Malloc'd buffer to load entire frame */
++ int szFrame; /* Number of bytes in buffer aFrame[] */
++ u8 *aData; /* Pointer to data part of aFrame buffer */
++ int iFrame; /* Index of last frame read */
++ i64 iOffset; /* Next offset to read from log file */
++ int szPage; /* Page size according to the log */
++ u32 magic; /* Magic value read from WAL header */
++ u32 version; /* Magic value read from WAL header */
++ int isValid; /* True if this frame is valid */
- /*
+-/*
-** Read the wal-index header from the wal-index and into pWal->hdr.
-** If the wal-header appears to be corrupt, try to reconstruct the
-** wal-index from the WAL before returning.
-**
-** Set *pChanged to 1 if the wal-index header value in pWal->hdr is
--** changed by this opertion. If pWal->hdr is unchanged, set *pChanged
+-** changed by this operation. If pWal->hdr is unchanged, set *pChanged
-** to 0.
-+** Find the smallest page number out of all pages held in the WAL that
-+** has not been returned by any prior invocation of this method on the
-+** same WalIterator object. Write into *piFrame the frame index where
-+** that page was last written into the WAL. Write into *piPage the page
-+** number.
- **
+-**
-** If the wal-index header is successfully read, return SQLITE_OK.
-** Otherwise an SQLite error code.
-+** Return 0 on success. If there are no pages in the WAL with a page
-+** number larger than *piPage, then return 1.
- */
+-*/
-static int walIndexReadHdr(Wal *pWal, int *pChanged){
- int rc; /* Return code */
- int badHdr; /* True if a header read failed */
- volatile u32 *page0; /* Chunk of wal-index containing header */
--
++ /* Read in the WAL header. */
++ rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0);
++ if( rc!=SQLITE_OK ){
++ goto recovery_error;
++ }
+
- /* Ensure that page 0 of the wal-index (the page that contains the
- ** wal-index header) is mapped. Return early if an error occurs here.
- */
@@ -6763,21 +40235,40 @@
- return rc;
- };
- assert( page0 || pWal->writeLock==0 );
--
++ /* If the database page size is not a power of two, or is greater than
++ ** SQLITE_MAX_PAGE_SIZE, conclude that the WAL file contains no valid
++ ** data. Similarly, if the 'magic' value is invalid, ignore the whole
++ ** WAL file.
++ */
++ magic = sqlite3Get4byte(&aBuf[0]);
++ szPage = sqlite3Get4byte(&aBuf[8]);
++ if( (magic&0xFFFFFFFE)!=WAL_MAGIC
++ || szPage&(szPage-1)
++ || szPage>SQLITE_MAX_PAGE_SIZE
++ || szPage<512
++ ){
++ goto finished;
++ }
++ pWal->hdr.bigEndCksum = (u8)(magic&0x00000001);
++ pWal->szPage = szPage;
++ pWal->nCkpt = sqlite3Get4byte(&aBuf[12]);
++ memcpy(&pWal->hdr.aSalt, &aBuf[16], 8);
+
- /* If the first page of the wal-index has been mapped, try to read the
- ** wal-index header immediately, without holding any lock. This usually
- ** works, but may fail if the wal-index header is corrupt or currently
- ** being modified by another thread or process.
- */
- badHdr = (page0 ? walIndexTryHdr(pWal, pChanged) : 1);
-+static int walIteratorNext(
-+ WalIterator *p, /* Iterator */
-+ u32 *piPage, /* OUT: The page number of the next page */
-+ u32 *piFrame /* OUT: Wal frame index of next page */
-+){
-+ u32 iMin; /* Result pgno must be greater than iMin */
-+ u32 iRet = 0xFFFFFFFF; /* 0xffffffff is never a valid page number */
-+ int i; /* For looping through segments */
++ /* Verify that the WAL header checksum is correct */
++ walChecksumBytes(pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN,
++ aBuf, WAL_HDRSIZE-2*4, 0, pWal->hdr.aFrameCksum
++ );
++ if( pWal->hdr.aFrameCksum[0]!=sqlite3Get4byte(&aBuf[24])
++ || pWal->hdr.aFrameCksum[1]!=sqlite3Get4byte(&aBuf[28])
++ ){
++ goto finished;
++ }
- /* If the first attempt failed, it might have been due to a race
- ** with a writer. So get a WRITE lock and try again.
@@ -6789,7 +40280,7 @@
- walUnlockShared(pWal, WAL_WRITE_LOCK);
- rc = SQLITE_READONLY_RECOVERY;
- }
-- }else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){
+- }else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1, 1)) ){
- pWal->writeLock = 1;
- if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
- badHdr = walIndexTryHdr(pWal, pChanged);
@@ -6800,80 +40291,55 @@
- */
- rc = walIndexRecover(pWal);
- *pChanged = 1;
-+ iMin = p->iPrior;
-+ assert( iMin<0xffffffff );
-+ for(i=p->nSegment-1; i>=0; i--){
-+ struct WalSegment *pSegment = &p->aSegment[i];
-+ while( pSegment->iNext<pSegment->nEntry ){
-+ u32 iPg = pSegment->aPgno[pSegment->aIndex[pSegment->iNext]];
-+ if( iPg>iMin ){
-+ if( iPg<iRet ){
-+ iRet = iPg;
-+ *piFrame = pSegment->iZero + pSegment->aIndex[pSegment->iNext];
- }
-+ break;
- }
-- pWal->writeLock = 0;
-- walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
-+ pSegment->iNext++;
+- }
++ /* Verify that the version number on the WAL format is one that
++ ** are able to understand */
++ version = sqlite3Get4byte(&aBuf[4]);
++ if( version!=WAL_MAX_VERSION ){
++ rc = SQLITE_CANTOPEN_BKPT;
++ goto finished;
+ }
-+ }
+
-+ *piPage = p->iPrior = iRet;
-+ return (iRet==0xFFFFFFFF);
-+}
++ /* Malloc a buffer to read frames into. */
++ szFrame = szPage + WAL_FRAME_HDRSIZE;
++ aFrame = (u8 *)sqlite3_malloc64(szFrame);
++ if( !aFrame ){
++ rc = SQLITE_NOMEM;
++ goto recovery_error;
++ }
++ aData = &aFrame[WAL_FRAME_HDRSIZE];
+
-+/*
-+** This function merges two sorted lists into a single sorted list.
-+**
-+** aLeft[] and aRight[] are arrays of indices. The sort key is
-+** aContent[aLeft[]] and aContent[aRight[]]. Upon entry, the following
-+** is guaranteed for all J<K:
-+**
-+** aContent[aLeft[J]] < aContent[aLeft[K]]
-+** aContent[aRight[J]] < aContent[aRight[K]]
-+**
-+** This routine overwrites aRight[] with a new (probably longer) sequence
-+** of indices such that the aRight[] contains every index that appears in
-+** either aLeft[] or the old aRight[] and such that the second condition
-+** above is still met.
-+**
-+** The aContent[aLeft[X]] values will be unique for all X. And the
-+** aContent[aRight[X]] values will be unique too. But there might be
-+** one or more combinations of X and Y such that
-+**
-+** aLeft[X]!=aRight[Y] && aContent[aLeft[X]] == aContent[aRight[Y]]
-+**
-+** When that happens, omit the aLeft[X] and use the aRight[Y] index.
-+*/
-+static void walMerge(
-+ const u32 *aContent, /* Pages in wal - keys for the sort */
-+ ht_slot *aLeft, /* IN: Left hand input list */
-+ int nLeft, /* IN: Elements in array *paLeft */
-+ ht_slot **paRight, /* IN/OUT: Right hand input list */
-+ int *pnRight, /* IN/OUT: Elements in *paRight */
-+ ht_slot *aTmp /* Temporary buffer */
-+){
-+ int iLeft = 0; /* Current index in aLeft */
-+ int iRight = 0; /* Current index in aRight */
-+ int iOut = 0; /* Current index in output buffer */
-+ int nRight = *pnRight;
-+ ht_slot *aRight = *paRight;
++ /* Read all frames from the log file. */
++ iFrame = 0;
++ for(iOffset=WAL_HDRSIZE; (iOffset+szFrame)<=nSize; iOffset+=szFrame){
++ u32 pgno; /* Database page number for frame */
++ u32 nTruncate; /* dbsize field from frame header */
+
-+ assert( nLeft>0 && nRight>0 );
-+ while( iRight<nRight || iLeft<nLeft ){
-+ ht_slot logpage;
-+ Pgno dbpage;
++ /* Read and decode the next log frame. */
++ iFrame++;
++ rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset);
++ if( rc!=SQLITE_OK ) break;
++ isValid = walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame);
++ if( !isValid ) break;
++ rc = walIndexAppend(pWal, iFrame, pgno);
++ if( rc!=SQLITE_OK ) break;
+
-+ if( (iLeft<nLeft)
-+ && (iRight>=nRight || aContent[aLeft[iLeft]]<aContent[aRight[iRight]])
-+ ){
-+ logpage = aLeft[iLeft++];
-+ }else{
-+ logpage = aRight[iRight++];
++ /* If nTruncate is non-zero, this is a commit record. */
++ if( nTruncate ){
++ pWal->hdr.mxFrame = iFrame;
++ pWal->hdr.nPage = nTruncate;
++ pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
++ testcase( szPage<=32768 );
++ testcase( szPage>=65536 );
++ aFrameCksum[0] = pWal->hdr.aFrameCksum[0];
++ aFrameCksum[1] = pWal->hdr.aFrameCksum[1];
+ }
+- pWal->writeLock = 0;
+- walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
}
-- }
-+ dbpage = aContent[logpage];
++
++ sqlite3_free(aFrame);
+ }
- /* If the header is read successfully, check the version number to make
- ** sure the wal-index was not constructed with some future format that
@@ -6881,39 +40347,70 @@
- */
- if( badHdr==0 && pWal->hdr.iVersion!=WALINDEX_MAX_VERSION ){
- rc = SQLITE_CANTOPEN_BKPT;
-+ aTmp[iOut++] = logpage;
-+ if( iLeft<nLeft && aContent[aLeft[iLeft]]==dbpage ) iLeft++;
++finished:
++ if( rc==SQLITE_OK ){
++ volatile WalCkptInfo *pInfo;
++ int i;
++ pWal->hdr.aFrameCksum[0] = aFrameCksum[0];
++ pWal->hdr.aFrameCksum[1] = aFrameCksum[1];
++ walIndexWriteHdr(pWal);
+
-+ assert( iLeft>=nLeft || aContent[aLeft[iLeft]]>dbpage );
-+ assert( iRight>=nRight || aContent[aRight[iRight]]>dbpage );
++ /* Reset the checkpoint-header. This is safe because this thread is
++ ** currently holding locks that exclude all other readers, writers and
++ ** checkpointers.
++ */
++ pInfo = walCkptInfo(pWal);
++ pInfo->nBackfill = 0;
++ pInfo->aReadMark[0] = 0;
++ for(i=1; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
++ if( pWal->hdr.mxFrame ) pInfo->aReadMark[1] = pWal->hdr.mxFrame;
++
++ /* If more than one frame was recovered from the log file, report an
++ ** event via sqlite3_log(). This is to help with identifying performance
++ ** problems caused by applications routinely shutting down without
++ ** checkpointing the log file.
++ */
++ if( pWal->hdr.nPage ){
++ sqlite3_log(SQLITE_NOTICE_RECOVER_WAL,
++ "recovered %d frames from WAL file %s",
++ pWal->hdr.mxFrame, pWal->zWalName
++ );
++ }
}
-- return rc;
-+ *paRight = aLeft;
-+ *pnRight = iOut;
-+ memcpy(aLeft, aTmp, sizeof(aTmp[0])*iOut);
++recovery_error:
++ WALTRACE(("WAL%p: recovery %s\n", pWal, rc ? "failed" : "ok"));
++ walUnlockExclusive(pWal, iLock, nLock);
+ return rc;
}
/*
-** This is the value that walTryBeginRead returns when it needs to
-** be retried.
--*/
++** Close an open wal-index.
+ */
-#define WAL_RETRY (-1)
--
++static void walIndexClose(Wal *pWal, int isDelete){
++ if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){
++ int i;
++ for(i=0; i<pWal->nWiData; i++){
++ sqlite3_free((void *)pWal->apWiData[i]);
++ pWal->apWiData[i] = 0;
++ }
++ }else{
++ sqlite3OsShmUnmap(pWal->pDbFd, isDelete);
++ }
++}
+
-/*
-** Attempt to start a read transaction. This might fail due to a race or
-** other transient condition. When that happens, it returns WAL_RETRY to
-** indicate to the caller that it is safe to retry immediately.
-+** Sort the elements in list aList using aContent[] as the sort key.
-+** Remove elements with duplicate keys, preferring to keep the
-+** larger aList[] values.
- **
+-**
-** On success return SQLITE_OK. On a permanent failure (such an
-** I/O error or an SQLITE_BUSY because another process is running
-** recovery) return a positive error code.
-+** The aList[] entries are indices into aContent[]. The values in
-+** aList[] are to be sorted so that for all J<K:
- **
+-**
-** The useWal parameter is true to force the use of the WAL and disable
-** the case where the WAL is bypassed because it has been completely
-** checkpointed. If useWal==0 then this routine calls walIndexReadHdr()
@@ -6922,8 +40419,7 @@
-** to the caller that the local paget cache is obsolete and needs to be
-** flushed.) When useWal==1, the wal-index header is assumed to already
-** be loaded and the pChanged parameter is unused.
-+** aContent[aList[J]] < aContent[aList[K]]
- **
+-**
-** The caller must set the cnt parameter to the number of prior calls to
-** this routine during the current read attempt that returned WAL_RETRY.
-** This routine will start taking more aggressive measures to clear the
@@ -6934,7 +40430,10 @@
-** chance that SQLITE_PROTOCOL could be returned because of a run of really
-** bad luck when there is lots of contention for the wal-index, but that
-** possibility is so small that it can be safely neglected, we believe.
-+** For any X and Y such that
++/*
++** Open a connection to the WAL file zWalName. The database file must
++** already be opened on connection pDbFd. The buffer that zWalName points
++** to must remain valid for the lifetime of the returned Wal* handle.
**
-** On success, this routine obtains a read lock on
-** WAL_READ_LOCK(pWal->readLock). The pWal->readLock integer is
@@ -6949,7 +40448,11 @@
-** this routine will always set pWal->readLock>0 on success.
-** When the read transaction is completed, the caller must release the
-** lock on WAL_READ_LOCK(pWal->readLock) and set pWal->readLock to -1.
-+** aContent[aList[X]] == aContent[aList[Y]]
++** A SHARED lock should be held on the database file when this function
++** is called. The purpose of this SHARED lock is to prevent any other
++** client from unlinking the WAL or wal-index file. If another process
++** were to do this just after this client opened one of these files, the
++** system would be badly broken.
**
-** This routine uses the nBackfill and aReadMark[] fields of the header
-** to select a particular WAL_READ_LOCK() that strives to let the
@@ -6957,8 +40460,9 @@
-** update values of the aReadMark[] array in the header, but if it does
-** so it takes care to hold an exclusive lock on the corresponding
-** WAL_READ_LOCK() while changing values.
-+** Keep the larger of the two values aList[X] and aList[Y] and discard
-+** the smaller.
++** If the log file is successfully opened, SQLITE_OK is returned and
++** *ppWal is set to point to a new WAL handle. If an error occurs,
++** an SQLite error code is returned and *ppWal is left unmodified.
*/
-static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
- volatile WalCkptInfo *pInfo; /* Checkpoint information in wal-index */
@@ -6966,24 +40470,21 @@
- int mxI; /* Index of largest aReadMark[] value */
- int i; /* Loop counter */
- int rc = SQLITE_OK; /* Return code */
-+static void walMergesort(
-+ const u32 *aContent, /* Pages in wal */
-+ ht_slot *aBuffer, /* Buffer of at least *pnList items to use */
-+ ht_slot *aList, /* IN/OUT: List to sort */
-+ int *pnList /* IN/OUT: Number of elements in aList[] */
++SQLITE_PRIVATE int sqlite3WalOpen(
++ sqlite3_vfs *pVfs, /* vfs module to open wal and wal-index */
++ sqlite3_file *pDbFd, /* The open database file */
++ const char *zWalName, /* Name of the WAL file */
++ int bNoShm, /* True to run in heap-memory mode */
++ i64 mxWalSize, /* Truncate WAL to this size on reset */
++ Wal **ppWal /* OUT: Allocated Wal handle */
+){
-+ struct Sublist {
-+ int nList; /* Number of elements in aList */
-+ ht_slot *aList; /* Pointer to sub-list content */
-+ };
++ int rc; /* Return Code */
++ Wal *pRet; /* Object to allocate and return */
++ int flags; /* Flags passed to OsOpen() */
- assert( pWal->readLock<0 ); /* Not currently locked */
-+ const int nList = *pnList; /* Size of input list */
-+ int nMerge = 0; /* Number of elements in list aMerge */
-+ ht_slot *aMerge = 0; /* List to be merged */
-+ int iList; /* Index into input list */
-+ int iSub = 0; /* Index into aSub array */
-+ struct Sublist aSub[13]; /* Array of sub-lists */
++ assert( zWalName && zWalName[0] );
++ assert( pDbFd );
- /* Take steps to avoid spinning forever if there is a protocol error.
- **
@@ -7001,7 +40502,10 @@
- ** an subsequent retries, the delays start becoming longer and longer,
- ** so that on the 100th (and last) RETRY we delay for 323 milliseconds.
- ** The total delay time before giving up is less than 10 seconds.
-- */
++ /* In the amalgamation, the os_unix.c and os_win.c source files come before
++ ** this source file. Verify that the #defines of the locking byte offsets
++ ** in os_unix.c and os_win.c agree with the WALINDEX_LOCK_OFFSET value.
+ */
- if( cnt>5 ){
- int nDelay = 1; /* Pause time in microseconds */
- if( cnt>100 ){
@@ -7011,9 +40515,12 @@
- if( cnt>=10 ) nDelay = (cnt-9)*(cnt-9)*39;
- sqlite3OsSleep(pWal->pVfs, nDelay);
- }
-+ memset(aSub, 0, sizeof(aSub));
-+ assert( nList<=HASHTABLE_NPAGE && nList>0 );
-+ assert( HASHTABLE_NPAGE==(1<<(ArraySize(aSub)-1)) );
++#ifdef WIN_SHM_BASE
++ assert( WIN_SHM_BASE==WALINDEX_LOCK_OFFSET );
++#endif
++#ifdef UNIX_SHM_BASE
++ assert( UNIX_SHM_BASE==WALINDEX_LOCK_OFFSET );
++#endif
- if( !useWal ){
- rc = walIndexReadHdr(pWal, pChanged);
@@ -7044,18 +40551,8 @@
- }
- if( rc!=SQLITE_OK ){
- return rc;
-+ for(iList=0; iList<nList; iList++){
-+ nMerge = 1;
-+ aMerge = &aList[iList];
-+ for(iSub=0; iList & (1<<iSub); iSub++){
-+ struct Sublist *p = &aSub[iSub];
-+ assert( p->aList && p->nList<=(1<<iSub) );
-+ assert( p->aList==&aList[iList&~((2<<iSub)-1)] );
-+ walMerge(aContent, p->aList, p->nList, &aMerge, &nMerge, aBuffer);
- }
-+ aSub[iSub].aList = aMerge;
-+ aSub[iSub].nList = nMerge;
- }
+- }
+- }
- pInfo = walCkptInfo(pWal);
- if( !useWal && pInfo->nBackfill==pWal->hdr.mxFrame ){
@@ -7070,7 +40567,7 @@
- ** may have been appended to the log before READ_LOCK(0) was obtained.
- ** When holding READ_LOCK(0), the reader ignores the entire log file,
- ** which implies that the database file contains a trustworthy
-- ** snapshoT. Since holding READ_LOCK(0) prevents a checkpoint from
+- ** snapshot. Since holding READ_LOCK(0) prevents a checkpoint from
- ** happening, this is usually correct.
- **
- ** However, if frames have been appended to the log (or if the log
@@ -7086,16 +40583,13 @@
- return SQLITE_OK;
- }else if( rc!=SQLITE_BUSY ){
- return rc;
-+ for(iSub++; iSub<ArraySize(aSub); iSub++){
-+ if( nList & (1<<iSub) ){
-+ struct Sublist *p = &aSub[iSub];
-+ assert( p->nList<=(1<<iSub) );
-+ assert( p->aList==&aList[nList&~((2<<iSub)-1)] );
-+ walMerge(aContent, p->aList, p->nList, &aMerge, &nMerge, aBuffer);
- }
+- }
++ /* Allocate an instance of struct Wal to return. */
++ *ppWal = 0;
++ pRet = (Wal*)sqlite3MallocZero(sizeof(Wal) + pVfs->szOsFile);
++ if( !pRet ){
++ return SQLITE_NOMEM;
}
-+ assert( aMerge==aList );
-+ *pnList = nMerge;
- /* If we get this far, it means that the reader will want to use
- ** the WAL to get at content from recent commits. The job now is
@@ -7111,15 +40605,29 @@
- mxReadMark = thisMark;
- mxI = i;
- }
-- }
++ pRet->pVfs = pVfs;
++ pRet->pWalFd = (sqlite3_file *)&pRet[1];
++ pRet->pDbFd = pDbFd;
++ pRet->readLock = -1;
++ pRet->mxWalSize = mxWalSize;
++ pRet->zWalName = zWalName;
++ pRet->syncHeader = 1;
++ pRet->padToSectorBoundary = 1;
++ pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE);
++
++ /* Open file handle on the write-ahead log file. */
++ flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL);
++ rc = sqlite3OsOpen(pVfs, zWalName, pRet->pWalFd, flags, &flags);
++ if( rc==SQLITE_OK && flags&SQLITE_OPEN_READONLY ){
++ pRet->readOnly = WAL_RDONLY;
+ }
- /* There was once an "if" here. The extra "{" is to preserve indentation. */
-+#ifdef SQLITE_DEBUG
- {
+- {
- if( (pWal->readOnly & WAL_SHM_RDONLY)==0
- && (mxReadMark<pWal->hdr.mxFrame || mxI==0)
- ){
- for(i=1; i<WAL_NREADER; i++){
-- rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
+- rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1, 0);
- if( rc==SQLITE_OK ){
- mxReadMark = pInfo->aReadMark[i] = pWal->hdr.mxFrame;
- mxI = i;
@@ -7134,7 +40642,7 @@
- assert( rc==SQLITE_BUSY || (pWal->readOnly & WAL_SHM_RDONLY)!=0 );
- return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTLOCK;
- }
--
+
- rc = walLockShared(pWal, WAL_READ_LOCK(mxI));
- if( rc ){
- return rc==SQLITE_BUSY ? WAL_RETRY : rc;
@@ -7168,15 +40676,23 @@
- }else{
- assert( mxReadMark<=pWal->hdr.mxFrame );
- pWal->readLock = (i16)mxI;
-+ int i;
-+ for(i=1; i<*pnList; i++){
-+ assert( aContent[aList[i]] > aContent[aList[i-1]] );
++ if( rc!=SQLITE_OK ){
++ walIndexClose(pRet, 0);
++ sqlite3OsClose(pRet->pWalFd);
++ sqlite3_free(pRet);
++ }else{
++ int iDC = sqlite3OsDeviceCharacteristics(pDbFd);
++ if( iDC & SQLITE_IOCAP_SEQUENTIAL ){ pRet->syncHeader = 0; }
++ if( iDC & SQLITE_IOCAP_POWERSAFE_OVERWRITE ){
++ pRet->padToSectorBoundary = 0;
}
++ *ppWal = pRet;
++ WALTRACE(("WAL%d: opened\n", pRet));
}
-- return rc;
--}
--
--/*
+ return rc;
+ }
+
+ /*
-** Begin a read transaction on the database.
-**
-** This routine used to be called sqlite3OpenSnapshot() and with good reason:
@@ -7189,7 +40705,8 @@
-** transaction, then *pChanged is set to 1 before returning. The
-** Pager layer will use this to know that is cache is stale and
-** needs to be flushed.
--*/
++** Change the size to which the WAL file is trucated on each reset.
+ */
-SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
- int rc; /* Return code */
- int cnt = 0; /* Number of TryBeginRead attempts */
@@ -7202,87 +40719,137 @@
- testcase( rc==SQLITE_PROTOCOL );
- testcase( rc==SQLITE_OK );
- return rc;
-+#endif
++SQLITE_PRIVATE void sqlite3WalLimit(Wal *pWal, i64 iLimit){
++ if( pWal ) pWal->mxWalSize = iLimit;
}
--/*
+ /*
-** Finish with a read transaction. All this does is release the
-** read-lock.
-+/*
-+** Free an iterator allocated by walIteratorInit().
++** Find the smallest page number out of all pages held in the WAL that
++** has not been returned by any prior invocation of this method on the
++** same WalIterator object. Write into *piFrame the frame index where
++** that page was last written into the WAL. Write into *piPage the page
++** number.
++**
++** Return 0 on success. If there are no pages in the WAL with a page
++** number larger than *piPage, then return 1.
*/
-SQLITE_PRIVATE void sqlite3WalEndReadTransaction(Wal *pWal){
- sqlite3WalEndWriteTransaction(pWal);
- if( pWal->readLock>=0 ){
- walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock));
- pWal->readLock = -1;
-- }
-+static void walIteratorFree(WalIterator *p){
-+ sqlite3ScratchFree(p);
++static int walIteratorNext(
++ WalIterator *p, /* Iterator */
++ u32 *piPage, /* OUT: The page number of the next page */
++ u32 *piFrame /* OUT: Wal frame index of next page */
++){
++ u32 iMin; /* Result pgno must be greater than iMin */
++ u32 iRet = 0xFFFFFFFF; /* 0xffffffff is never a valid page number */
++ int i; /* For looping through segments */
++
++ iMin = p->iPrior;
++ assert( iMin<0xffffffff );
++ for(i=p->nSegment-1; i>=0; i--){
++ struct WalSegment *pSegment = &p->aSegment[i];
++ while( pSegment->iNext<pSegment->nEntry ){
++ u32 iPg = pSegment->aPgno[pSegment->aIndex[pSegment->iNext]];
++ if( iPg>iMin ){
++ if( iPg<iRet ){
++ iRet = iPg;
++ *piFrame = pSegment->iZero + pSegment->aIndex[pSegment->iNext];
++ }
++ break;
++ }
++ pSegment->iNext++;
++ }
+ }
++
++ *piPage = p->iPrior = iRet;
++ return (iRet==0xFFFFFFFF);
}
/*
-** 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.
-+** Construct a WalInterator object that can be used to loop over all
-+** pages in the WAL in ascending order. The caller must hold the checkpoint
-+** lock.
++** This function merges two sorted lists into a single sorted list.
**
-** 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.
-+** On success, make *pp point to the newly allocated WalInterator object
-+** return SQLITE_OK. Otherwise, return an error code. If this routine
-+** returns an error, the value of *pp is undefined.
++** aLeft[] and aRight[] are arrays of indices. The sort key is
++** aContent[aLeft[]] and aContent[aRight[]]. Upon entry, the following
++** is guaranteed for all J<K:
+**
-+** The calling routine should invoke walIteratorFree() to destroy the
-+** WalIterator object when it has finished with it.
++** aContent[aLeft[J]] < aContent[aLeft[K]]
++** aContent[aRight[J]] < aContent[aRight[K]]
++**
++** This routine overwrites aRight[] with a new (probably longer) sequence
++** of indices such that the aRight[] contains every index that appears in
++** either aLeft[] or the old aRight[] and such that the second condition
++** above is still met.
++**
++** The aContent[aLeft[X]] values will be unique for all X. And the
++** aContent[aRight[X]] values will be unique too. But there might be
++** one or more combinations of X and Y such that
++**
++** aLeft[X]!=aRight[Y] && aContent[aLeft[X]] == aContent[aRight[Y]]
++**
++** When that happens, omit the aLeft[X] and use the aRight[Y] index.
*/
-SQLITE_PRIVATE int sqlite3WalFindFrame(
- Wal *pWal, /* WAL handle */
- Pgno pgno, /* Database page number to read data for */
- u32 *piRead /* OUT: Frame number (or zero) */
--){
++static void walMerge(
++ const u32 *aContent, /* Pages in wal - keys for the sort */
++ ht_slot *aLeft, /* IN: Left hand input list */
++ int nLeft, /* IN: Elements in array *paLeft */
++ ht_slot **paRight, /* IN/OUT: Right hand input list */
++ int *pnRight, /* IN/OUT: Elements in *paRight */
++ ht_slot *aTmp /* Temporary buffer */
+ ){
- u32 iRead = 0; /* If !=0, WAL frame to return data from */
- u32 iLast = pWal->hdr.mxFrame; /* Last page in WAL for this reader */
- int iHash; /* Used to loop through N hash tables */
--
++ int iLeft = 0; /* Current index in aLeft */
++ int iRight = 0; /* Current index in aRight */
++ int iOut = 0; /* Current index in output buffer */
++ int nRight = *pnRight;
++ ht_slot *aRight = *paRight;
+
- /* This routine is only be called from within a read transaction. */
- assert( pWal->readLock>=0 || pWal->lockError );
-+static int walIteratorInit(Wal *pWal, WalIterator **pp){
-+ WalIterator *p; /* Return value */
-+ int nSegment; /* Number of segments to merge */
-+ u32 iLast; /* Last frame in log */
-+ int nByte; /* Number of bytes to allocate */
-+ int i; /* Iterator variable */
-+ ht_slot *aTmp; /* Temp space used by merge-sort */
-+ int rc = SQLITE_OK; /* Return Code */
++ assert( nLeft>0 && nRight>0 );
++ while( iRight<nRight || iLeft<nLeft ){
++ ht_slot logpage;
++ Pgno dbpage;
- /* If the "last page" field of the wal-index header snapshot is 0, then
- ** no data will be read from the wal under any circumstances. Return early
- ** in this case as an optimization. Likewise, if pWal->readLock==0,
- ** then the WAL is ignored by the reader so return early, as if the
- ** WAL were empty.
-+ /* This routine only runs while holding the checkpoint lock. And
-+ ** it only runs if there is actually content in the log (mxFrame>0).
- */
+- */
- if( iLast==0 || pWal->readLock==0 ){
- *piRead = 0;
- return SQLITE_OK;
-+ assert( pWal->ckptLock && pWal->hdr.mxFrame>0 );
-+ iLast = pWal->hdr.mxFrame;
++ if( (iLeft<nLeft)
++ && (iRight>=nRight || aContent[aLeft[iLeft]]<aContent[aRight[iRight]])
++ ){
++ logpage = aLeft[iLeft++];
++ }else{
++ logpage = aRight[iRight++];
++ }
++ dbpage = aContent[logpage];
+
-+ /* Allocate space for the WalIterator object. */
-+ nSegment = walFramePage(iLast) + 1;
-+ nByte = sizeof(WalIterator)
-+ + (nSegment-1)*sizeof(struct WalSegment)
-+ + iLast*sizeof(ht_slot);
-+ p = (WalIterator *)sqlite3ScratchMalloc(nByte);
-+ if( !p ){
-+ return SQLITE_NOMEM;
++ aTmp[iOut++] = logpage;
++ if( iLeft<nLeft && aContent[aLeft[iLeft]]==dbpage ) iLeft++;
++
++ assert( iLeft>=nLeft || aContent[aLeft[iLeft]]>dbpage );
++ assert( iRight>=nRight || aContent[aRight[iRight]]>dbpage );
}
-+ memset(p, 0, nByte);
-+ p->nSegment = nSegment;
- /* Search the hash table or tables for an entry matching page number
- ** pgno. Each iteration of the following for() loop searches one
@@ -7308,9 +40875,7 @@
- ** (iFrame<=iLast):
- ** This condition filters out entries that were added to the hash
- ** table after the current read-transaction had started.
-+ /* Allocate temporary space used by the merge-sort routine. This block
-+ ** of memory will be freed before this function returns.
- */
+- */
- for(iHash=walFramePage(iLast); iHash>=0 && iRead==0; iHash--){
- volatile ht_slot *aHash; /* Pointer to hash table */
- volatile u32 *aPgno; /* Pointer to array of page numbers */
@@ -7318,62 +40883,93 @@
- int iKey; /* Hash slot index */
- int nCollide; /* Number of hash collisions remaining */
- int rc; /* Error code */
-+ aTmp = (ht_slot *)sqlite3ScratchMalloc(
-+ sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast)
-+ );
-+ if( !aTmp ){
-+ rc = SQLITE_NOMEM;
-+ }
++ *paRight = aLeft;
++ *pnRight = iOut;
++ memcpy(aLeft, aTmp, sizeof(aTmp[0])*iOut);
++}
- rc = walHashGet(pWal, iHash, &aHash, &aPgno, &iZero);
- if( rc!=SQLITE_OK ){
- return rc;
-- }
++/*
++** Sort the elements in list aList using aContent[] as the sort key.
++** Remove elements with duplicate keys, preferring to keep the
++** larger aList[] values.
++**
++** The aList[] entries are indices into aContent[]. The values in
++** aList[] are to be sorted so that for all J<K:
++**
++** aContent[aList[J]] < aContent[aList[K]]
++**
++** For any X and Y such that
++**
++** aContent[aList[X]] == aContent[aList[Y]]
++**
++** Keep the larger of the two values aList[X] and aList[Y] and discard
++** the smaller.
++*/
++static void walMergesort(
++ const u32 *aContent, /* Pages in wal */
++ ht_slot *aBuffer, /* Buffer of at least *pnList items to use */
++ ht_slot *aList, /* IN/OUT: List to sort */
++ int *pnList /* IN/OUT: Number of elements in aList[] */
++){
++ struct Sublist {
++ int nList; /* Number of elements in aList */
++ ht_slot *aList; /* Pointer to sub-list content */
++ };
++
++ const int nList = *pnList; /* Size of input list */
++ int nMerge = 0; /* Number of elements in list aMerge */
++ ht_slot *aMerge = 0; /* List to be merged */
++ int iList; /* Index into input list */
++ int iSub = 0; /* Index into aSub array */
++ struct Sublist aSub[13]; /* Array of sub-lists */
++
++ memset(aSub, 0, sizeof(aSub));
++ assert( nList<=HASHTABLE_NPAGE && nList>0 );
++ assert( HASHTABLE_NPAGE==(1<<(ArraySize(aSub)-1)) );
++
++ for(iList=0; iList<nList; iList++){
++ nMerge = 1;
++ aMerge = &aList[iList];
++ for(iSub=0; iList & (1<<iSub); iSub++){
++ struct Sublist *p = &aSub[iSub];
++ assert( p->aList && p->nList<=(1<<iSub) );
++ assert( p->aList==&aList[iList&~((2<<iSub)-1)] );
++ walMerge(aContent, p->aList, p->nList, &aMerge, &nMerge, aBuffer);
+ }
- nCollide = HASHTABLE_NSLOT;
- for(iKey=walHash(pgno); aHash[iKey]; iKey=walNextHash(iKey)){
- u32 iFrame = aHash[iKey] + iZero;
- if( iFrame<=iLast && aPgno[aHash[iKey]]==pgno ){
-- /* assert( iFrame>iRead ); -- not true if there is corruption */
+- assert( iFrame>iRead || CORRUPT_DB );
- iRead = iFrame;
-+ for(i=0; rc==SQLITE_OK && i<nSegment; i++){
-+ volatile ht_slot *aHash;
-+ u32 iZero;
-+ volatile u32 *aPgno;
-+
-+ rc = walHashGet(pWal, i, &aHash, &aPgno, &iZero);
-+ if( rc==SQLITE_OK ){
-+ int j; /* Counter variable */
-+ int nEntry; /* Number of entries in this segment */
-+ ht_slot *aIndex; /* Sorted index for this segment */
-+
-+ aPgno++;
-+ if( (i+1)==nSegment ){
-+ nEntry = (int)(iLast - iZero);
-+ }else{
-+ nEntry = (int)((u32*)aHash - (u32*)aPgno);
- }
+- }
- if( (nCollide--)==0 ){
- return SQLITE_CORRUPT_BKPT;
-+ aIndex = &((ht_slot *)&p->aSegment[p->nSegment])[iZero];
-+ iZero++;
-+
-+ for(j=0; j<nEntry; j++){
-+ aIndex[j] = (ht_slot)j;
- }
-+ walMergesort((u32 *)aPgno, aTmp, aIndex, &nEntry);
-+ p->aSegment[i].iZero = iZero;
-+ p->aSegment[i].nEntry = nEntry;
-+ p->aSegment[i].aIndex = aIndex;
-+ p->aSegment[i].aPgno = (u32 *)aPgno;
+- }
++ aSub[iSub].aList = aMerge;
++ aSub[iSub].nList = nMerge;
++ }
++
++ for(iSub++; iSub<ArraySize(aSub); iSub++){
++ if( nList & (1<<iSub) ){
++ struct Sublist *p = &aSub[iSub];
++ assert( p->nList<=(1<<iSub) );
++ assert( p->aList==&aList[nList&~((2<<iSub)-1)] );
++ walMerge(aContent, p->aList, p->nList, &aMerge, &nMerge, aBuffer);
}
}
-+ sqlite3ScratchFree(aTmp);
++ assert( aMerge==aList );
++ *pnList = nMerge;
-#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
- /* If expensive assert() statements are available, do a linear search
- ** of the wal-index file content. Make sure the results agree with the
- ** result obtained using the hash indexes above. */
-- {
++#ifdef SQLITE_DEBUG
+ {
- u32 iRead2 = 0;
- u32 iTest;
- for(iTest=iLast; iTest>0; iTest--){
@@ -7381,28 +40977,23 @@
- iRead2 = iTest;
- break;
- }
-- }
++ int i;
++ for(i=1; i<*pnList; i++){
++ assert( aContent[aList[i]] > aContent[aList[i-1]] );
+ }
- assert( iRead==iRead2 );
-+ if( rc!=SQLITE_OK ){
-+ walIteratorFree(p);
}
--#endif
+ #endif
-
- *piRead = iRead;
- return SQLITE_OK;
-+ *pp = p;
-+ 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
-** error code otherwise.
-+** Attempt to obtain the exclusive WAL lock defined by parameters lockIdx and
-+** n. If the attempt fails and parameter xBusy is not NULL, then it is a
-+** busy-handler function. Invoke it and retry the lock until either the
-+** lock is successfully obtained or the busy-handler returns 0.
- */
+-*/
-SQLITE_PRIVATE int sqlite3WalReadFrame(
- Wal *pWal, /* WAL handle */
- u32 iRead, /* Frame to read */
@@ -7418,168 +41009,188 @@
- iOffset = walFrameOffset(iRead, sz) + WAL_FRAME_HDRSIZE;
- /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
- return sqlite3OsRead(pWal->pWalFd, pOut, (nOut>sz ? sz : nOut), iOffset);
-+static int walBusyLock(
-+ Wal *pWal, /* WAL connection */
-+ int (*xBusy)(void*), /* Function to call when busy */
-+ void *pBusyArg, /* Context argument for xBusyHandler */
-+ int lockIdx, /* Offset of first byte to lock */
-+ int n /* Number of bytes to lock */
-+){
-+ int rc;
-+ do {
-+ rc = walLockExclusive(pWal, lockIdx, n);
-+ }while( xBusy && rc==SQLITE_BUSY && xBusy(pBusyArg) );
-+ return rc;
}
--/*
+ /*
-** Return the size of the database in pages (or zero, if unknown).
-+/*
-+** The cache of the wal-index header must be valid to call this function.
-+** Return the page-size in bytes used by the database.
++** Free an iterator allocated by walIteratorInit().
*/
-SQLITE_PRIVATE Pgno sqlite3WalDbsize(Wal *pWal){
- if( pWal && ALWAYS(pWal->readLock>=0) ){
- return pWal->hdr.nPage;
- }
- return 0;
-+static int walPagesize(Wal *pWal){
-+ return (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16);
++static void walIteratorFree(WalIterator *p){
++ sqlite3_free(p);
}
-
-/*
-** This function starts a write transaction on the WAL.
-+/*
-+** Copy as much content as we can from the WAL back into the database file
-+** in response to an sqlite3_wal_checkpoint() request or the equivalent.
- **
+-**
-** A read transaction must have already been started by a prior call
-** to sqlite3WalBeginReadTransaction().
-+** The amount of information copies from WAL to database might be limited
-+** by active readers. This routine will never overwrite a database page
-+** that a concurrent reader might be using.
++/*
++** Construct a WalInterator object that can be used to loop over all
++** pages in the WAL in ascending order. The caller must hold the checkpoint
++** lock.
**
-** If another thread or process has written into the database since
-** the read transaction was started, then it is not possible for this
-** thread to write as doing so would cause a fork. So this routine
-** returns SQLITE_BUSY in that case and no write transaction is started.
-+** All I/O barrier operations (a.k.a fsyncs) occur in this routine when
-+** SQLite is in WAL-mode in synchronous=NORMAL. That means that if
-+** checkpoints are always run by a background thread or background
-+** process, foreground threads will never block on a lengthy fsync call.
++** On success, make *pp point to the newly allocated WalInterator object
++** return SQLITE_OK. Otherwise, return an error code. If this routine
++** returns an error, the value of *pp is undefined.
**
-** There can only be a single writer active at a time.
-+** Fsync is called on the WAL before writing content out of the WAL and
-+** into the database. This ensures that if the new content is persistent
-+** in the WAL and can be recovered following a power-loss or hard reset.
-+**
-+** Fsync is also called on the database file if (and only if) the entire
-+** WAL content is copied into the database file. This second fsync makes
-+** it safe to delete the WAL since the new content will persist in the
-+** database file.
-+**
-+** This routine uses and updates the nBackfill field of the wal-index header.
-+** This is the only routine tha will increase the value of nBackfill.
-+** (A WAL reset or recovery will revert nBackfill to zero, but not increase
-+** its value.)
-+**
-+** The caller must be holding sufficient locks to ensure that no other
-+** checkpoint is running (in any other thread or process) at the same
-+** time.
++** The calling routine should invoke walIteratorFree() to destroy the
++** WalIterator object when it has finished with it.
*/
-SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){
- int rc;
--
++static int walIteratorInit(Wal *pWal, WalIterator **pp){
++ WalIterator *p; /* Return value */
++ int nSegment; /* Number of segments to merge */
++ u32 iLast; /* Last frame in log */
++ int nByte; /* Number of bytes to allocate */
++ int i; /* Iterator variable */
++ ht_slot *aTmp; /* Temp space used by merge-sort */
++ int rc = SQLITE_OK; /* Return Code */
+
- /* Cannot start a write transaction without first holding a read
- ** transaction. */
- assert( pWal->readLock>=0 );
-+static int walCheckpoint(
-+ Wal *pWal, /* Wal connection */
-+ int eMode, /* One of PASSIVE, FULL or RESTART */
-+ int (*xBusyCall)(void*), /* Function to call when busy */
-+ void *pBusyArg, /* Context argument for xBusyHandler */
-+ int sync_flags, /* Flags for OsSync() (or 0) */
-+ u8 *zBuf /* Temporary buffer to use */
-+){
-+ int rc; /* Return code */
-+ int szPage; /* Database page-size */
-+ WalIterator *pIter = 0; /* Wal iterator context */
-+ u32 iDbpage = 0; /* Next database page to write */
-+ u32 iFrame = 0; /* Wal frame containing data for iDbpage */
-+ u32 mxSafeFrame; /* Max frame that can be backfilled */
-+ u32 mxPage; /* Max database page to write */
-+ int i; /* Loop counter */
-+ volatile WalCkptInfo *pInfo; /* The checkpoint status information */
-+ int (*xBusy)(void*) = 0; /* Function to call when waiting for locks */
++ /* This routine only runs while holding the checkpoint lock. And
++ ** it only runs if there is actually content in the log (mxFrame>0).
++ */
++ assert( pWal->ckptLock && pWal->hdr.mxFrame>0 );
++ iLast = pWal->hdr.mxFrame;
- if( pWal->readOnly ){
- return SQLITE_READONLY;
-- }
-+ szPage = walPagesize(pWal);
-+ testcase( szPage<=32768 );
-+ testcase( szPage>=65536 );
-+ pInfo = walCkptInfo(pWal);
-+ if( pInfo->nBackfill>=pWal->hdr.mxFrame ) return SQLITE_OK;
++ /* Allocate space for the WalIterator object. */
++ nSegment = walFramePage(iLast) + 1;
++ nByte = sizeof(WalIterator)
++ + (nSegment-1)*sizeof(struct WalSegment)
++ + iLast*sizeof(ht_slot);
++ p = (WalIterator *)sqlite3_malloc64(nByte);
++ if( !p ){
++ return SQLITE_NOMEM;
+ }
++ memset(p, 0, nByte);
++ p->nSegment = nSegment;
- /* Only one writer allowed at a time. Get the write lock. Return
- ** SQLITE_BUSY if unable.
-- */
-- rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
++ /* Allocate temporary space used by the merge-sort routine. This block
++ ** of memory will be freed before this function returns.
+ */
+- rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1, 0);
- if( rc ){
-+ /* Allocate the iterator */
-+ rc = walIteratorInit(pWal, &pIter);
-+ if( rc!=SQLITE_OK ){
- return rc;
+- return rc;
++ aTmp = (ht_slot *)sqlite3_malloc64(
++ sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast)
++ );
++ if( !aTmp ){
++ rc = SQLITE_NOMEM;
}
- pWal->writeLock = 1;
-+ assert( pIter );
- /* If another connection has written to the database file since the
- ** time the read transaction on this connection was started, then
- ** the write is disallowed.
-+ if( eMode!=SQLITE_CHECKPOINT_PASSIVE ) xBusy = xBusyCall;
-+
-+ /* Compute in mxSafeFrame the index of the last frame of the WAL that is
-+ ** safe to write into the database. Frames beyond mxSafeFrame might
-+ ** overwrite database pages that are in use by active readers and thus
-+ ** cannot be backfilled from the WAL.
- */
+- */
- if( memcmp(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr))!=0 ){
- walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
- pWal->writeLock = 0;
- rc = SQLITE_BUSY_SNAPSHOT;
-+ mxSafeFrame = pWal->hdr.mxFrame;
-+ mxPage = pWal->hdr.nPage;
-+ for(i=1; i<WAL_NREADER; i++){
-+ u32 y = pInfo->aReadMark[i];
-+ if( mxSafeFrame>y ){
-+ assert( y<=pWal->hdr.mxFrame );
-+ rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
-+ if( rc==SQLITE_OK ){
-+ pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
-+ walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
-+ }else if( rc==SQLITE_BUSY ){
-+ mxSafeFrame = y;
-+ xBusy = 0;
++ for(i=0; rc==SQLITE_OK && i<nSegment; i++){
++ volatile ht_slot *aHash;
++ u32 iZero;
++ volatile u32 *aPgno;
++
++ rc = walHashGet(pWal, i, &aHash, &aPgno, &iZero);
++ if( rc==SQLITE_OK ){
++ int j; /* Counter variable */
++ int nEntry; /* Number of entries in this segment */
++ ht_slot *aIndex; /* Sorted index for this segment */
++
++ aPgno++;
++ if( (i+1)==nSegment ){
++ nEntry = (int)(iLast - iZero);
+ }else{
-+ goto walcheckpoint_out;
++ nEntry = (int)((u32*)aHash - (u32*)aPgno);
+ }
++ aIndex = &((ht_slot *)&p->aSegment[p->nSegment])[iZero];
++ iZero++;
++
++ for(j=0; j<nEntry; j++){
++ aIndex[j] = (ht_slot)j;
++ }
++ walMergesort((u32 *)aPgno, aTmp, aIndex, &nEntry);
++ p->aSegment[i].iZero = iZero;
++ p->aSegment[i].nEntry = nEntry;
++ p->aSegment[i].aIndex = aIndex;
++ p->aSegment[i].aPgno = (u32 *)aPgno;
+ }
++ }
++ sqlite3_free(aTmp);
++
++ if( rc!=SQLITE_OK ){
++ walIteratorFree(p);
}
++ *pp = p;
++ return rc;
++}
-- return rc;
--}
-+ if( pInfo->nBackfill<mxSafeFrame
-+ && (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0), 1))==SQLITE_OK
-+ ){
-+ i64 nSize; /* Current size of database file */
-+ u32 nBackfill = pInfo->nBackfill;
++/*
++** Attempt to obtain the exclusive WAL lock defined by parameters lockIdx and
++** n. If the attempt fails and parameter xBusy is not NULL, then it is a
++** busy-handler function. Invoke it and retry the lock until either the
++** lock is successfully obtained or the busy-handler returns 0.
++*/
++static int walBusyLock(
++ Wal *pWal, /* WAL connection */
++ int (*xBusy)(void*), /* Function to call when busy */
++ void *pBusyArg, /* Context argument for xBusyHandler */
++ int lockIdx, /* Offset of first byte to lock */
++ int n /* Number of bytes to lock */
++){
++ int rc;
++ do {
++ rc = walLockExclusive(pWal, lockIdx, n, 0);
++ }while( xBusy && rc==SQLITE_BUSY && xBusy(pBusyArg) );
+ return rc;
+ }
--/*
+ /*
-** End a write transaction. The commit has already been done. This
-** routine merely releases the lock.
--*/
++** The cache of the wal-index header must be valid to call this function.
++** Return the page-size in bytes used by the database.
++*/
++static int walPagesize(Wal *pWal){
++ return (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16);
++}
++
++/*
++** The following is guaranteed when this function is called:
++**
++** a) the WRITER lock is held,
++** b) the entire log file has been checkpointed, and
++** c) any existing readers are reading exclusively from the database
++** file - there are no readers that may attempt to read a frame from
++** the log file.
++**
++** This function updates the shared-memory structures so that the next
++** client to write to the database (which may be this one) does so by
++** writing frames into the start of the log file.
++**
++** The value of parameter salt1 is used as the aSalt[1] value in the
++** new wal-index header. It should be passed a pseudo-random value (i.e.
++** one obtained from sqlite3_randomness()).
+ */
-SQLITE_PRIVATE int sqlite3WalEndWriteTransaction(Wal *pWal){
- if( pWal->writeLock ){
- walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
@@ -7587,24 +41198,60 @@
- pWal->truncateOnCommit = 0;
- }
- return SQLITE_OK;
--}
-+ /* Sync the WAL to disk */
-+ if( sync_flags ){
-+ rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
-+ }
++static void walRestartHdr(Wal *pWal, u32 salt1){
++ volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
++ int i; /* Loop counter */
++ u32 *aSalt = pWal->hdr.aSalt; /* Big-endian salt values */
++ pWal->nCkpt++;
++ pWal->hdr.mxFrame = 0;
++ sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0]));
++ memcpy(&pWal->hdr.aSalt[1], &salt1, 4);
++ walIndexWriteHdr(pWal);
++ pInfo->nBackfill = 0;
++ pInfo->aReadMark[1] = 0;
++ for(i=2; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
++ assert( pInfo->aReadMark[0]==0 );
+ }
--/*
+ /*
-** If any data has been written (but not committed) to the log file, this
-** function moves the write-pointer back to the start of the transaction.
--**
++** Copy as much content as we can from the WAL back into the database file
++** in response to an sqlite3_wal_checkpoint() request or the equivalent.
+ **
-** Additionally, the callback function is invoked for each frame written
-** to the WAL since the start of the transaction. If the callback returns
-** other than SQLITE_OK, it is not invoked again and the error code is
-** returned to the caller.
--**
++** The amount of information copies from WAL to database might be limited
++** by active readers. This routine will never overwrite a database page
++** that a concurrent reader might be using.
+ **
-** Otherwise, if the callback function does not return an error, this
-** function returns SQLITE_OK.
--*/
++** All I/O barrier operations (a.k.a fsyncs) occur in this routine when
++** SQLite is in WAL-mode in synchronous=NORMAL. That means that if
++** checkpoints are always run by a background thread or background
++** process, foreground threads will never block on a lengthy fsync call.
++**
++** Fsync is called on the WAL before writing content out of the WAL and
++** into the database. This ensures that if the new content is persistent
++** in the WAL and can be recovered following a power-loss or hard reset.
++**
++** Fsync is also called on the database file if (and only if) the entire
++** WAL content is copied into the database file. This second fsync makes
++** it safe to delete the WAL since the new content will persist in the
++** database file.
++**
++** This routine uses and updates the nBackfill field of the wal-index header.
++** This is the only routine that will increase the value of nBackfill.
++** (A WAL reset or recovery will revert nBackfill to zero, but not increase
++** its value.)
++**
++** The caller must be holding sufficient locks to ensure that no other
++** checkpoint is running (in any other thread or process) at the same
++** time.
+ */
-SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx){
- int rc = SQLITE_OK;
- if( ALWAYS(pWal->writeLock) ){
@@ -7613,15 +41260,80 @@
-
- /* Restore the clients cache of the wal-index header to the state it
- ** was in before the client began writing to the database.
-+ /* If the database may grow as a result of this checkpoint, hint
-+ ** about the eventual size of the db file to the VFS layer.
++static int walCheckpoint(
++ Wal *pWal, /* Wal connection */
++ int eMode, /* One of PASSIVE, FULL or RESTART */
++ int (*xBusy)(void*), /* Function to call when busy */
++ void *pBusyArg, /* Context argument for xBusyHandler */
++ int sync_flags, /* Flags for OsSync() (or 0) */
++ u8 *zBuf /* Temporary buffer to use */
++){
++ int rc = SQLITE_OK; /* Return code */
++ int szPage; /* Database page-size */
++ WalIterator *pIter = 0; /* Wal iterator context */
++ u32 iDbpage = 0; /* Next database page to write */
++ u32 iFrame = 0; /* Wal frame containing data for iDbpage */
++ u32 mxSafeFrame; /* Max frame that can be backfilled */
++ u32 mxPage; /* Max database page to write */
++ int i; /* Loop counter */
++ volatile WalCkptInfo *pInfo; /* The checkpoint status information */
++
++ szPage = walPagesize(pWal);
++ testcase( szPage<=32768 );
++ testcase( szPage>=65536 );
++ pInfo = walCkptInfo(pWal);
++ if( pInfo->nBackfill<pWal->hdr.mxFrame ){
++
++ /* Allocate the iterator */
++ rc = walIteratorInit(pWal, &pIter);
++ if( rc!=SQLITE_OK ){
++ return rc;
++ }
++ assert( pIter );
++
++ /* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked
++ ** in the SQLITE_CHECKPOINT_PASSIVE mode. */
++ assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 );
++
++ /* Compute in mxSafeFrame the index of the last frame of the WAL that is
++ ** safe to write into the database. Frames beyond mxSafeFrame might
++ ** overwrite database pages that are in use by active readers and thus
++ ** cannot be backfilled from the WAL.
*/
- memcpy(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr));
--
++ mxSafeFrame = pWal->hdr.mxFrame;
++ mxPage = pWal->hdr.nPage;
++ for(i=1; i<WAL_NREADER; i++){
++ /* Thread-sanitizer reports that the following is an unsafe read,
++ ** as some other thread may be in the process of updating the value
++ ** of the aReadMark[] slot. The assumption here is that if that is
++ ** happening, the other client may only be increasing the value,
++ ** not decreasing it. So assuming either that either the "old" or
++ ** "new" version of the value is read, and not some arbitrary value
++ ** that would never be written by a real client, things are still
++ ** safe. */
++ u32 y = pInfo->aReadMark[i];
++ if( mxSafeFrame>y ){
++ assert( y<=pWal->hdr.mxFrame );
++ rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
++ if( rc==SQLITE_OK ){
++ pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
++ walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
++ }else if( rc==SQLITE_BUSY ){
++ mxSafeFrame = y;
++ xBusy = 0;
++ }else{
++ goto walcheckpoint_out;
++ }
++ }
++ }
+
- for(iFrame=pWal->hdr.mxFrame+1;
- ALWAYS(rc==SQLITE_OK) && iFrame<=iMax;
- iFrame++
-- ){
++ if( pInfo->nBackfill<mxSafeFrame
++ && (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0),1))==SQLITE_OK
+ ){
- /* This call cannot fail. Unless the page for which the page number
- ** is passed as the second argument is (a) in the cache and
- ** (b) has an outstanding reference, then xUndo is either a no-op
@@ -7635,18 +41347,13 @@
- */
- assert( walFramePgno(pWal, iFrame)!=1 );
- rc = xUndo(pUndoCtx, walFramePgno(pWal, iFrame));
-+ if( rc==SQLITE_OK ){
-+ i64 nReq = ((i64)mxPage * szPage);
-+ rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
-+ if( rc==SQLITE_OK && nSize<nReq ){
-+ sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
-+ }
- }
+- }
- if( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal);
- }
-- assert( rc==SQLITE_OK );
- return rc;
-}
++ i64 nSize; /* Current size of database file */
++ u32 nBackfill = pInfo->nBackfill;
-/*
-** Argument aWalData must point to an array of WAL_SAVEPOINT_NDATA u32
@@ -7661,6 +41368,10 @@
- aWalData[2] = pWal->hdr.aFrameCksum[1];
- aWalData[3] = pWal->nCkpt;
-}
++ /* Sync the WAL to disk */
++ if( sync_flags ){
++ rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
++ }
-/*
-** Move the write position of the WAL back to the point identified by
@@ -7670,37 +41381,19 @@
-*/
-SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData){
- int rc = SQLITE_OK;
-+ /* Iterate through the contents of the WAL, copying data to the db file. */
-+ while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
-+ i64 iOffset;
-+ assert( walFramePgno(pWal, iFrame)==iDbpage );
-+ if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ) continue;
-+ iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE;
-+ /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
-+ rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset);
-+ if( rc!=SQLITE_OK ) break;
-+ iOffset = (iDbpage-1)*(i64)szPage;
-+ testcase( IS_BIG_INT(iOffset) );
-+ rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset);
-+ if( rc!=SQLITE_OK ) break;
-+ }
++ /* If the database may grow as a result of this checkpoint, hint
++ ** about the eventual size of the db file to the VFS layer.
++ */
++ if( rc==SQLITE_OK ){
++ i64 nReq = ((i64)mxPage * szPage);
++ rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
++ if( rc==SQLITE_OK && nSize<nReq ){
++ sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
++ }
++ }
- assert( pWal->writeLock );
- assert( aWalData[3]!=pWal->nCkpt || aWalData[0]<=pWal->hdr.mxFrame );
-+ /* If work was actually accomplished... */
-+ if( rc==SQLITE_OK ){
-+ if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
-+ i64 szDb = pWal->hdr.nPage*(i64)szPage;
-+ testcase( IS_BIG_INT(szDb) );
-+ rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
-+ if( rc==SQLITE_OK && sync_flags ){
-+ rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
-+ }
-+ }
-+ if( rc==SQLITE_OK ){
-+ pInfo->nBackfill = mxSafeFrame;
-+ }
-+ }
- if( aWalData[3]!=pWal->nCkpt ){
- /* This savepoint was opened immediately after the write-transaction
@@ -7709,25 +41402,51 @@
- */
- aWalData[0] = 0;
- aWalData[3] = pWal->nCkpt;
-+ /* Release the reader lock held while backfilling */
-+ walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
- }
+- }
++ /* Iterate through the contents of the WAL, copying data to the db file */
++ while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
++ i64 iOffset;
++ assert( walFramePgno(pWal, iFrame)==iDbpage );
++ if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ){
++ continue;
++ }
++ iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE;
++ /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
++ rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset);
++ if( rc!=SQLITE_OK ) break;
++ iOffset = (iDbpage-1)*(i64)szPage;
++ testcase( IS_BIG_INT(iOffset) );
++ rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset);
++ if( rc!=SQLITE_OK ) break;
++ }
- if( aWalData[0]<pWal->hdr.mxFrame ){
- pWal->hdr.mxFrame = aWalData[0];
- pWal->hdr.aFrameCksum[0] = aWalData[1];
- pWal->hdr.aFrameCksum[1] = aWalData[2];
- walCleanupHash(pWal);
-+ if( rc==SQLITE_BUSY ){
-+ /* Reset the return code so as not to report a checkpoint failure
-+ ** just because there are active readers. */
-+ rc = SQLITE_OK;
- }
+- }
++ /* If work was actually accomplished... */
++ if( rc==SQLITE_OK ){
++ if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
++ i64 szDb = pWal->hdr.nPage*(i64)szPage;
++ testcase( IS_BIG_INT(szDb) );
++ rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
++ if( rc==SQLITE_OK && sync_flags ){
++ rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
++ }
++ }
++ if( rc==SQLITE_OK ){
++ pInfo->nBackfill = mxSafeFrame;
++ }
++ }
- return rc;
-}
--
--
++ /* Release the reader lock held while backfilling */
++ walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
++ }
+
-/*
-** This function is called just before writing a set of frames to the log
-** file (see sqlite3WalFrames()). It checks to see if, instead of appending
@@ -7743,25 +41462,31 @@
-static int walRestartLog(Wal *pWal){
- int rc = SQLITE_OK;
- int cnt;
--
++ if( rc==SQLITE_BUSY ){
++ /* Reset the return code so as not to report a checkpoint failure
++ ** just because there are active readers. */
++ rc = SQLITE_OK;
++ }
++ }
+
- if( pWal->readLock==0 ){
- volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
- assert( pInfo->nBackfill==pWal->hdr.mxFrame );
- if( pInfo->nBackfill>0 ){
-- u32 salt1;
-- sqlite3_randomness(4, &salt1);
-- rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
-+ /* If this is an SQLITE_CHECKPOINT_RESTART operation, and the entire wal
-+ ** file has been copied into the database file, then block until all
-+ ** readers have finished using the wal file. This ensures that the next
-+ ** process to write to the database restarts the wal file.
++ /* If this is an SQLITE_CHECKPOINT_RESTART or TRUNCATE operation, and the
++ ** entire wal file has been copied into the database file, then block
++ ** until all readers have finished using the wal file. This ensures that
++ ** the next process to write to the database restarts the wal file.
+ */
+ if( rc==SQLITE_OK && eMode!=SQLITE_CHECKPOINT_PASSIVE ){
+ assert( pWal->writeLock );
+ if( pInfo->nBackfill<pWal->hdr.mxFrame ){
+ rc = SQLITE_BUSY;
-+ }else if( eMode==SQLITE_CHECKPOINT_RESTART ){
-+ assert( mxSafeFrame==pWal->hdr.mxFrame );
++ }else if( eMode>=SQLITE_CHECKPOINT_RESTART ){
+ u32 salt1;
+ sqlite3_randomness(4, &salt1);
+- rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1, 0);
++ assert( pInfo->nBackfill==pWal->hdr.mxFrame );
+ rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(1), WAL_NREADER-1);
if( rc==SQLITE_OK ){
- /* If all readers are using WAL_READ_LOCK(0) (in other words if no
@@ -7772,20 +41497,25 @@
- ** In theory it would be Ok to update the cache of the header only
- ** at this point. But updating the actual wal-index header is also
- ** safe and means there is no special case for sqlite3WalUndo()
-- ** to handle if this transaction is rolled back.
-- */
-- int i; /* Loop counter */
-- u32 *aSalt = pWal->hdr.aSalt; /* Big-endian salt values */
--
-- pWal->nCkpt++;
-- pWal->hdr.mxFrame = 0;
-- sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0]));
-- aSalt[1] = salt1;
-- walIndexWriteHdr(pWal);
-- pInfo->nBackfill = 0;
-- pInfo->aReadMark[1] = 0;
-- for(i=2; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
-- assert( pInfo->aReadMark[0]==0 );
+- ** to handle if this transaction is rolled back. */
+- walRestartHdr(pWal, salt1);
++ if( eMode==SQLITE_CHECKPOINT_TRUNCATE ){
++ /* IMPLEMENTATION-OF: R-44699-57140 This mode works the same way as
++ ** SQLITE_CHECKPOINT_RESTART with the addition that it also
++ ** truncates the log file to zero bytes just prior to a
++ ** successful return.
++ **
++ ** In theory, it might be safe to do this without updating the
++ ** wal-index header in shared memory, as all subsequent reader or
++ ** writer clients should see that the entire log file has been
++ ** checkpointed and behave accordingly. This seems unsafe though,
++ ** as it would leave the system in a state where the contents of
++ ** the wal-index header do not match the contents of the
++ ** file-system. To avoid this, update the wal-index header to
++ ** indicate that the log file contains zero valid frames. */
++ walRestartHdr(pWal, salt1);
++ rc = sqlite3OsTruncate(pWal->pWalFd, 0);
++ }
walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
- }else if( rc!=SQLITE_BUSY ){
- return rc;
@@ -7813,7 +41543,9 @@
-** Information about the current state of the WAL file and where
-** the next fsync should occur - passed from sqlite3WalFrames() into
-** walWriteToLog().
--*/
++** If the WAL file is currently larger than nMax bytes in size, truncate
++** it to exactly nMax bytes. If an error occurs while doing so, ignore it.
+ */
-typedef struct WalWriter {
- Wal *pWal; /* The complete WAL information */
- sqlite3_file *pFd; /* The WAL file to which we write */
@@ -7821,23 +41553,40 @@
- int syncFlags; /* Flags for the fsync */
- int szPage; /* Size of one page */
-} WalWriter;
--
--/*
++static void walLimitSize(Wal *pWal, i64 nMax){
++ i64 sz;
++ int rx;
++ sqlite3BeginBenignMalloc();
++ rx = sqlite3OsFileSize(pWal->pWalFd, &sz);
++ if( rx==SQLITE_OK && (sz > nMax ) ){
++ rx = sqlite3OsTruncate(pWal->pWalFd, nMax);
++ }
++ sqlite3EndBenignMalloc();
++ if( rx ){
++ sqlite3_log(rx, "cannot limit WAL size: %s", pWal->zWalName);
++ }
++}
+
+ /*
-** Write iAmt bytes of content into the WAL file beginning at iOffset.
-** Do a sync when crossing the p->iSyncPoint boundary.
-**
-** In other words, if iSyncPoint is in between iOffset and iOffset+iAmt,
-** first write the part before iSyncPoint, then sync, then write the
-** rest.
-+** If the WAL file is currently larger than nMax bytes in size, truncate
-+** it to exactly nMax bytes. If an error occurs while doing so, ignore it.
++** Close a connection to a log file.
*/
-static int walWriteToLog(
- WalWriter *p, /* WAL to write to */
- void *pContent, /* Content to be written */
- int iAmt, /* Number of bytes to write */
- sqlite3_int64 iOffset /* Start writing at this offset */
--){
++SQLITE_PRIVATE int sqlite3WalClose(
++ Wal *pWal, /* Wal to close */
++ int sync_flags, /* Flags to pass to OsSync() (or 0) */
++ int nBuf,
++ u8 *zBuf /* Buffer of at least nBuf bytes */
+ ){
- int rc;
- if( iOffset<p->iSyncPoint && iOffset+iAmt>=p->iSyncPoint ){
- int iFirstAmt = (int)(p->iSyncPoint - iOffset);
@@ -7849,50 +41598,6 @@
- assert( p->syncFlags & (SQLITE_SYNC_NORMAL|SQLITE_SYNC_FULL) );
- rc = sqlite3OsSync(p->pFd, p->syncFlags & SQLITE_SYNC_MASK);
- if( iAmt==0 || rc ) return rc;
-+static void walLimitSize(Wal *pWal, i64 nMax){
-+ i64 sz;
-+ int rx;
-+ sqlite3BeginBenignMalloc();
-+ rx = sqlite3OsFileSize(pWal->pWalFd, &sz);
-+ if( rx==SQLITE_OK && (sz > nMax ) ){
-+ rx = sqlite3OsTruncate(pWal->pWalFd, nMax);
-+ }
-+ sqlite3EndBenignMalloc();
-+ if( rx ){
-+ sqlite3_log(rx, "cannot limit WAL size: %s", pWal->zWalName);
- }
-- rc = sqlite3OsWrite(p->pFd, pContent, iAmt, iOffset);
-- return rc;
- }
-
- /*
--** Write out a single frame of the WAL
-+** Close a connection to a log file.
- */
--static int walWriteOneFrame(
-- WalWriter *p, /* Where to write the frame */
-- PgHdr *pPage, /* The page of the frame to be written */
-- int nTruncate, /* The commit flag. Usually 0. >0 for commit */
-- sqlite3_int64 iOffset /* Byte offset at which to write */
-+SQLITE_PRIVATE int sqlite3WalClose(
-+ Wal *pWal, /* Wal to close */
-+ int sync_flags, /* Flags to pass to OsSync() (or 0) */
-+ int nBuf,
-+ u8 *zBuf /* Buffer of at least nBuf bytes */
- ){
-- int rc; /* Result code from subfunctions */
-- void *pData; /* Data actually written */
-- u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */
--#if defined(SQLITE_HAS_CODEC)
-- if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM;
--#else
-- pData = pPage->pData;
--#endif
-- walEncodeFrame(p->pWal, pPage->pgno, nTruncate, pData, aFrame);
-- rc = walWriteToLog(p, aFrame, sizeof(aFrame), iOffset);
-- if( rc ) return rc;
-- /* Write the page data */
-- rc = walWriteToLog(p, pData, p->szPage, iOffset+sizeof(aFrame));
+ int rc = SQLITE_OK;
+ if( pWal ){
+ int isDelete = 0; /* True to unlink wal and wal-index files */
@@ -7945,31 +41650,13 @@
+ WALTRACE(("WAL%p: closed\n", pWal));
+ sqlite3_free((void *)pWal->apWiData);
+ sqlite3_free(pWal);
-+ }
+ }
+- rc = sqlite3OsWrite(p->pFd, pContent, iAmt, iOffset);
return rc;
}
--/*
--** Write a set of frames to the log. The caller must hold the write-lock
--** on the log file (obtained using sqlite3WalBeginWriteTransaction()).
--*/
--SQLITE_PRIVATE 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; /* Used to catch return codes */
-- u32 iFrame; /* Next frame address */
-- PgHdr *p; /* Iterator to run through pList with. */
-- PgHdr *pLast = 0; /* Last frame in list */
-- int nExtra = 0; /* Number of extra copies of last page */
-- int szFrame; /* The size of a single frame */
-- i64 iOffset; /* Next byte to write in WAL file */
-- WalWriter w; /* The writer */
-+/*
+ /*
+-** Write out a single frame of the WAL
+** Try to read the wal-index header. Return 0 on success and 1 if
+** there is a problem.
+**
@@ -7985,20 +41672,58 @@
+**
+** If the checksum cannot be verified return non-zero. If the header
+** is read successfully and the checksum verified, return zero.
-+*/
+ */
+-static int walWriteOneFrame(
+- WalWriter *p, /* Where to write the frame */
+- PgHdr *pPage, /* The page of the frame to be written */
+- int nTruncate, /* The commit flag. Usually 0. >0 for commit */
+- sqlite3_int64 iOffset /* Byte offset at which to write */
+-){
+- int rc; /* Result code from subfunctions */
+- void *pData; /* Data actually written */
+- u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */
+-#if defined(SQLITE_HAS_CODEC)
+- if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM;
+-#else
+- pData = pPage->pData;
+-#endif
+- walEncodeFrame(p->pWal, pPage->pgno, nTruncate, pData, aFrame);
+- rc = walWriteToLog(p, aFrame, sizeof(aFrame), iOffset);
+- if( rc ) return rc;
+- /* Write the page data */
+- rc = walWriteToLog(p, pData, p->szPage, iOffset+sizeof(aFrame));
+- return rc;
+-}
+static int walIndexTryHdr(Wal *pWal, int *pChanged){
+ u32 aCksum[2]; /* Checksum on the header content */
+ WalIndexHdr h1, h2; /* Two copies of the header content */
+ WalIndexHdr volatile *aHdr; /* Header in shared memory */
-- assert( pList );
-- assert( pWal->writeLock );
+-/*
+-** Write a set of frames to the log. The caller must hold the write-lock
+-** on the log file (obtained using sqlite3WalBeginWriteTransaction()).
+-*/
+-SQLITE_PRIVATE 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; /* Used to catch return codes */
+- u32 iFrame; /* Next frame address */
+- PgHdr *p; /* Iterator to run through pList with. */
+- PgHdr *pLast = 0; /* Last frame in list */
+- int nExtra = 0; /* Number of extra copies of last page */
+- int szFrame; /* The size of a single frame */
+- i64 iOffset; /* Next byte to write in WAL file */
+- WalWriter w; /* The writer */
+ /* The first page of the wal-index must be mapped at this point. */
+ assert( pWal->nWiData>0 && pWal->apWiData[0] );
-- /* If this frame set completes a transaction, then nTruncate>0. If
-- ** nTruncate==0 then this frame set does not complete the transaction. */
-- assert( (isCommit!=0)==(nTruncate!=0) );
+- assert( pList );
+- assert( pWal->writeLock );
+ /* Read the header. This might happen concurrently with a write to the
+ ** same area of shared memory on a different CPU in a SMP,
+ ** meaning it is possible that an inconsistent snapshot is read
@@ -8014,70 +41739,24 @@
+ walShmBarrier(pWal);
+ memcpy(&h2, (void *)&aHdr[1], sizeof(h2));
--#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
-- { int cnt; for(cnt=0, p=pList; p; p=p->pDirty, cnt++){}
-- WALTRACE(("WAL%p: frame write begin. %d frames. mxFrame=%d. %s\n",
-- pWal, cnt, pWal->hdr.mxFrame, isCommit ? "Commit" : "Spill"));
+- /* If this frame set completes a transaction, then nTruncate>0. If
+- ** nTruncate==0 then this frame set does not complete the transaction. */
+- assert( (isCommit!=0)==(nTruncate!=0) );
+ if( memcmp(&h1, &h2, sizeof(h1))!=0 ){
+ return 1; /* Dirty read */
+ }
+ if( h1.isInit==0 ){
+ return 1; /* Malformed header - probably all zeros */
- }
--#endif
--
-- /* See if it is possible to write these frames into the start of the
-- ** log file, instead of appending to it at pWal->hdr.mxFrame.
-- */
-- if( SQLITE_OK!=(rc = walRestartLog(pWal)) ){
-- return rc;
++ }
+ walChecksumBytes(1, (u8*)&h1, sizeof(h1)-sizeof(h1.aCksum), 0, aCksum);
+ if( aCksum[0]!=h1.aCksum[0] || aCksum[1]!=h1.aCksum[1] ){
+ return 1; /* Checksum does not match */
- }
++ }
-- /* If this is the first frame written into the log, write the WAL
-- ** header to the start of the WAL file. See comments at the top of
-- ** this source file for a description of the WAL header format.
-- */
-- iFrame = pWal->hdr.mxFrame;
-- if( iFrame==0 ){
-- u8 aWalHdr[WAL_HDRSIZE]; /* Buffer to assemble wal-header in */
-- u32 aCksum[2]; /* Checksum for wal-header */
--
-- sqlite3Put4byte(&aWalHdr[0], (WAL_MAGIC | SQLITE_BIGENDIAN));
-- sqlite3Put4byte(&aWalHdr[4], WAL_MAX_VERSION);
-- sqlite3Put4byte(&aWalHdr[8], szPage);
-- sqlite3Put4byte(&aWalHdr[12], pWal->nCkpt);
-- if( pWal->nCkpt==0 ) sqlite3_randomness(8, pWal->hdr.aSalt);
-- memcpy(&aWalHdr[16], pWal->hdr.aSalt, 8);
-- walChecksumBytes(1, aWalHdr, WAL_HDRSIZE-2*4, 0, aCksum);
-- sqlite3Put4byte(&aWalHdr[24], aCksum[0]);
-- sqlite3Put4byte(&aWalHdr[28], aCksum[1]);
--
-- pWal->szPage = szPage;
-- pWal->hdr.bigEndCksum = SQLITE_BIGENDIAN;
-- pWal->hdr.aFrameCksum[0] = aCksum[0];
-- pWal->hdr.aFrameCksum[1] = aCksum[1];
-- pWal->truncateOnCommit = 1;
--
-- rc = sqlite3OsWrite(pWal->pWalFd, aWalHdr, sizeof(aWalHdr), 0);
-- WALTRACE(("WAL%p: wal-header write %s\n", pWal, rc ? "failed" : "ok"));
-- if( rc!=SQLITE_OK ){
-- return rc;
-- }
--
-- /* Sync the header (unless SQLITE_IOCAP_SEQUENTIAL is true or unless
-- ** all syncing is turned off by PRAGMA synchronous=OFF). Otherwise
-- ** an out-of-order write following a WAL restart could result in
-- ** database corruption. See the ticket:
-- **
-- ** http://localhost:591/sqlite/info/ff5be73dee
-- */
-- if( pWal->syncHeader && sync_flags ){
-- rc = sqlite3OsSync(pWal->pWalFd, sync_flags & SQLITE_SYNC_MASK);
-- if( rc ) return rc;
-- }
+-#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
+- { int cnt; for(cnt=0, p=pList; p; p=p->pDirty, cnt++){}
+- WALTRACE(("WAL%p: frame write begin. %d frames. mxFrame=%d. %s\n",
+- pWal, cnt, pWal->hdr.mxFrame, isCommit ? "Commit" : "Spill"));
+ if( memcmp(&pWal->hdr, &h1, sizeof(WalIndexHdr)) ){
+ *pChanged = 1;
+ memcpy(&pWal->hdr, &h1, sizeof(WalIndexHdr));
@@ -8085,38 +41764,21 @@
+ testcase( pWal->szPage<=32768 );
+ testcase( pWal->szPage>=65536 );
}
-- assert( (int)pWal->szPage==szPage );
+-#endif
-- /* Setup information needed to write frames into the WAL */
-- w.pWal = pWal;
-- w.pFd = pWal->pWalFd;
-- w.iSyncPoint = 0;
-- w.syncFlags = sync_flags;
-- w.szPage = szPage;
-- iOffset = walFrameOffset(iFrame+1, szPage);
-- szFrame = szPage + WAL_FRAME_HDRSIZE;
+- /* See if it is possible to write these frames into the start of the
+- ** log file, instead of appending to it at pWal->hdr.mxFrame.
+ /* The header was successfully read. Return zero. */
+ return 0;
+}
-
-- /* Write all frames into the log file exactly once */
-- for(p=pList; p; p=p->pDirty){
-- int nDbSize; /* 0 normally. Positive == commit flag */
-- iFrame++;
-- assert( iOffset==walFrameOffset(iFrame, szPage) );
-- nDbSize = (isCommit && p->pDirty==0) ? nTruncate : 0;
-- rc = walWriteOneFrame(&w, p, nDbSize, iOffset);
-- if( rc ) return rc;
-- pLast = p;
-- iOffset += szFrame;
-- }
++
+/*
+** Read the wal-index header from the wal-index and into pWal->hdr.
+** If the wal-header appears to be corrupt, try to reconstruct the
+** wal-index from the WAL before returning.
+**
+** Set *pChanged to 1 if the wal-index header value in pWal->hdr is
-+** changed by this opertion. If pWal->hdr is unchanged, set *pChanged
++** changed by this operation. If pWal->hdr is unchanged, set *pChanged
+** to 0.
+**
+** If the wal-index header is successfully read, return SQLITE_OK.
@@ -8126,78 +41788,56 @@
+ int rc; /* Return code */
+ int badHdr; /* True if a header read failed */
+ volatile u32 *page0; /* Chunk of wal-index containing header */
-
-- /* If this is the end of a transaction, then we might need to pad
-- ** the transaction and/or sync the WAL file.
-- **
-- ** Padding and syncing only occur if this set of frames complete a
-- ** transaction and if PRAGMA synchronous=FULL. If synchronous==NORMAL
-- ** or synchonous==OFF, then no padding or syncing are needed.
-- **
-- ** If SQLITE_IOCAP_POWERSAFE_OVERWRITE is defined, then padding is not
-- ** needed and only the sync is done. If padding is needed, then the
-- ** final frame is repeated (with its commit mark) until the next sector
-- ** boundary is crossed. Only the part of the WAL prior to the last
-- ** sector boundary is synced; the part of the last frame that extends
-- ** past the sector boundary is written after the sync.
++
+ /* Ensure that page 0 of the wal-index (the page that contains the
+ ** wal-index header) is mapped. Return early if an error occurs here.
*/
-- if( isCommit && (sync_flags & WAL_SYNC_TRANSACTIONS)!=0 ){
-- if( pWal->padToSectorBoundary ){
-- int sectorSize = sqlite3SectorSize(pWal->pWalFd);
-- w.iSyncPoint = ((iOffset+sectorSize-1)/sectorSize)*sectorSize;
-- while( iOffset<w.iSyncPoint ){
-- rc = walWriteOneFrame(&w, pLast, nTruncate, iOffset);
-- if( rc ) return rc;
-- iOffset += szFrame;
-- nExtra++;
-- }
-- }else{
-- rc = sqlite3OsSync(w.pFd, sync_flags & SQLITE_SYNC_MASK);
-- }
-- }
+- if( SQLITE_OK!=(rc = walRestartLog(pWal)) ){
+ assert( pChanged );
+ rc = walIndexPage(pWal, 0, &page0);
+ if( rc!=SQLITE_OK ){
-+ return rc;
+ return rc;
+- }
+ };
+ assert( page0 || pWal->writeLock==0 );
-- /* If this frame set completes the first transaction in the WAL and
-- ** if PRAGMA journal_size_limit is set, then truncate the WAL to the
-- ** journal size limit, if possible.
+- /* If this is the first frame written into the log, write the WAL
+- ** header to the start of the WAL file. See comments at the top of
+- ** this source file for a description of the WAL header format.
+ /* If the first page of the wal-index has been mapped, try to read the
+ ** wal-index header immediately, without holding any lock. This usually
+ ** works, but may fail if the wal-index header is corrupt or currently
+ ** being modified by another thread or process.
*/
-- if( isCommit && pWal->truncateOnCommit && pWal->mxWalSize>=0 ){
-- i64 sz = pWal->mxWalSize;
-- if( walFrameOffset(iFrame+nExtra+1, szPage)>pWal->mxWalSize ){
-- sz = walFrameOffset(iFrame+nExtra+1, szPage);
-- }
-- walLimitSize(pWal, sz);
-- pWal->truncateOnCommit = 0;
-- }
+- iFrame = pWal->hdr.mxFrame;
+- if( iFrame==0 ){
+- u8 aWalHdr[WAL_HDRSIZE]; /* Buffer to assemble wal-header in */
+- u32 aCksum[2]; /* Checksum for wal-header */
+-
+- sqlite3Put4byte(&aWalHdr[0], (WAL_MAGIC | SQLITE_BIGENDIAN));
+- sqlite3Put4byte(&aWalHdr[4], WAL_MAX_VERSION);
+- sqlite3Put4byte(&aWalHdr[8], szPage);
+- sqlite3Put4byte(&aWalHdr[12], pWal->nCkpt);
+- if( pWal->nCkpt==0 ) sqlite3_randomness(8, pWal->hdr.aSalt);
+- memcpy(&aWalHdr[16], pWal->hdr.aSalt, 8);
+- walChecksumBytes(1, aWalHdr, WAL_HDRSIZE-2*4, 0, aCksum);
+- sqlite3Put4byte(&aWalHdr[24], aCksum[0]);
+- sqlite3Put4byte(&aWalHdr[28], aCksum[1]);
+-
+- pWal->szPage = szPage;
+- pWal->hdr.bigEndCksum = SQLITE_BIGENDIAN;
+- pWal->hdr.aFrameCksum[0] = aCksum[0];
+- pWal->hdr.aFrameCksum[1] = aCksum[1];
+- pWal->truncateOnCommit = 1;
+ badHdr = (page0 ? walIndexTryHdr(pWal, pChanged) : 1);
-- /* Append data to the wal-index. It is not necessary to lock the
-- ** wal-index to do this as the SQLITE_SHM_WRITE lock held on the wal-index
-- ** guarantees that there are no other writers, and no data that may
-- ** be in use by existing readers is being overwritten.
+- rc = sqlite3OsWrite(pWal->pWalFd, aWalHdr, sizeof(aWalHdr), 0);
+- WALTRACE(("WAL%p: wal-header write %s\n", pWal, rc ? "failed" : "ok"));
+- if( rc!=SQLITE_OK ){
+- return rc;
+ /* If the first attempt failed, it might have been due to a race
+ ** with a writer. So get a WRITE lock and try again.
- */
-- iFrame = pWal->hdr.mxFrame;
-- for(p=pList; p && rc==SQLITE_OK; p=p->pDirty){
-- iFrame++;
-- rc = walIndexAppend(pWal, iFrame, p->pgno);
-- }
-- while( rc==SQLITE_OK && nExtra>0 ){
-- iFrame++;
-- nExtra--;
-- rc = walIndexAppend(pWal, iFrame, pLast->pgno);
++ */
+ assert( badHdr==0 || pWal->writeLock==0 );
+ if( badHdr ){
+ if( pWal->readOnly & WAL_SHM_RDONLY ){
@@ -8205,7 +41845,7 @@
+ walUnlockShared(pWal, WAL_WRITE_LOCK);
+ rc = SQLITE_READONLY_RECOVERY;
+ }
-+ }else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){
++ }else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1, 1)) ){
+ pWal->writeLock = 1;
+ if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
+ badHdr = walIndexTryHdr(pWal, pChanged);
@@ -8220,23 +41860,19 @@
+ }
+ pWal->writeLock = 0;
+ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
-+ }
- }
+ }
++ }
-- if( rc==SQLITE_OK ){
-- /* Update the private copy of the header. */
-- pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
-- testcase( szPage<=32768 );
-- testcase( szPage>=65536 );
-- pWal->hdr.mxFrame = iFrame;
-- if( isCommit ){
-- pWal->hdr.iChange++;
-- pWal->hdr.nPage = nTruncate;
-- }
-- /* If this is a commit, update the wal-index header too. */
-- if( isCommit ){
-- walIndexWriteHdr(pWal);
-- pWal->iCallback = iFrame;
+- /* Sync the header (unless SQLITE_IOCAP_SEQUENTIAL is true or unless
+- ** all syncing is turned off by PRAGMA synchronous=OFF). Otherwise
+- ** an out-of-order write following a WAL restart could result in
+- ** database corruption. See the ticket:
+- **
+- ** http://localhost:591/sqlite/info/ff5be73dee
+- */
+- if( pWal->syncHeader && sync_flags ){
+- rc = sqlite3OsSync(pWal->pWalFd, sync_flags & SQLITE_SYNC_MASK);
+- if( rc ) return rc;
- }
+ /* If the header is read successfully, check the version number to make
+ ** sure the wal-index was not constructed with some future format that
@@ -8245,33 +41881,47 @@
+ if( badHdr==0 && pWal->hdr.iVersion!=WALINDEX_MAX_VERSION ){
+ rc = SQLITE_CANTOPEN_BKPT;
}
+- assert( (int)pWal->szPage==szPage );
-- WALTRACE(("WAL%p: frame write %s\n", pWal, rc ? "failed" : "ok"));
- return rc;
- }
+- /* Setup information needed to write frames into the WAL */
+- w.pWal = pWal;
+- w.pFd = pWal->pWalFd;
+- w.iSyncPoint = 0;
+- w.syncFlags = sync_flags;
+- w.szPage = szPage;
+- iOffset = walFrameOffset(iFrame+1, szPage);
+- szFrame = szPage + WAL_FRAME_HDRSIZE;
++ return rc;
++}
--/*
--** This routine is called to implement sqlite3_wal_checkpoint() and
--** related interfaces.
+- /* Write all frames into the log file exactly once */
+- for(p=pList; p; p=p->pDirty){
+- int nDbSize; /* 0 normally. Positive == commit flag */
+- iFrame++;
+- assert( iOffset==walFrameOffset(iFrame, szPage) );
+- nDbSize = (isCommit && p->pDirty==0) ? nTruncate : 0;
+- rc = walWriteOneFrame(&w, p, nDbSize, iOffset);
+- if( rc ) return rc;
+- pLast = p;
+- iOffset += szFrame;
+- }
+/*
+** This is the value that walTryBeginRead returns when it needs to
+** be retried.
+*/
+#define WAL_RETRY (-1)
-+
+
+- /* If this is the end of a transaction, then we might need to pad
+- ** the transaction and/or sync the WAL file.
+/*
+** Attempt to start a read transaction. This might fail due to a race or
+** other transient condition. When that happens, it returns WAL_RETRY to
+** indicate to the caller that it is safe to retry immediately.
- **
--** Obtain a CHECKPOINT lock and then backfill as much information as
--** we can from WAL into the database.
++**
+** On success return SQLITE_OK. On a permanent failure (such an
+** I/O error or an SQLITE_BUSY because another process is running
+** recovery) return a positive error code.
- **
--** If parameter xBusy is not NULL, it is a pointer to a busy-handler
--** callback. In this case this function runs a blocking checkpoint.
++**
+** The useWal parameter is true to force the use of the WAL and disable
+** the case where the WAL is bypassed because it has been completely
+** checkpointed. If useWal==0 then this routine calls walIndexReadHdr()
@@ -8312,52 +41962,21 @@
+** update values of the aReadMark[] array in the header, but if it does
+** so it takes care to hold an exclusive lock on the corresponding
+** WAL_READ_LOCK() while changing values.
- */
--SQLITE_PRIVATE int sqlite3WalCheckpoint(
-- Wal *pWal, /* Wal connection */
-- int eMode, /* PASSIVE, FULL or RESTART */
-- int (*xBusy)(void*), /* Function to call when busy */
-- void *pBusyArg, /* Context argument for xBusyHandler */
-- int sync_flags, /* Flags to sync db file with (or 0) */
-- int nBuf, /* Size of temporary buffer */
-- u8 *zBuf, /* Temporary buffer to use */
-- int *pnLog, /* OUT: Number of frames in WAL */
-- int *pnCkpt /* OUT: Number of backfilled frames in WAL */
--){
-- int rc; /* Return code */
-- int isChanged = 0; /* True if a new wal-index header is loaded */
-- int eMode2 = eMode; /* Mode to pass to walCheckpoint() */
--
-- assert( pWal->ckptLock==0 );
-- assert( pWal->writeLock==0 );
++*/
+static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
+ volatile WalCkptInfo *pInfo; /* Checkpoint information in wal-index */
+ u32 mxReadMark; /* Largest aReadMark[] value */
+ int mxI; /* Index of largest aReadMark[] value */
+ int i; /* Loop counter */
+ int rc = SQLITE_OK; /* Return code */
-
-- if( pWal->readOnly ) return SQLITE_READONLY;
-- WALTRACE(("WAL%p: checkpoint begins\n", pWal));
-- rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
-- if( rc ){
-- /* Usually this is SQLITE_BUSY meaning that another thread or process
-- ** is already running a checkpoint, or maybe a recovery. But it might
-- ** also be SQLITE_IOERR. */
-- return rc;
-- }
-- pWal->ckptLock = 1;
++
+ assert( pWal->readLock<0 ); /* Not currently locked */
-
-- /* If this is a blocking-checkpoint, then obtain the write-lock as well
-- ** to prevent any writers from running while the checkpoint is underway.
-- ** This has to be done before the call to walIndexReadHdr() below.
++
+ /* Take steps to avoid spinning forever if there is a protocol error.
**
-- ** If the writer lock cannot be obtained, then a passive checkpoint is
-- ** run instead. Since the checkpointer is not holding the writer lock,
-- ** there is no point in blocking waiting for any readers. Assuming no
-- ** other error occurs, this function will return SQLITE_BUSY to the caller.
+- ** Padding and syncing only occur if this set of frames complete a
+- ** transaction and if PRAGMA synchronous=FULL. If synchronous==NORMAL
+- ** or synchronous==OFF, then no padding or syncing are needed.
+ ** Circumstances that cause a RETRY should only last for the briefest
+ ** instances of time. No I/O or other system calls are done while the
+ ** locks are held, so the locks should not be held for very long. But
@@ -8365,7 +41984,13 @@
+ ** paged out or take a page-fault that is time-consuming to resolve,
+ ** during the few nanoseconds that it is holding the lock. In that case,
+ ** it might take longer than normal for the lock to free.
-+ **
+ **
+- ** If SQLITE_IOCAP_POWERSAFE_OVERWRITE is defined, then padding is not
+- ** needed and only the sync is done. If padding is needed, then the
+- ** final frame is repeated (with its commit mark) until the next sector
+- ** boundary is crossed. Only the part of the WAL prior to the last
+- ** sector boundary is synced; the part of the last frame that extends
+- ** past the sector boundary is written after the sync.
+ ** After 5 RETRYs, we begin calling sqlite3OsSleep(). The first few
+ ** calls to sqlite3OsSleep() have a delay of 1 microsecond. Really this
+ ** is more of a scheduler yield than an actual delay. But on the 10th
@@ -8373,8 +41998,15 @@
+ ** so that on the 100th (and last) RETRY we delay for 323 milliseconds.
+ ** The total delay time before giving up is less than 10 seconds.
*/
-- if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){
-- rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_WRITE_LOCK, 1);
+- if( isCommit && (sync_flags & WAL_SYNC_TRANSACTIONS)!=0 ){
+- if( pWal->padToSectorBoundary ){
+- int sectorSize = sqlite3SectorSize(pWal->pWalFd);
+- w.iSyncPoint = ((iOffset+sectorSize-1)/sectorSize)*sectorSize;
+- while( iOffset<w.iSyncPoint ){
+- rc = walWriteOneFrame(&w, pLast, nTruncate, iOffset);
+- if( rc ) return rc;
+- iOffset += szFrame;
+- nExtra++;
+ if( cnt>5 ){
+ int nDelay = 1; /* Pause time in microseconds */
+ if( cnt>100 ){
@@ -8410,13 +42042,23 @@
+ rc = WAL_RETRY;
+ }else if( rc==SQLITE_BUSY ){
+ rc = SQLITE_BUSY_RECOVERY;
-+ }
+ }
+- }else{
+- rc = sqlite3OsSync(w.pFd, sync_flags & SQLITE_SYNC_MASK);
+ }
+ if( rc!=SQLITE_OK ){
+ return rc;
-+ }
-+ }
-+
+ }
+ }
+
+- /* If this frame set completes the first transaction in the WAL and
+- ** if PRAGMA journal_size_limit is set, then truncate the WAL to the
+- ** journal size limit, if possible.
+- */
+- if( isCommit && pWal->truncateOnCommit && pWal->mxWalSize>=0 ){
+- i64 sz = pWal->mxWalSize;
+- if( walFrameOffset(iFrame+nExtra+1, szPage)>pWal->mxWalSize ){
+- sz = walFrameOffset(iFrame+nExtra+1, szPage);
+ pInfo = walCkptInfo(pWal);
+ if( !useWal && pInfo->nBackfill==pWal->hdr.mxFrame ){
+ /* The WAL has been completely backfilled (or it is empty).
@@ -8424,17 +42066,13 @@
+ */
+ rc = walLockShared(pWal, WAL_READ_LOCK(0));
+ walShmBarrier(pWal);
- if( rc==SQLITE_OK ){
-- pWal->writeLock = 1;
-- }else if( rc==SQLITE_BUSY ){
-- eMode2 = SQLITE_CHECKPOINT_PASSIVE;
-- rc = SQLITE_OK;
++ if( rc==SQLITE_OK ){
+ if( memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){
+ /* It is not safe to allow the reader to continue here if frames
+ ** may have been appended to the log before READ_LOCK(0) was obtained.
+ ** When holding READ_LOCK(0), the reader ignores the entire log file,
+ ** which implies that the database file contains a trustworthy
-+ ** snapshoT. Since holding READ_LOCK(0) prevents a checkpoint from
++ ** snapshot. Since holding READ_LOCK(0) prevents a checkpoint from
+ ** happening, this is usually correct.
+ **
+ ** However, if frames have been appended to the log (or if the log
@@ -8451,18 +42089,28 @@
+ }else if( rc!=SQLITE_BUSY ){
+ return rc;
}
+- walLimitSize(pWal, sz);
+- pWal->truncateOnCommit = 0;
}
-- /* Read the wal-index header. */
-- if( rc==SQLITE_OK ){
-- rc = walIndexReadHdr(pWal, &isChanged);
-- if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
-- sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
+- /* Append data to the wal-index. It is not necessary to lock the
+- ** wal-index to do this as the SQLITE_SHM_WRITE lock held on the wal-index
+- ** guarantees that there are no other writers, and no data that may
+- ** be in use by existing readers is being overwritten.
+ /* If we get this far, it means that the reader will want to use
+ ** the WAL to get at content from recent commits. The job now is
+ ** to select one of the aReadMark[] entries that is closest to
+ ** but not exceeding pWal->hdr.mxFrame and lock that entry.
-+ */
+ */
+- iFrame = pWal->hdr.mxFrame;
+- for(p=pList; p && rc==SQLITE_OK; p=p->pDirty){
+- iFrame++;
+- rc = walIndexAppend(pWal, iFrame, p->pgno);
+- }
+- while( rc==SQLITE_OK && nExtra>0 ){
+- iFrame++;
+- nExtra--;
+- rc = walIndexAppend(pWal, iFrame, pLast->pgno);
+ mxReadMark = 0;
+ mxI = 0;
+ for(i=1; i<WAL_NREADER; i++){
@@ -8471,7 +42119,7 @@
+ assert( thisMark!=READMARK_NOT_USED );
+ mxReadMark = thisMark;
+ mxI = i;
- }
++ }
}
+ /* There was once an "if" here. The extra "{" is to preserve indentation. */
+ {
@@ -8479,7 +42127,7 @@
+ && (mxReadMark<pWal->hdr.mxFrame || mxI==0)
+ ){
+ for(i=1; i<WAL_NREADER; i++){
-+ rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
++ rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1, 0);
+ if( rc==SQLITE_OK ){
+ mxReadMark = pInfo->aReadMark[i] = pWal->hdr.mxFrame;
+ mxI = i;
@@ -8495,14 +42143,23 @@
+ return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTLOCK;
+ }
-- /* Copy data from the log to the database file. */
- if( rc==SQLITE_OK ){
-- if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
-- rc = SQLITE_CORRUPT_BKPT;
+- /* Update the private copy of the header. */
+- pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
+- testcase( szPage<=32768 );
+- testcase( szPage>=65536 );
+- pWal->hdr.mxFrame = iFrame;
+- if( isCommit ){
+- pWal->hdr.iChange++;
+- pWal->hdr.nPage = nTruncate;
+ rc = walLockShared(pWal, WAL_READ_LOCK(mxI));
+ if( rc ){
+ return rc==SQLITE_BUSY ? WAL_RETRY : rc;
-+ }
+ }
+- /* If this is a commit, update the wal-index header too. */
+- if( isCommit ){
+- walIndexWriteHdr(pWal);
+- pWal->iCallback = iFrame;
+ /* Now that the read-lock has been obtained, check that neither the
+ ** value in the aReadMark[] array or the contents of the wal-index
+ ** header have changed.
@@ -8529,54 +42186,57 @@
+ ){
+ walUnlockShared(pWal, WAL_READ_LOCK(mxI));
+ return WAL_RETRY;
- }else{
-- rc = walCheckpoint(pWal, eMode2, xBusy, pBusyArg, sync_flags, zBuf);
-- }
--
-- /* If no error occurred, set the output variables. */
-- if( rc==SQLITE_OK || rc==SQLITE_BUSY ){
-- if( pnLog ) *pnLog = (int)pWal->hdr.mxFrame;
-- if( pnCkpt ) *pnCkpt = (int)(walCkptInfo(pWal)->nBackfill);
++ }else{
+ assert( mxReadMark<=pWal->hdr.mxFrame );
+ pWal->readLock = (i16)mxI;
}
}
-+ return rc;
-+}
+-
+- WALTRACE(("WAL%p: frame write %s\n", pWal, rc ? "failed" : "ok"));
+ return rc;
+ }
-- if( isChanged ){
-- /* If a new wal-index header was loaded before the checkpoint was
-- ** performed, then the pager-cache associated with pWal is now
-- ** out of date. So zero the cached wal-index header to ensure that
-- ** next time the pager opens a snapshot on this database it knows that
-- ** the cache needs to be reset.
-- */
-- memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
-- }
+-/*
+-** This routine is called to implement sqlite3_wal_checkpoint() and
+-** related interfaces.
+/*
+** Begin a read transaction on the database.
-+**
+ **
+-** Obtain a CHECKPOINT lock and then backfill as much information as
+-** we can from WAL into 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 parameter xBusy is not NULL, it is a pointer to a busy-handler
+-** callback. In this case this function runs a blocking checkpoint.
+** 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 is cache is stale and
+** needs to be flushed.
-+*/
+ */
+-SQLITE_PRIVATE int sqlite3WalCheckpoint(
+- Wal *pWal, /* Wal connection */
+- int eMode, /* PASSIVE, FULL, RESTART, or TRUNCATE */
+- int (*xBusy)(void*), /* Function to call when busy */
+- void *pBusyArg, /* Context argument for xBusyHandler */
+- int sync_flags, /* Flags to sync db file with (or 0) */
+- int nBuf, /* Size of temporary buffer */
+- u8 *zBuf, /* Temporary buffer to use */
+- int *pnLog, /* OUT: Number of frames in WAL */
+- int *pnCkpt /* OUT: Number of backfilled frames in WAL */
+-){
+SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
-+ int rc; /* Return code */
+ int rc; /* Return code */
+- int isChanged = 0; /* True if a new wal-index header is loaded */
+- int eMode2 = eMode; /* Mode to pass to walCheckpoint() */
+- int (*xBusy2)(void*) = xBusy; /* Busy handler for eMode2 */
+ int cnt = 0; /* Number of TryBeginRead attempts */
-- /* Release the locks. */
-- sqlite3WalEndWriteTransaction(pWal);
-- walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
-- pWal->ckptLock = 0;
-- WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok"));
-- return (rc==SQLITE_OK && eMode!=eMode2 ? SQLITE_BUSY : rc);
+- assert( pWal->ckptLock==0 );
+- assert( pWal->writeLock==0 );
+ do{
+ rc = walTryBeginRead(pWal, pChanged, 0, ++cnt);
+ }while( rc==WAL_RETRY );
@@ -8585,63 +42245,31 @@
+ testcase( rc==SQLITE_PROTOCOL );
+ testcase( rc==SQLITE_OK );
+ return rc;
- }
++}
--/* Return the value to pass to a sqlite3_wal_hook callback, the
--** number of frames in the WAL at the point of the last commit since
--** sqlite3WalCallback() was called. If no commits have occurred since
--** the last call, then return 0.
+- /* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked
+- ** in the SQLITE_CHECKPOINT_PASSIVE mode. */
+- assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 );
+/*
+** Finish with a read transaction. All this does is release the
+** read-lock.
- */
--SQLITE_PRIVATE int sqlite3WalCallback(Wal *pWal){
-- u32 ret = 0;
-- if( pWal ){
-- ret = pWal->iCallback;
-- pWal->iCallback = 0;
++*/
+SQLITE_PRIVATE void sqlite3WalEndReadTransaction(Wal *pWal){
+ sqlite3WalEndWriteTransaction(pWal);
+ if( pWal->readLock>=0 ){
+ walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock));
+ pWal->readLock = -1;
- }
-- return (int)ret;
- }
-
- /*
--** This function is called to change the WAL subsystem into or out
--** of locking_mode=EXCLUSIVE.
--**
--** If op is zero, then attempt to change from locking_mode=EXCLUSIVE
--** into locking_mode=NORMAL. This means that we must acquire a lock
--** on the pWal->readLock byte. If the WAL is already in locking_mode=NORMAL
--** or if the acquisition of the lock fails, then return 0. If the
--** transition out of exclusive-mode is successful, return 1. This
--** operation must occur while the pager is still holding the exclusive
--** lock on the main database file.
--**
--** If op is one, then change from locking_mode=NORMAL into
--** locking_mode=EXCLUSIVE. This means that the pWal->readLock must
--** be released. Return 1 if the transition is made and 0 if the
--** WAL is already in exclusive-locking mode - meaning that this
--** routine is a no-op. The pager must already hold the exclusive lock
--** on the main database file before invoking this operation.
++ }
++}
++
++/*
+** 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.
- **
--** If op is negative, then do a dry-run of the op==1 case but do
--** not actually change anything. The pager uses this to see if it
--** should acquire the database exclusive lock prior to invoking
--** the op==1 case.
++**
+** 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.
- */
--SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op){
-- int rc;
-- assert( pWal->writeLock==0 );
-- assert( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE || op==-1 );
++*/
+SQLITE_PRIVATE int sqlite3WalFindFrame(
+ Wal *pWal, /* WAL handle */
+ Pgno pgno, /* Database page number to read data for */
@@ -8651,21 +42279,24 @@
+ u32 iLast = pWal->hdr.mxFrame; /* Last page in WAL for this reader */
+ int iHash; /* Used to loop through N hash tables */
-- /* pWal->readLock is usually set, but might be -1 if there was a
-- ** prior error while attempting to acquire are read-lock. This cannot
-- ** happen if the connection is actually in exclusive mode (as no xShmLock
-- ** locks are taken in this case). Nor should the pager attempt to
-- ** upgrade to exclusive-mode following such an error.
-- */
+- if( pWal->readOnly ) return SQLITE_READONLY;
+- WALTRACE(("WAL%p: checkpoint begins\n", pWal));
+ /* This routine is only be called from within a read transaction. */
- assert( pWal->readLock>=0 || pWal->lockError );
-- assert( pWal->readLock>=0 || (op<=0 && pWal->exclusiveMode==0) );
++ assert( pWal->readLock>=0 || pWal->lockError );
-- if( op==0 ){
-- if( pWal->exclusiveMode ){
-- pWal->exclusiveMode = 0;
-- if( walLockShared(pWal, WAL_READ_LOCK(pWal->readLock))!=SQLITE_OK ){
-- pWal->exclusiveMode = 1;
+- /* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive
+- ** "checkpoint" lock on the database file. */
+- rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1, 0);
+- if( rc ){
+- /* EVIDENCE-OF: R-10421-19736 If any other process is running a
+- ** checkpoint operation at the same time, the lock cannot be obtained and
+- ** SQLITE_BUSY is returned.
+- ** EVIDENCE-OF: R-53820-33897 Even if there is a busy-handler configured,
+- ** it will not be invoked in this case.
+- */
+- testcase( rc==SQLITE_BUSY );
+- testcase( xBusy!=0 );
+- return rc;
+ /* If the "last page" field of the wal-index header snapshot is 0, then
+ ** no data will be read from the wal under any circumstances. Return early
+ ** in this case as an optimization. Likewise, if pWal->readLock==0,
@@ -8675,12 +42306,20 @@
+ if( iLast==0 || pWal->readLock==0 ){
+ *piRead = 0;
+ return SQLITE_OK;
-+ }
-+
+ }
+- pWal->ckptLock = 1;
+
+- /* IMPLEMENTATION-OF: R-59782-36818 The SQLITE_CHECKPOINT_FULL, RESTART and
+- ** TRUNCATE modes also obtain the exclusive "writer" lock on the database
+- ** file.
+ /* Search the hash table or tables for an entry matching page number
+ ** pgno. Each iteration of the following for() loop searches one
+ ** hash table (each hash table indexes up to HASHTABLE_NPAGE frames).
-+ **
+ **
+- ** EVIDENCE-OF: R-60642-04082 If the writer lock cannot be obtained
+- ** immediately, and a busy-handler is configured, it is invoked and the
+- ** writer lock retried until either the busy-handler returns 0 or the
+- ** lock is successfully obtained.
+ ** This code might run concurrently to the code in walIndexAppend()
+ ** that adds entries to the wal-index (and possibly to this hash
+ ** table). This means the value just read from the hash
@@ -8701,7 +42340,17 @@
+ ** (iFrame<=iLast):
+ ** This condition filters out entries that were added to the hash
+ ** table after the current read-transaction had started.
-+ */
+ */
+- if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){
+- rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_WRITE_LOCK, 1);
+- if( rc==SQLITE_OK ){
+- pWal->writeLock = 1;
+- }else if( rc==SQLITE_BUSY ){
+- eMode2 = SQLITE_CHECKPOINT_PASSIVE;
+- xBusy2 = 0;
+- rc = SQLITE_OK;
+- }
+- }
+ for(iHash=walFramePage(iLast); iHash>=0 && iRead==0; iHash--){
+ volatile ht_slot *aHash; /* Pointer to hash table */
+ volatile u32 *aPgno; /* Pointer to array of page numbers */
@@ -8709,37 +42358,41 @@
+ int iKey; /* Hash slot index */
+ int nCollide; /* Number of hash collisions remaining */
+ int rc; /* Error code */
-+
+
+- /* Read the wal-index header. */
+- if( rc==SQLITE_OK ){
+- rc = walIndexReadHdr(pWal, &isChanged);
+- if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
+- sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
+ rc = walHashGet(pWal, iHash, &aHash, &aPgno, &iZero);
+ if( rc!=SQLITE_OK ){
+ return rc;
-+ }
+ }
+- }
+-
+- /* 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{
+- rc = walCheckpoint(pWal, eMode2, xBusy2, pBusyArg, sync_flags, zBuf);
+ nCollide = HASHTABLE_NSLOT;
+ for(iKey=walHash(pgno); aHash[iKey]; iKey=walNextHash(iKey)){
+ u32 iFrame = aHash[iKey] + iZero;
+ if( iFrame<=iLast && aPgno[aHash[iKey]]==pgno ){
-+ /* assert( iFrame>iRead ); -- not true if there is corruption */
++ assert( iFrame>iRead || CORRUPT_DB );
+ iRead = iFrame;
+ }
+ if( (nCollide--)==0 ){
+ return SQLITE_CORRUPT_BKPT;
- }
-- rc = pWal->exclusiveMode==0;
-- }else{
-- /* Already in locking_mode=NORMAL */
-- rc = 0;
++ }
}
-- }else if( op>0 ){
-- assert( pWal->exclusiveMode==0 );
-- assert( pWal->readLock>=0 );
-- walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock));
-- pWal->exclusiveMode = 1;
-- rc = 1;
-- }else{
-- rc = pWal->exclusiveMode==0;
- }
-- return rc;
-+
++ }
+
+- /* If no error occurred, set the output variables. */
+- if( rc==SQLITE_OK || rc==SQLITE_BUSY ){
+- if( pnLog ) *pnLog = (int)pWal->hdr.mxFrame;
+- if( pnCkpt ) *pnCkpt = (int)(walCkptInfo(pWal)->nBackfill);
+#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
+ /* If expensive assert() statements are available, do a linear search
+ ** of the wal-index file content. Make sure the results agree with the
@@ -8752,26 +42405,35 @@
+ iRead2 = iTest;
+ break;
+ }
-+ }
+ }
+ assert( iRead==iRead2 );
-+ }
+ }
+#endif
-+
+
+- if( isChanged ){
+- /* If a new wal-index header was loaded before the checkpoint was
+- ** performed, then the pager-cache associated with pWal is now
+- ** out of date. So zero the cached wal-index header to ensure that
+- ** next time the pager opens a snapshot on this database it knows that
+- ** the cache needs to be reset.
+- */
+- memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
+- }
+ *piRead = iRead;
+ return SQLITE_OK;
- }
++}
--/*
--** Return true if the argument is non-NULL and the WAL module is using
--** heap-memory for the wal-index. Otherwise, if the argument is NULL or the
--** WAL module is using shared-memory, return false.
+- /* Release the locks. */
+- sqlite3WalEndWriteTransaction(pWal);
+- walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
+- pWal->ckptLock = 0;
+- WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok"));
+- return (rc==SQLITE_OK && eMode!=eMode2 ? SQLITE_BUSY : 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
+** error code otherwise.
- */
--SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal){
-- return (pWal && pWal->exclusiveMode==WAL_HEAPMEMORY_MODE );
++*/
+SQLITE_PRIVATE int sqlite3WalReadFrame(
+ Wal *pWal, /* WAL handle */
+ u32 iRead, /* Frame to read */
@@ -8789,54 +42451,165 @@
+ return sqlite3OsRead(pWal->pWalFd, pOut, (nOut>sz ? sz : nOut), iOffset);
}
--#ifdef SQLITE_ENABLE_ZIPVFS
--/*
--** If the argument is not NULL, it points to a Wal object that holds a
--** read-lock. This function returns the database page-size if it is known,
--** or zero if it is not (or if pWal is NULL).
+-/* Return the value to pass to a sqlite3_wal_hook callback, the
+-** number of frames in the WAL at the point of the last commit since
+-** sqlite3WalCallback() was called. If no commits have occurred since
+-** the last call, then return 0.
+/*
+** Return the size of the database in pages (or zero, if unknown).
*/
--SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal){
-- assert( pWal==0 || pWal->readLock>=0 );
-- return (pWal ? pWal->szPage : 0);
+-SQLITE_PRIVATE int sqlite3WalCallback(Wal *pWal){
+- u32 ret = 0;
+- if( pWal ){
+- ret = pWal->iCallback;
+- pWal->iCallback = 0;
+SQLITE_PRIVATE Pgno sqlite3WalDbsize(Wal *pWal){
+ if( pWal && ALWAYS(pWal->readLock>=0) ){
+ return pWal->hdr.nPage;
-+ }
+ }
+- return (int)ret;
+ return 0;
}
+
+-/*
+-** This function is called to change the WAL subsystem into or out
+-** of locking_mode=EXCLUSIVE.
++
++/*
++** This function starts a write transaction on the WAL.
+ **
+-** If op is zero, then attempt to change from locking_mode=EXCLUSIVE
+-** into locking_mode=NORMAL. This means that we must acquire a lock
+-** on the pWal->readLock byte. If the WAL is already in locking_mode=NORMAL
+-** or if the acquisition of the lock fails, then return 0. If the
+-** transition out of exclusive-mode is successful, return 1. This
+-** operation must occur while the pager is still holding the exclusive
+-** lock on the main database file.
++** A read transaction must have already been started by a prior call
++** to sqlite3WalBeginReadTransaction().
+ **
+-** If op is one, then change from locking_mode=NORMAL into
+-** locking_mode=EXCLUSIVE. This means that the pWal->readLock must
+-** be released. Return 1 if the transition is made and 0 if the
+-** WAL is already in exclusive-locking mode - meaning that this
+-** routine is a no-op. The pager must already hold the exclusive lock
+-** on the main database file before invoking this operation.
++** If another thread or process has written into the database since
++** the read transaction was started, then it is not possible for this
++** thread to write as doing so would cause a fork. So this routine
++** returns SQLITE_BUSY in that case and no write transaction is started.
+ **
+-** If op is negative, then do a dry-run of the op==1 case but do
+-** not actually change anything. The pager uses this to see if it
+-** should acquire the database exclusive lock prior to invoking
+-** the op==1 case.
++** There can only be a single writer active at a time.
+ */
+-SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op){
++SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){
+ int rc;
+- assert( pWal->writeLock==0 );
+- assert( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE || op==-1 );
+
+- /* pWal->readLock is usually set, but might be -1 if there was a
+- ** prior error while attempting to acquire are read-lock. This cannot
+- ** happen if the connection is actually in exclusive mode (as no xShmLock
+- ** locks are taken in this case). Nor should the pager attempt to
+- ** upgrade to exclusive-mode following such an error.
+- */
+- assert( pWal->readLock>=0 || pWal->lockError );
+- assert( pWal->readLock>=0 || (op<=0 && pWal->exclusiveMode==0) );
++ /* Cannot start a write transaction without first holding a read
++ ** transaction. */
++ assert( pWal->readLock>=0 );
+
+- if( op==0 ){
+- if( pWal->exclusiveMode ){
+- pWal->exclusiveMode = 0;
+- if( walLockShared(pWal, WAL_READ_LOCK(pWal->readLock))!=SQLITE_OK ){
+- pWal->exclusiveMode = 1;
+- }
+- rc = pWal->exclusiveMode==0;
+- }else{
+- /* Already in locking_mode=NORMAL */
+- rc = 0;
+- }
+- }else if( op>0 ){
+- assert( pWal->exclusiveMode==0 );
+- assert( pWal->readLock>=0 );
+- walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock));
+- pWal->exclusiveMode = 1;
+- rc = 1;
+- }else{
+- rc = pWal->exclusiveMode==0;
++ if( pWal->readOnly ){
++ return SQLITE_READONLY;
+ }
+- return rc;
+-}
+
+-/*
+-** Return true if the argument is non-NULL and the WAL module is using
+-** heap-memory for the wal-index. Otherwise, if the argument is NULL or the
+-** WAL module is using shared-memory, return false.
+-*/
+-SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal){
+- return (pWal && pWal->exclusiveMode==WAL_HEAPMEMORY_MODE );
+-}
++ /* Only one writer allowed at a time. Get the write lock. Return
++ ** SQLITE_BUSY if unable.
++ */
++ rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1, 0);
++ if( rc ){
++ return rc;
++ }
++ pWal->writeLock = 1;
+
+-#ifdef SQLITE_ENABLE_ZIPVFS
+-/*
+-** If the argument is not NULL, it points to a Wal object that holds a
+-** read-lock. This function returns the database page-size if it is known,
+-** or zero if it is not (or if pWal is NULL).
+-*/
+-SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal){
+- assert( pWal==0 || pWal->readLock>=0 );
+- return (pWal ? pWal->szPage : 0);
+-}
-#endif
++ /* If another connection has written to the database file since the
++ ** time the read transaction on this connection was started, then
++ ** the write is disallowed.
++ */
++ if( memcmp(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr))!=0 ){
++ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
++ pWal->writeLock = 0;
++ rc = SQLITE_BUSY_SNAPSHOT;
++ }
-#endif /* #ifndef SQLITE_OMIT_WAL */
++ return rc;
++}
-/************** End of wal.c *************************************************/
-/************** Begin file btmutex.c *****************************************/
--/*
+ /*
-** 2007 August 27
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-+/*
-+** This function starts a write transaction on the WAL.
- **
+-**
-** 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.
-+** A read transaction must have already been started by a prior call
-+** to sqlite3WalBeginReadTransaction().
- **
+-**
-*************************************************************************
-+** If another thread or process has written into the database since
-+** the read transaction was started, then it is not possible for this
-+** thread to write as doing so would cause a fork. So this routine
-+** returns SQLITE_BUSY in that case and no write transaction is started.
- **
+-**
-** This file contains code used to implement mutexes on Btree objects.
-** This code really belongs in btree.c. But btree.c is getting too
-** big and we want to break it down some. This packaged seemed like
-** a good breakout.
-+** There can only be a single writer active at a time.
++** End a write transaction. The commit has already been done. This
++** routine merely releases the lock.
*/
-/************** Include btreeInt.h in the middle of btmutex.c ****************/
-/************** Begin file btreeInt.h ****************************************/
@@ -8851,7 +42624,7 @@
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
--** This file implements a external (disk-based) database using BTrees.
+-** This file implements an external (disk-based) database using BTrees.
-** For a detailed discussion of BTrees, refer to
-**
-** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
@@ -8977,7 +42750,7 @@
-**
-** The flags define the format of this btree page. The leaf flag means that
-** this page has no children. The zerodata flag means that this page carries
--** only keys and no data. The intkey flag means that the key is a integer
+-** only keys and no data. The intkey flag means that the key is an integer
-** which is stored in the key size entry of the cell header rather than in
-** the payload area.
-**
@@ -9044,43 +42817,6 @@
-** SIZE DESCRIPTION
-** 4 Page number of next overflow page
-** * Data
-+SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){
-+ int rc;
-+
-+ /* Cannot start a write transaction without first holding a read
-+ ** transaction. */
-+ assert( pWal->readLock>=0 );
-+
-+ if( pWal->readOnly ){
-+ return SQLITE_READONLY;
-+ }
-+
-+ /* Only one writer allowed at a time. Get the write lock. Return
-+ ** SQLITE_BUSY if unable.
-+ */
-+ rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
-+ if( rc ){
-+ return rc;
-+ }
-+ pWal->writeLock = 1;
-+
-+ /* If another connection has written to the database file since the
-+ ** time the read transaction on this connection was started, then
-+ ** the write is disallowed.
-+ */
-+ if( memcmp(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr))!=0 ){
-+ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
-+ pWal->writeLock = 0;
-+ rc = SQLITE_BUSY_SNAPSHOT;
-+ }
-+
-+ return rc;
-+}
-+
-+/*
-+** End a write transaction. The commit has already been done. This
-+** routine merely releases the lock.
-+*/
+SQLITE_PRIVATE int sqlite3WalEndWriteTransaction(Wal *pWal){
+ if( pWal->writeLock ){
+ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
@@ -9141,7 +42877,6 @@
+ }
+ if( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal);
+ }
-+ assert( rc==SQLITE_OK );
+ return rc;
+}
@@ -9175,7 +42910,10 @@
-#define MX_CELL(pBt) ((pBt->pageSize-8)/6)
+SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData){
+ int rc = SQLITE_OK;
-+
+
+-/* Forward declarations */
+-typedef struct MemPage MemPage;
+-typedef struct BtLock BtLock;
+ assert( pWal->writeLock );
+ assert( aWalData[3]!=pWal->nCkpt || aWalData[0]<=pWal->hdr.mxFrame );
+
@@ -9198,10 +42936,6 @@
+ return rc;
+}
--/* Forward declarations */
--typedef struct MemPage MemPage;
--typedef struct BtLock BtLock;
-
/*
-** This is a magic string that appears at the beginning of every
-** SQLite database in order to identify the file as a real database.
@@ -9236,7 +42970,7 @@
+ if( pInfo->nBackfill>0 ){
+ u32 salt1;
+ sqlite3_randomness(4, &salt1);
-+ rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
++ rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1, 0);
+ if( rc==SQLITE_OK ){
+ /* If all readers are using WAL_READ_LOCK(0) (in other words if no
+ ** readers are currently using the WAL), then the transactions
@@ -9246,20 +42980,8 @@
+ ** In theory it would be Ok to update the cache of the header only
+ ** at this point. But updating the actual wal-index header is also
+ ** safe and means there is no special case for sqlite3WalUndo()
-+ ** to handle if this transaction is rolled back.
-+ */
-+ int i; /* Loop counter */
-+ u32 *aSalt = pWal->hdr.aSalt; /* Big-endian salt values */
-+
-+ pWal->nCkpt++;
-+ pWal->hdr.mxFrame = 0;
-+ sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0]));
-+ aSalt[1] = salt1;
-+ walIndexWriteHdr(pWal);
-+ pInfo->nBackfill = 0;
-+ pInfo->aReadMark[1] = 0;
-+ for(i=2; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
-+ assert( pInfo->aReadMark[0]==0 );
++ ** to handle if this transaction is rolled back. */
++ walRestartHdr(pWal, salt1);
+ walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
+ }else if( rc!=SQLITE_BUSY ){
+ return rc;
@@ -9320,12 +43042,14 @@
-struct MemPage {
- u8 isInit; /* True if previously initialized. MUST BE FIRST! */
- u8 nOverflow; /* Number of overflow cell bodies in aCell[] */
-- u8 intKey; /* True if intkey flag is set */
-- u8 leaf; /* True if leaf flag is set */
-- u8 hasData; /* True if this page stores data */
+- u8 intKey; /* True if table b-trees. False for index b-trees */
+- u8 intKeyLeaf; /* True if the leaf of an intKey table */
+- u8 noPayload; /* True if internal intKey page (thus w/o data) */
+- u8 leaf; /* True if a leaf page */
- u8 hdrOffset; /* 100 for page 1. 0 otherwise */
- u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */
- u8 max1bytePayload; /* min(maxLocal,127) */
+- u8 bBusy; /* Prevent endless loops on corrupt database files */
- u16 maxLocal; /* Copy of BtShared.maxLocal or BtShared.maxLeaf */
- u16 minLocal; /* Copy of BtShared.minLocal or BtShared.minLeaf */
- u16 cellOffset; /* Index in aData of first cell pointer */
@@ -9461,6 +43185,7 @@
- u8 locked; /* True if db currently has pBt locked */
- int wantToLock; /* Number of nested calls to sqlite3BtreeEnter() */
- int nBackup; /* Number of backup operations reading this btree */
+- u32 iDataVersion; /* Combines with pBt->pPager->iDataVersion */
- Btree *pNext; /* List of other sharable Btrees from the same db */
- Btree *pPrev; /* Back pointer of the same list */
-#ifndef SQLITE_OMIT_SHARED_CACHE
@@ -9565,7 +43290,7 @@
+ **
+ ** Padding and syncing only occur if this set of frames complete a
+ ** transaction and if PRAGMA synchronous=FULL. If synchronous==NORMAL
-+ ** or synchonous==OFF, then no padding or syncing are needed.
++ ** or synchronous==OFF, then no padding or syncing are needed.
+ **
+ ** If SQLITE_IOCAP_POWERSAFE_OVERWRITE is defined, then padding is not
+ ** needed and only the sync is done. If padding is needed, then the
@@ -9694,6 +43419,9 @@
-#endif
- u8 inTransaction; /* Transaction state */
- u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */
+-#ifdef SQLITE_HAS_CODEC
+- u8 optimalReserve; /* Desired amount of reserved space per page */
+-#endif
- 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 */
@@ -9713,11 +43441,11 @@
- BtLock *pLock; /* List of locks held on this shared-btree struct */
- Btree *pWriter; /* Btree with currently open write transaction */
-#endif
-- u8 *pTmpSpace; /* BtShared.pageSize bytes of space for tmp use */
+- u8 *pTmpSpace; /* Temp space sufficient to hold a single cell */
-};
+SQLITE_PRIVATE int sqlite3WalCheckpoint(
+ Wal *pWal, /* Wal connection */
-+ int eMode, /* PASSIVE, FULL or RESTART */
++ int eMode, /* PASSIVE, FULL, RESTART, or TRUNCATE */
+ int (*xBusy)(void*), /* Function to call when busy */
+ void *pBusyArg, /* Context argument for xBusyHandler */
+ int sync_flags, /* Flags to sync db file with (or 0) */
@@ -9729,6 +43457,7 @@
+ int rc; /* Return code */
+ int isChanged = 0; /* True if a new wal-index header is loaded */
+ int eMode2 = eMode; /* Mode to pass to walCheckpoint() */
++ int (*xBusy2)(void*) = xBusy; /* Busy handler for eMode2 */
-/*
-** Allowed values for BtShared.btsFlags
@@ -9750,25 +43479,16 @@
-*/
-typedef struct CellInfo CellInfo;
-struct CellInfo {
-- i64 nKey; /* The key for INTKEY tables, or number of bytes in key */
-- u8 *pCell; /* Pointer to the start of cell content */
-- u32 nData; /* Number of bytes of data */
-- u32 nPayload; /* Total amount of payload */
-- u16 nHeader; /* Size of the cell content header in bytes */
-- u16 nLocal; /* Amount of payload held locally */
+- i64 nKey; /* The key for INTKEY tables, or nPayload otherwise */
+- u8 *pPayload; /* Pointer to the start of payload */
+- u32 nPayload; /* Bytes of payload */
+- u16 nLocal; /* Amount of payload held locally, not on overflow */
- u16 iOverflow; /* Offset to overflow page number. Zero if no overflow */
- u16 nSize; /* Size of the cell content on the main b-tree page */
-};
-+ if( pWal->readOnly ) return SQLITE_READONLY;
-+ WALTRACE(("WAL%p: checkpoint begins\n", pWal));
-+ rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
-+ if( rc ){
-+ /* Usually this is SQLITE_BUSY meaning that another thread or process
-+ ** is already running a checkpoint, or maybe a recovery. But it might
-+ ** also be SQLITE_IOERR. */
-+ return rc;
-+ }
-+ pWal->ckptLock = 1;
++ /* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked
++ ** in the SQLITE_CHECKPOINT_PASSIVE mode. */
++ assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 );
-/*
-** Maximum depth of an SQLite B-Tree structure. Any B-Tree deeper than
@@ -9780,24 +43500,8 @@
-** assumed that the database is corrupt.
-*/
-#define BTCURSOR_MAX_DEPTH 20
-+ /* If this is a blocking-checkpoint, then obtain the write-lock as well
-+ ** to prevent any writers from running while the checkpoint is underway.
-+ ** This has to be done before the call to walIndexReadHdr() below.
-+ **
-+ ** If the writer lock cannot be obtained, then a passive checkpoint is
-+ ** run instead. Since the checkpointer is not holding the writer lock,
-+ ** there is no point in blocking waiting for any readers. Assuming no
-+ ** other error occurs, this function will return SQLITE_BUSY to the caller.
-+ */
-+ if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){
-+ rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_WRITE_LOCK, 1);
-+ if( rc==SQLITE_OK ){
-+ pWal->writeLock = 1;
-+ }else if( rc==SQLITE_BUSY ){
-+ eMode2 = SQLITE_CHECKPOINT_PASSIVE;
-+ rc = SQLITE_OK;
-+ }
-+ }
++ if( pWal->readOnly ) return SQLITE_READONLY;
++ WALTRACE(("WAL%p: checkpoint begins\n", pWal));
-/*
-** A cursor is a pointer to a particular entry within a particular
@@ -9812,6 +43516,11 @@
-**
-** Fields in this structure are accessed under the BtShared.mutex
-** found at self->pBt->mutex.
+-**
+-** skipNext meaning:
+-** eState==SKIPNEXT && skipNext>0: Next sqlite3BtreeNext() is no-op.
+-** eState==SKIPNEXT && skipNext<0: Next sqlite3BtreePrevious() is no-op.
+-** eState==FAULT: Cursor fault with skipNext as error code.
-*/
-struct BtCursor {
- Btree *pBtree; /* The Btree to which this cursor belongs */
@@ -9824,7 +43533,8 @@
- void *pKey; /* Saved key that was cursor last known position */
- Pgno pgnoRoot; /* The root page of this tree */
- int nOvflAlloc; /* Allocated size of aOverflow[] array */
-- int skipNext; /* Prev() is noop if negative. Next() is noop if positive */
+- int skipNext; /* Prev() is noop if negative. Next() is noop if positive.
+- ** Error code if eState==CURSOR_FAULT */
- u8 curFlags; /* zero or more BTCF_* flags defined below */
- u8 eState; /* One of the CURSOR_XXX constants (see below) */
- u8 hints; /* As configured by CursorSetHints() */
@@ -9832,13 +43542,21 @@
- u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */
- MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */
-};
-+ /* Read the wal-index header. */
-+ if( rc==SQLITE_OK ){
-+ rc = walIndexReadHdr(pWal, &isChanged);
-+ if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
-+ sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
-+ }
++ /* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive
++ ** "checkpoint" lock on the database file. */
++ rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1, 0);
++ if( rc ){
++ /* EVIDENCE-OF: R-10421-19736 If any other process is running a
++ ** checkpoint operation at the same time, the lock cannot be obtained and
++ ** SQLITE_BUSY is returned.
++ ** EVIDENCE-OF: R-53820-33897 Even if there is a busy-handler configured,
++ ** it will not be invoked in this case.
++ */
++ testcase( rc==SQLITE_BUSY );
++ testcase( xBusy!=0 );
++ return rc;
+ }
++ pWal->ckptLock = 1;
-/*
-** Legal values for BtCursor.curFlags
@@ -9848,13 +43566,25 @@
-#define BTCF_ValidOvfl 0x04 /* True if aOverflow is valid */
-#define BTCF_AtLast 0x08 /* Cursor is pointing ot the last entry */
-#define BTCF_Incrblob 0x10 /* True if an incremental I/O handle */
-+ /* 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{
-+ rc = walCheckpoint(pWal, eMode2, xBusy, pBusyArg, sync_flags, zBuf);
++ /* IMPLEMENTATION-OF: R-59782-36818 The SQLITE_CHECKPOINT_FULL, RESTART and
++ ** TRUNCATE modes also obtain the exclusive "writer" lock on the database
++ ** file.
++ **
++ ** EVIDENCE-OF: R-60642-04082 If the writer lock cannot be obtained
++ ** immediately, and a busy-handler is configured, it is invoked and the
++ ** writer lock retried until either the busy-handler returns 0 or the
++ ** lock is successfully obtained.
++ */
++ if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){
++ rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_WRITE_LOCK, 1);
++ if( rc==SQLITE_OK ){
++ pWal->writeLock = 1;
++ }else if( rc==SQLITE_BUSY ){
++ eMode2 = SQLITE_CHECKPOINT_PASSIVE;
++ xBusy2 = 0;
++ rc = SQLITE_OK;
+ }
++ }
-/*
-** Potential values for BtCursor.eState.
@@ -9880,21 +43610,22 @@
-** seek the cursor to the saved position.
-**
-** CURSOR_FAULT:
--** A unrecoverable error (an I/O error or a malloc failure) has occurred
+-** An unrecoverable error (an I/O error or a malloc failure) has occurred
-** on a different connection that shares the BtShared cache with this
-** cursor. The error has left the cache in an inconsistent state.
-** Do nothing else with this cursor. Any attempt to use the cursor
--** should return the error code stored in BtCursor.skip
+-** should return the error code stored in BtCursor.skipNext
-*/
-#define CURSOR_INVALID 0
-#define CURSOR_VALID 1
-#define CURSOR_SKIPNEXT 2
-#define CURSOR_REQUIRESEEK 3
-#define CURSOR_FAULT 4
-+ /* If no error occurred, set the output variables. */
-+ if( rc==SQLITE_OK || rc==SQLITE_BUSY ){
-+ if( pnLog ) *pnLog = (int)pWal->hdr.mxFrame;
-+ if( pnCkpt ) *pnCkpt = (int)(walCkptInfo(pWal)->nBackfill);
++ /* Read the wal-index header. */
++ if( rc==SQLITE_OK ){
++ rc = walIndexReadHdr(pWal, &isChanged);
++ if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
++ sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
+ }
+ }
@@ -9902,15 +43633,13 @@
-** The database page the PENDING_BYTE occupies. This page is never used.
-*/
-# define PENDING_BYTE_PAGE(pBt) PAGER_MJ_PGNO(pBt)
-+ if( isChanged ){
-+ /* If a new wal-index header was loaded before the checkpoint was
-+ ** performed, then the pager-cache associated with pWal is now
-+ ** out of date. So zero the cached wal-index header to ensure that
-+ ** next time the pager opens a snapshot on this database it knows that
-+ ** the cache needs to be reset.
-+ */
-+ memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
-+ }
++ /* 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{
++ rc = walCheckpoint(pWal, eMode2, xBusy2, pBusyArg, sync_flags, zBuf);
++ }
-/*
-** These macros define the location of the pointer-map entry for a
@@ -9926,6 +43655,23 @@
-** then pgno is returned. So (pgno==PTRMAP_PAGENO(pgsz, pgno)) can be
-** used to test if pgno is a pointer-map page. PTRMAP_ISPAGE implements
-** this test.
++ /* If no error occurred, set the output variables. */
++ if( rc==SQLITE_OK || rc==SQLITE_BUSY ){
++ if( pnLog ) *pnLog = (int)pWal->hdr.mxFrame;
++ if( pnCkpt ) *pnCkpt = (int)(walCkptInfo(pWal)->nBackfill);
++ }
++ }
++
++ if( isChanged ){
++ /* If a new wal-index header was loaded before the checkpoint was
++ ** performed, then the pager-cache associated with pWal is now
++ ** out of date. So zero the cached wal-index header to ensure that
++ ** next time the pager opens a snapshot on this database it knows that
++ ** the cache needs to be reset.
++ */
++ memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
++ }
++
+ /* Release the locks. */
+ sqlite3WalEndWriteTransaction(pWal);
+ walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
@@ -10103,6 +43849,8 @@
- int mxErr; /* Stop accumulating errors when this reaches zero */
- int nErr; /* Number of messages written to zErrMsg so far */
- int mallocFailed; /* A memory allocation error has occurred */
+- const char *zPfx; /* Error message prefix */
+- int v1, v2; /* Values for up to two %d fields in zPfx */
- StrAccum errMsg; /* Accumulate the error message text here */
-};
-
@@ -10132,7 +43880,7 @@
#ifndef SQLITE_OMIT_SHARED_CACHE
#if SQLITE_THREADSAFE
-@@ -93233,10 +96142,24 @@
+@@ -98030,10 +101008,24 @@
*/
SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
int rc = sqlite3_overload_function(db, "MATCH", 2);
@@ -10157,7 +43905,7 @@
}
/*
-@@ -98888,24 +101811,6 @@
+@@ -103838,24 +106830,6 @@
return azModeName[eMode];
}
@@ -10182,20 +43930,19 @@
/*
** Process a pragma statement.
**
-@@ -98939,6 +101844,12 @@
- sqlite3 *db = pParse->db; /* The database connection */
+@@ -103890,6 +106864,11 @@
Db *pDb; /* The specific database being pragmaed */
Vdbe *v = sqlite3GetVdbe(pParse); /* Prepared statement */
+ const struct sPragmaNames *pPragma;
+/* BEGIN SQLCIPHER */
+#ifdef SQLITE_HAS_CODEC
+ extern int sqlcipher_codec_pragma(sqlite3*, int, Parse *, const char *, const char *);
+#endif
+/* END SQLCIPHER */
-+
if( v==0 ) return;
sqlite3VdbeRunOnlyOnce(v);
-@@ -98999,8 +101910,18 @@
+@@ -103961,8 +106940,18 @@
}
pParse->nErr++;
pParse->rc = rc;
@@ -10214,7 +43961,7 @@
/* Locate the pragma in the lookup table */
lwr = 0;
-@@ -99632,54 +102553,6 @@
+@@ -104602,54 +107591,6 @@
#ifndef SQLITE_OMIT_SCHEMA_PRAGMAS
/*
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]