[libgda] Switched to SQlite 3.7.17 and SlqCipher 2.2.0
- From: Vivien Malerba <vivien src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libgda] Switched to SQlite 3.7.17 and SlqCipher 2.2.0
- Date: Sun, 30 Jun 2013 16:29:33 +0000 (UTC)
commit fd2e8b3f3b08bb71830810967babe063a4b1ca95
Author: Vivien Malerba <malerba gnome-db org>
Date: Sun Jun 30 15:38:59 2013 +0200
Switched to SQlite 3.7.17 and SlqCipher 2.2.0
libgda/sqlite/sqlite-src/PragmasPatch | 6 +-
libgda/sqlite/sqlite-src/sqlite3.c |11692 ++++--
libgda/sqlite/sqlite-src/sqlite3.h | 192 +-
providers/sqlcipher/sqlcipher.patch |65083 ++++++++++++++++++++++++++++++++-
4 files changed, 71384 insertions(+), 5589 deletions(-)
---
diff --git a/libgda/sqlite/sqlite-src/PragmasPatch b/libgda/sqlite/sqlite-src/PragmasPatch
index b0b53da..a8f87f9 100644
--- a/libgda/sqlite/sqlite-src/PragmasPatch
+++ b/libgda/sqlite/sqlite-src/PragmasPatch
@@ -1,6 +1,6 @@
---- sqlite3.c.orig 2012-10-04 21:49:28.000000000 +0200
-+++ sqlite3.c 2012-12-22 18:10:51.472282229 +0100
-@@ -92000,6 +92000,60 @@
+--- sqlite3.c.orig 2013-05-20 12:56:34.000000000 +0200
++++ sqlite3.c 2013-06-30 15:08:52.994949387 +0200
+@@ -94348,6 +94348,60 @@
#ifndef SQLITE_OMIT_SCHEMA_PRAGMAS
/*
diff --git a/libgda/sqlite/sqlite-src/sqlite3.c b/libgda/sqlite/sqlite-src/sqlite3.c
index 712a8bc..3e7d7a5 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.7.14.1. By combining all the individual C code files into this
+** version 3.7.17. 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
@@ -306,6 +306,10 @@
# define _GNU_SOURCE
#endif
+#if defined(__OpenBSD__) && !defined(_BSD_SOURCE)
+# define _BSD_SOURCE
+#endif
+
/*
** Include standard header files as necessary
*/
@@ -358,11 +362,11 @@
** We support that for legacy.
*/
#if !defined(SQLITE_THREADSAFE)
-#if defined(THREADSAFE)
-# define SQLITE_THREADSAFE THREADSAFE
-#else
-# define SQLITE_THREADSAFE 1 /* IMP: R-07272-22309 */
-#endif
+# if defined(THREADSAFE)
+# define SQLITE_THREADSAFE THREADSAFE
+# else
+# define SQLITE_THREADSAFE 1 /* IMP: R-07272-22309 */
+# endif
#endif
/*
@@ -440,7 +444,8 @@
**
** See also ticket #2741.
*/
-#if !defined(_XOPEN_SOURCE) && !defined(__DARWIN__) && !defined(__APPLE__) && SQLITE_THREADSAFE
+#if !defined(_XOPEN_SOURCE) && !defined(__DARWIN__) \
+ && !defined(__APPLE__) && SQLITE_THREADSAFE
# define _XOPEN_SOURCE 500 /* Needed to enable pthread recursive mutexes */
#endif
@@ -673,9 +678,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.7.14.1"
-#define SQLITE_VERSION_NUMBER 3007014
-#define SQLITE_SOURCE_ID "2012-10-04 19:37:12 091570e46d04e84b67228e0bdbcd6e1fb60c6bdb"
+#define SQLITE_VERSION "3.7.17"
+#define SQLITE_VERSION_NUMBER 3007017
+#define SQLITE_SOURCE_ID "2013-05-20 00:56:22 118a3b35693b134d56ebd780123b7fd6f1497668"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -854,7 +859,7 @@ typedef sqlite_uint64 sqlite3_uint64;
** [sqlite3_blob_close | close] all [BLOB handles], and
** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated
** with the [sqlite3] object prior to attempting to close the object. ^If
-** sqlite3_close() is called on a [database connection] that still has
+** sqlite3_close_v2() is called on a [database connection] that still has
** outstanding [prepared statements], [BLOB handles], and/or
** [sqlite3_backup] objects then it returns SQLITE_OK but the deallocation
** of resources is deferred until all [prepared statements], [BLOB handles],
@@ -991,6 +996,8 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_FORMAT 24 /* Auxiliary database format error */
#define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */
#define SQLITE_NOTADB 26 /* File opened that is not a database file */
+#define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */
+#define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */
#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */
#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */
/* end-of-error-codes */
@@ -1040,14 +1047,29 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8))
#define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8))
#define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8))
+#define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23<<8))
+#define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24<<8))
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8))
+#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8))
#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
+#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8))
#define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8))
+#define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1<<8))
+#define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2<<8))
+#define SQLITE_CONSTRAINT_FOREIGNKEY (SQLITE_CONSTRAINT | (3<<8))
+#define SQLITE_CONSTRAINT_FUNCTION (SQLITE_CONSTRAINT | (4<<8))
+#define SQLITE_CONSTRAINT_NOTNULL (SQLITE_CONSTRAINT | (5<<8))
+#define SQLITE_CONSTRAINT_PRIMARYKEY (SQLITE_CONSTRAINT | (6<<8))
+#define SQLITE_CONSTRAINT_TRIGGER (SQLITE_CONSTRAINT | (7<<8))
+#define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8))
+#define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8))
+#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8))
+#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
/*
** CAPI3REF: Flags For File Open Operations
@@ -1287,6 +1309,9 @@ struct sqlite3_io_methods {
void (*xShmBarrier)(sqlite3_file*);
int (*xShmUnmap)(sqlite3_file*, int deleteFlag);
/* Methods above are valid for version 2 */
+ int (*xFetch)(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);
+ int (*xUnfetch)(sqlite3_file*, sqlite3_int64 iOfst, void *p);
+ /* Methods above are valid for version 3 */
/* Additional methods may be added in future releases */
};
@@ -1421,6 +1446,38 @@ struct sqlite3_io_methods {
** compilation of the PRAGMA fails with an error. ^The [SQLITE_FCNTL_PRAGMA]
** file control occurs at the beginning of pragma statement analysis and so
** it is able to override built-in [PRAGMA] statements.
+**
+** <li>[[SQLITE_FCNTL_BUSYHANDLER]]
+** ^The [SQLITE_FCNTL_BUSYHANDLER]
+** file-control may be invoked by SQLite on the database file handle
+** shortly after it is opened in order to provide a custom VFS with access
+** to the connections busy-handler callback. The argument is of type (void **)
+** - an array of two (void *) values. The first (void *) actually points
+** to a function of type (int (*)(void *)). In order to invoke the connections
+** busy-handler, this function should be invoked with the second (void *) in
+** the array as the only argument. If it returns non-zero, then the operation
+** should be retried. If it returns zero, the custom VFS should abandon the
+** current operation.
+**
+** <li>[[SQLITE_FCNTL_TEMPFILENAME]]
+** ^Application can invoke the [SQLITE_FCNTL_TEMPFILENAME] file-control
+** to have SQLite generate a
+** temporary filename using the same algorithm that is followed to generate
+** temporary filenames for TEMP tables and other internal uses. The
+** argument should be a char** which will be filled with the filename
+** written into memory obtained from [sqlite3_malloc()]. The caller should
+** invoke [sqlite3_free()] on the result to avoid a memory leak.
+**
+** <li>[[SQLITE_FCNTL_MMAP_SIZE]]
+** The [SQLITE_FCNTL_MMAP_SIZE] file control is used to query or set the
+** maximum number of bytes that will be used for memory-mapped I/O.
+** The argument is a pointer to a value of type sqlite3_int64 that
+** is an advisory maximum number of bytes in the file to memory map. The
+** pointer is overwritten with the old value. The limit is not changed if
+** the value originally pointed to is negative, and so the current limit
+** can be queried by passing in a pointer to a negative number. This
+** file-control is used internally to implement [PRAGMA mmap_size].
+**
** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE 1
@@ -1437,6 +1494,9 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_VFSNAME 12
#define SQLITE_FCNTL_POWERSAFE_OVERWRITE 13
#define SQLITE_FCNTL_PRAGMA 14
+#define SQLITE_FCNTL_BUSYHANDLER 15
+#define SQLITE_FCNTL_TEMPFILENAME 16
+#define SQLITE_FCNTL_MMAP_SIZE 18
/*
** CAPI3REF: Mutex Handle
@@ -2103,7 +2163,9 @@ struct sqlite3_mem_methods {
** page cache implementation into that object.)^ </dd>
**
** [[SQLITE_CONFIG_LOG]] <dt>SQLITE_CONFIG_LOG</dt>
-** <dd> ^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a
+** <dd> The SQLITE_CONFIG_LOG option is used to configure the SQLite
+** global [error log].
+** (^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a
** function with a call signature of void(*)(void*,int,const char*),
** and a pointer to void. ^If the function pointer is not NULL, it is
** invoked by [sqlite3_log()] to process each logging event. ^If the
@@ -2133,10 +2195,54 @@ struct sqlite3_mem_methods {
** disabled. The default value may be changed by compiling with the
** [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
+** 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
+** is because some incorrectly coded legacy applications might malfunction
+** malfunction when the optimization is enabled. Providing the ability to
+** disable the optimization allows the older, buggy application code to work
+** without change even with newer versions of SQLite.
+**
** [[SQLITE_CONFIG_PCACHE]] [[SQLITE_CONFIG_GETPCACHE]]
** <dt>SQLITE_CONFIG_PCACHE and SQLITE_CONFIG_GETPCACHE
** <dd> These options are obsolete and should not be used by new code.
** They are retained for backwards compatibility but are now no-ops.
+** </dd>
+**
+** [[SQLITE_CONFIG_SQLLOG]]
+** <dt>SQLITE_CONFIG_SQLLOG
+** <dd>This option is only available if sqlite is compiled with the
+** [SQLITE_ENABLE_SQLLOG] pre-processor macro defined. The first argument should
+** be a pointer to a function of type void(*)(void*,sqlite3*,const char*, int).
+** The second should be of type (void*). The callback is invoked by the library
+** in three separate circumstances, identified by the value passed as the
+** fourth parameter. If the fourth parameter is 0, then the database connection
+** passed as the second argument has just been opened. The third argument
+** points to a buffer containing the name of the main database file. If the
+** fourth parameter is 1, then the SQL statement that the third parameter
+** points to has just been executed. Or, if the fourth parameter is 2, then
+** the connection being passed as the second parameter is being closed. The
+** third parameter is passed NULL In this case. An example of using this
+** configuration option can be seen in the "test_sqllog.c" source file in
+** the canonical SQLite source tree.</dd>
+**
+** [[SQLITE_CONFIG_MMAP_SIZE]]
+** <dt>SQLITE_CONFIG_MMAP_SIZE
+** <dd>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.
+** 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
+** [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.
** </dl>
*/
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
@@ -2158,6 +2264,9 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_URI 17 /* int */
#define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */
#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */
+#define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */
+#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
+#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */
/*
** CAPI3REF: Database Connection Configuration Options
@@ -2991,6 +3100,9 @@ SQLITE_API int sqlite3_set_authorizer(
** as each triggered subprogram is entered. The callbacks for triggers
** contain a UTF-8 SQL comment that identifies the trigger.)^
**
+** The [SQLITE_TRACE_SIZE_LIMIT] compile-time option can be used to limit
+** the length of [bound parameter] expansion in the output of sqlite3_trace().
+**
** ^The callback function registered by sqlite3_profile() is invoked
** as each SQL statement finishes. ^The profile callback contains
** the original statement text and an estimate of wall-clock time
@@ -3166,7 +3278,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** an error)^.
** ^If "ro" is specified, then the database is opened for read-only
** access, just as if the [SQLITE_OPEN_READONLY] flag had been set in the
-** third argument to sqlite3_prepare_v2(). ^If the mode option is set to
+** third argument to sqlite3_open_v2(). ^If the mode option is set to
** "rw", then the database is opened for read-write (but not create)
** access, as if SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had
** been set. ^Value "rwc" is equivalent to setting both
@@ -3182,7 +3294,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** sqlite3_open_v2(). ^Setting the cache parameter to "private" is
** equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit.
** ^If sqlite3_open_v2() is used and the "cache" parameter is present in
-** a URI filename, its value overrides any behaviour requested by setting
+** a URI filename, its value overrides any behavior requested by setting
** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag.
** </ul>
**
@@ -3318,6 +3430,11 @@ SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int
** However, the error string might be overwritten or deallocated by
** subsequent calls to other SQLite interface functions.)^
**
+** ^The sqlite3_errstr() interface returns the English-language text
+** that describes the [result code], as UTF-8.
+** ^(Memory to hold the error message string is managed internally
+** and must not be freed by the application)^.
+**
** When the serialized [threading mode] is in use, it might be the
** case that a second error occurs on a separate thread in between
** the time of the first error and the call to these interfaces.
@@ -3336,6 +3453,7 @@ 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);
/*
** CAPI3REF: SQL Statement Object
@@ -3523,7 +3641,8 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** <li>
** ^If the database schema changes, instead of returning [SQLITE_SCHEMA] as it
** always used to do, [sqlite3_step()] will automatically recompile the SQL
-** statement and try to run it again.
+** statement and try to run it again. As many as [SQLITE_MAX_SCHEMA_RETRY]
+** retries will occur before sqlite3_step() gives up and returns an error.
** </li>
**
** <li>
@@ -3727,6 +3846,9 @@ typedef struct sqlite3_context sqlite3_context;
** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 999).
**
** ^The third argument is the value to bind to the parameter.
+** ^If the third parameter to sqlite3_bind_text() or sqlite3_bind_text16()
+** or sqlite3_bind_blob() is a NULL pointer then the fourth parameter
+** is ignored and the end result is the same as sqlite3_bind_null().
**
** ^(In those routines that have a fourth argument, its value is the
** number of bytes in the parameter. To be clear: the value is the
@@ -4494,7 +4616,8 @@ 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),void*,sqlite3_int64);
+SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
+ void*,sqlite3_int64);
#endif
/*
@@ -4574,14 +4697,17 @@ SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
** In those cases, sqlite3_aggregate_context() might be called for the
** first time from within xFinal().)^
**
-** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer if N is
-** less than or equal to zero or if a memory allocate error occurs.
+** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer
+** when first called if N is less than or equal to zero or if a memory
+** allocate error occurs.
**
** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is
** determined by the N parameter on first successful call. Changing the
** value of N in subsequent call to sqlite3_aggregate_context() within
** the same aggregate function instance will not resize the memory
-** allocation.)^
+** allocation.)^ Within the xFinal callback, it is customary to set
+** N=0 in calls to sqlite3_aggregate_context(C,N) so that no
+** pointless memory allocations occur.
**
** ^SQLite automatically frees the memory allocated by
** sqlite3_aggregate_context() when the aggregate query concludes.
@@ -4679,7 +4805,7 @@ SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(voi
** the content before returning.
**
** The typedef is necessary to work around problems in certain
-** C++ compilers. See ticket #2191.
+** C++ compilers.
*/
typedef void (*sqlite3_destructor_type)(void*);
#define SQLITE_STATIC ((sqlite3_destructor_type)0)
@@ -5298,6 +5424,9 @@ SQLITE_API void *sqlite3_update_hook(
** future releases of SQLite. Applications that care about shared
** cache setting should set it explicitly.
**
+** 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);
@@ -5475,11 +5604,20 @@ SQLITE_API int sqlite3_table_column_metadata(
** ^This interface loads an SQLite extension library from the named file.
**
** ^The sqlite3_load_extension() interface attempts to load an
-** SQLite extension library contained in the file zFile.
+** [SQLite extension] library contained in the file zFile. If
+** the file cannot be loaded directly, attempts are made to load
+** with various operating-system specific extensions added.
+** So for example, if "samplelib" cannot be loaded, then names like
+** "samplelib.so" or "samplelib.dylib" or "samplelib.dll" might
+** be tried also.
**
** ^The entry point is zProc.
-** ^zProc may be 0, in which case the name of the entry point
-** defaults to "sqlite3_extension_init".
+** ^(zProc may be 0, in which case SQLite will try to come up with an
+** entry point name on its own. It first tries "sqlite3_extension_init".
+** If that does not work, it constructs a name "sqlite3_X_init" where the
+** X is consists of the lower-case equivalent of all ASCII alphabetic
+** characters in the filename from the last "/" to the first following
+** "." and omitting any initial "lib".)^
** ^The sqlite3_load_extension() interface returns
** [SQLITE_OK] on success and [SQLITE_ERROR] if something goes wrong.
** ^If an error occurs and pzErrMsg is not 0, then the
@@ -5505,11 +5643,11 @@ SQLITE_API int sqlite3_load_extension(
** CAPI3REF: Enable Or Disable Extension Loading
**
** ^So as not to open security holes in older applications that are
-** unprepared to deal with extension loading, and as a means of disabling
-** extension loading while evaluating user-entered SQL, the following API
+** unprepared to deal with [extension loading], and as a means of disabling
+** [extension loading] while evaluating user-entered SQL, the following API
** is provided to turn the [sqlite3_load_extension()] mechanism on and off.
**
-** ^Extension loading is off by default. See ticket #1863.
+** ^Extension loading is off by default.
** ^Call the sqlite3_enable_load_extension() routine with onoff==1
** to turn extension loading on and call it with onoff==0 to turn
** it back off again.
@@ -5521,7 +5659,7 @@ SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
**
** ^This interface causes the xEntryPoint() function to be invoked for
** each new [database connection] that is created. The idea here is that
-** xEntryPoint() is the entry point for a statically linked SQLite extension
+** xEntryPoint() is the entry point for a statically linked [SQLite extension]
** that is to be automatically loaded into all new database connections.
**
** ^(Even though the function prototype shows that xEntryPoint() takes
@@ -6872,7 +7010,7 @@ struct sqlite3_pcache_page {
** parameter to help it determined what action to take:
**
** <table border=1 width=85% align=center>
-** <tr><th> createFlag <th> Behaviour when page is not already in cache
+** <tr><th> createFlag <th> Behavior when page is not already in cache
** <tr><td> 0 <td> Do not allocate a new page. Return NULL.
** <tr><td> 1 <td> Allocate a new page if it easy and convenient to do so.
** Otherwise return NULL.
@@ -7302,9 +7440,24 @@ SQLITE_API int sqlite3_stricmp(const char *, const char *);
SQLITE_API int sqlite3_strnicmp(const char *, const char *, int);
/*
+** CAPI3REF: String Globbing
+*
+** ^The [sqlite3_strglob(P,X)] interface returns zero if string X matches
+** the glob pattern P, and it returns non-zero if string X does not match
+** the glob pattern P. ^The definition of glob pattern matching used in
+** [sqlite3_strglob(P,X)] is the same as for the "X GLOB P" operator in the
+** SQL dialect used by SQLite. ^The sqlite3_strglob(P,X) function is case
+** sensitive.
+**
+** 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);
+
+/*
** CAPI3REF: Error Logging Interface
**
-** ^The [sqlite3_log()] interface writes a message into the error log
+** ^The [sqlite3_log()] interface writes a message into the [error log]
** established by the [SQLITE_CONFIG_LOG] option to [sqlite3_config()].
** ^If logging is enabled, the zFormat string and subsequent arguments are
** used with [sqlite3_snprintf()] to generate the final output string.
@@ -7677,7 +7830,7 @@ struct sqlite3_rtree_geometry {
** May you share freely, never taking more than you give.
**
*************************************************************************
-** This is the header file for the generic hash-table implemenation
+** This is the header file for the generic hash-table implementation
** used in SQLite.
*/
#ifndef _SQLITE_HASH_H_
@@ -7989,6 +8142,7 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
*/
#ifndef SQLITE_TEMP_STORE
# define SQLITE_TEMP_STORE 1
+# define SQLITE_TEMP_STORE_xc 1 /* Exclude from ctime.c */
#endif
/*
@@ -8136,6 +8290,49 @@ SQLITE_PRIVATE const int sqlite3one;
# define EIGHT_BYTE_ALIGNMENT(X) ((((char*)(X) - (char*)0)&7)==0)
#endif
+/*
+** Disable MMAP on platforms where it is known to not work
+*/
+#if defined(__OpenBSD__) || defined(__QNXNTO__)
+# undef SQLITE_MAX_MMAP_SIZE
+# define SQLITE_MAX_MMAP_SIZE 0
+#endif
+
+/*
+** Default maximum size of memory used by memory-mapped I/O in the VFS
+*/
+#ifdef __APPLE__
+# include <TargetConditionals.h>
+# if TARGET_OS_IPHONE
+# undef SQLITE_MAX_MMAP_SIZE
+# define SQLITE_MAX_MMAP_SIZE 0
+# endif
+#endif
+#ifndef SQLITE_MAX_MMAP_SIZE
+# if defined(__linux__) \
+ || defined(_WIN32) \
+ || (defined(__APPLE__) && defined(__MACH__)) \
+ || defined(__sun)
+# define SQLITE_MAX_MMAP_SIZE 0x7fff0000 /* 2147418112 */
+# else
+# define SQLITE_MAX_MMAP_SIZE 0
+# endif
+# define SQLITE_MAX_MMAP_SIZE_xc 1 /* exclude from ctime.c */
+#endif
+
+/*
+** The default MMAP_SIZE is zero on all platforms. Or, even if a larger
+** default MMAP_SIZE is specified at compile-time, make sure that it does
+** not exceed the maximum mmap size.
+*/
+#ifndef SQLITE_DEFAULT_MMAP_SIZE
+# define SQLITE_DEFAULT_MMAP_SIZE 0
+# define SQLITE_DEFAULT_MMAP_SIZE_xc 1 /* Exclude from ctime.c */
+#endif
+#if SQLITE_DEFAULT_MMAP_SIZE>SQLITE_MAX_MMAP_SIZE
+# undef SQLITE_DEFAULT_MMAP_SIZE
+# define SQLITE_DEFAULT_MMAP_SIZE SQLITE_MAX_MMAP_SIZE
+#endif
/*
** An instance of the following structure is used to store the busy-handler
@@ -8178,6 +8375,11 @@ struct BusyHandler {
#define ArraySize(X) ((int)(sizeof(X)/sizeof(X[0])))
/*
+** Determine if the argument is a power of two
+*/
+#define IsPowerOfTwo(X) (((X)&((X)-1))==0)
+
+/*
** The following value as a destructor means to use sqlite3DbFree().
** The sqlite3DbFree() routine requires two parameters instead of the
** one parameter that destructors normally want. So we have to introduce
@@ -8263,6 +8465,7 @@ typedef struct Parse Parse;
typedef struct RowSet RowSet;
typedef struct Savepoint Savepoint;
typedef struct Select Select;
+typedef struct SelectDest SelectDest;
typedef struct SrcList SrcList;
typedef struct StrAccum StrAccum;
typedef struct Table Table;
@@ -8351,6 +8554,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
SQLITE_PRIVATE int sqlite3BtreeClose(Btree*);
SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree*,int);
+SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64);
SQLITE_PRIVATE int sqlite3BtreeSetSafetyLevel(Btree*,int,int,int);
SQLITE_PRIVATE int sqlite3BtreeSyncDisabled(Btree*);
SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
@@ -8359,6 +8563,9 @@ 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 sqlite3BtreeGetReserveNoMutex(Btree *p);
+#endif
SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *, int);
SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *);
SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree*,int);
@@ -8402,6 +8609,8 @@ SQLITE_PRIVATE void sqlite3BtreeTripAllCursors(Btree*, int);
SQLITE_PRIVATE void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue);
SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
+SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p);
+
/*
** The second parameter to sqlite3BtreeGetMeta or sqlite3BtreeUpdateMeta
** should be one of the following values. The integer values are assigned
@@ -8422,6 +8631,7 @@ SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
#define BTREE_TEXT_ENCODING 5
#define BTREE_USER_VERSION 6
#define BTREE_INCR_VACUUM 7
+#define BTREE_APPLICATION_ID 8
/*
** Values that may be OR'd together to form the second argument of an
@@ -8869,7 +9079,7 @@ typedef struct VdbeOpList VdbeOpList;
#define OPFLG_OUT3 0x0040 /* out3: P3 is an output */
#define OPFLG_INITIALIZER {\
/* 0 */ 0x00, 0x01, 0x01, 0x04, 0x04, 0x10, 0x00, 0x02,\
-/* 8 */ 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x24, 0x24,\
+/* 8 */ 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x24,\
/* 16 */ 0x00, 0x00, 0x00, 0x24, 0x04, 0x05, 0x04, 0x00,\
/* 24 */ 0x00, 0x01, 0x01, 0x05, 0x05, 0x00, 0x00, 0x00,\
/* 32 */ 0x02, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00,\
@@ -8916,7 +9126,7 @@ SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe*);
SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe*);
SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe*);
-SQLITE_PRIVATE void sqlite3VdbeDeleteObject(sqlite3*,Vdbe*);
+SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3*,Vdbe*);
SQLITE_PRIVATE void sqlite3VdbeMakeReady(Vdbe*,Parse*);
SQLITE_PRIVATE int sqlite3VdbeFinalize(Vdbe*);
SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe*, int);
@@ -9047,6 +9257,12 @@ typedef struct PgHdr DbPage;
#define PAGER_JOURNALMODE_WAL 5 /* Use write-ahead logging */
/*
+** Flags that make up the mask passed to sqlite3PagerAcquire().
+*/
+#define PAGER_ACQUIRE_NOCONTENT 0x01 /* Do not load data from disk */
+#define PAGER_ACQUIRE_READONLY 0x02 /* Read-only page is acceptable */
+
+/*
** The remainder of this file contains the declarations of the functions
** that make up the Pager sub-system API. See source code comments for
** a detailed description of each routine.
@@ -9070,6 +9286,7 @@ SQLITE_PRIVATE void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *);
SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u32*, int);
SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager*, int);
SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int);
+SQLITE_PRIVATE void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64);
SQLITE_PRIVATE void sqlite3PagerShrink(Pager*);
SQLITE_PRIVATE void sqlite3PagerSetSafetyLevel(Pager*,int,int,int);
SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *, int);
@@ -9106,11 +9323,14 @@ SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int n);
SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint);
SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager);
-SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, int, int*, int*);
-SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager);
-SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager);
-SQLITE_PRIVATE int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
-SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager);
+#ifndef SQLITE_OMIT_WAL
+SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, int, int*, int*);
+SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager);
+SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager);
+SQLITE_PRIVATE int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
+SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager);
+#endif
+
#ifdef SQLITE_ENABLE_ZIPVFS
SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager);
#endif
@@ -9128,6 +9348,7 @@ SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*);
SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*);
SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *);
SQLITE_PRIVATE void sqlite3PagerClearCache(Pager *);
+SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *);
/* Functions used to truncate the database file. */
SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno);
@@ -9212,6 +9433,8 @@ struct PgHdr {
#define PGHDR_REUSE_UNLIKELY 0x010 /* A hint that reuse is unlikely */
#define PGHDR_DONT_WRITE 0x020 /* Do not write content to disk */
+#define PGHDR_MMAP 0x040 /* This is an mmap page object */
+
/* Initialize and shutdown the page cache subsystem */
SQLITE_PRIVATE int sqlite3PcacheInitialize(void);
SQLITE_PRIVATE void sqlite3PcacheShutdown(void);
@@ -9423,14 +9646,6 @@ SQLITE_PRIVATE void sqlite3PCacheSetDefault(void);
# define SQLITE_OS_WINRT 0
#endif
-/*
-** When compiled for WinCE or WinRT, there is no concept of the current
-** directory.
- */
-#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
-# define SQLITE_CURDIR 1
-#endif
-
/* If the SET_FULLSYNC macro is not defined above, then make it
** a no-op
*/
@@ -9583,6 +9798,8 @@ SQLITE_PRIVATE int sqlite3OsShmMap(sqlite3_file *,int,int,int,void volatile **);
SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int, int, int);
SQLITE_PRIVATE void sqlite3OsShmBarrier(sqlite3_file *id);
SQLITE_PRIVATE int sqlite3OsShmUnmap(sqlite3_file *id, int);
+SQLITE_PRIVATE int sqlite3OsFetch(sqlite3_file *id, i64, int, void **);
+SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *, i64, void *);
/*
@@ -9822,9 +10039,11 @@ struct sqlite3 {
int nDb; /* Number of backends currently in use */
int flags; /* Miscellaneous flags. See below */
i64 lastRowid; /* ROWID of most recent insert (see above) */
+ i64 szMmap; /* Default mmap_size setting */
unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */
int errCode; /* Most recent error code (SQLITE_*) */
int errMask; /* & result codes with this before returning */
+ u16 dbOptFlags; /* Flags to enable/disable optimizations */
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 */
@@ -9929,48 +10148,60 @@ struct sqlite3 {
/*
** Possible values for the sqlite3.flags.
*/
-#define SQLITE_VdbeTrace 0x00000100 /* True to trace VDBE execution */
-#define SQLITE_InternChanges 0x00000200 /* Uncommitted Hash table changes */
-#define SQLITE_FullColNames 0x00000400 /* Show full column names on SELECT */
-#define SQLITE_ShortColNames 0x00000800 /* Show short columns names */
-#define SQLITE_CountRows 0x00001000 /* Count rows changed by INSERT, */
+#define SQLITE_VdbeTrace 0x00000001 /* True to trace VDBE execution */
+#define SQLITE_InternChanges 0x00000002 /* Uncommitted Hash table changes */
+#define SQLITE_FullColNames 0x00000004 /* Show full column names on SELECT */
+#define SQLITE_ShortColNames 0x00000008 /* Show short columns names */
+#define SQLITE_CountRows 0x00000010 /* Count rows changed by INSERT, */
/* DELETE, or UPDATE and return */
/* the count using a callback. */
-#define SQLITE_NullCallback 0x00002000 /* Invoke the callback once if the */
+#define SQLITE_NullCallback 0x00000020 /* Invoke the callback once if the */
/* result set is empty */
-#define SQLITE_SqlTrace 0x00004000 /* Debug print SQL as it executes */
-#define SQLITE_VdbeListing 0x00008000 /* Debug listings of VDBE programs */
-#define SQLITE_WriteSchema 0x00010000 /* OK to update SQLITE_MASTER */
- /* 0x00020000 Unused */
-#define SQLITE_IgnoreChecks 0x00040000 /* Do not enforce check constraints */
-#define SQLITE_ReadUncommitted 0x0080000 /* For shared-cache mode */
-#define SQLITE_LegacyFileFmt 0x00100000 /* Create new databases in format 1 */
-#define SQLITE_FullFSync 0x00200000 /* Use full fsync on the backend */
-#define SQLITE_CkptFullFSync 0x00400000 /* Use full fsync for checkpoint */
-#define SQLITE_RecoveryMode 0x00800000 /* Ignore schema errors */
-#define SQLITE_ReverseOrder 0x01000000 /* Reverse unordered SELECTs */
-#define SQLITE_RecTriggers 0x02000000 /* Enable recursive triggers */
-#define SQLITE_ForeignKeys 0x04000000 /* Enforce foreign key constraints */
-#define SQLITE_AutoIndex 0x08000000 /* Enable automatic indexes */
-#define SQLITE_PreferBuiltin 0x10000000 /* Preference to built-in funcs */
-#define SQLITE_LoadExtension 0x20000000 /* Enable load_extension */
-#define SQLITE_EnableTrigger 0x40000000 /* True to enable triggers */
-
-/*
-** Bits of the sqlite3.flags field that are used by the
-** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface.
-** These must be the low-order bits of the flags field.
-*/
-#define SQLITE_QueryFlattener 0x01 /* Disable query flattening */
-#define SQLITE_ColumnCache 0x02 /* Disable the column cache */
-#define SQLITE_IndexSort 0x04 /* Disable indexes for sorting */
-#define SQLITE_IndexSearch 0x08 /* Disable indexes for searching */
-#define SQLITE_IndexCover 0x10 /* Disable index covering table */
-#define SQLITE_GroupByOrder 0x20 /* Disable GROUPBY cover of ORDERBY */
-#define SQLITE_FactorOutConst 0x40 /* Disable factoring out constants */
-#define SQLITE_IdxRealAsInt 0x80 /* Store REAL as INT in indices */
-#define SQLITE_DistinctOpt 0x80 /* DISTINCT using indexes */
-#define SQLITE_OptMask 0xff /* Mask of all disablable opts */
+#define SQLITE_SqlTrace 0x00000040 /* Debug print SQL as it executes */
+#define SQLITE_VdbeListing 0x00000080 /* Debug listings of VDBE programs */
+#define SQLITE_WriteSchema 0x00000100 /* OK to update SQLITE_MASTER */
+#define SQLITE_VdbeAddopTrace 0x00000200 /* Trace sqlite3VdbeAddOp() calls */
+#define SQLITE_IgnoreChecks 0x00000400 /* Do not enforce check constraints */
+#define SQLITE_ReadUncommitted 0x0000800 /* For shared-cache mode */
+#define SQLITE_LegacyFileFmt 0x00001000 /* Create new databases in format 1 */
+#define SQLITE_FullFSync 0x00002000 /* Use full fsync on the backend */
+#define SQLITE_CkptFullFSync 0x00004000 /* Use full fsync for checkpoint */
+#define SQLITE_RecoveryMode 0x00008000 /* Ignore schema errors */
+#define SQLITE_ReverseOrder 0x00010000 /* Reverse unordered SELECTs */
+#define SQLITE_RecTriggers 0x00020000 /* Enable recursive triggers */
+#define SQLITE_ForeignKeys 0x00040000 /* Enforce foreign key constraints */
+#define SQLITE_AutoIndex 0x00080000 /* Enable automatic indexes */
+#define SQLITE_PreferBuiltin 0x00100000 /* Preference to built-in funcs */
+#define SQLITE_LoadExtension 0x00200000 /* Enable load_extension */
+#define SQLITE_EnableTrigger 0x00400000 /* True to enable triggers */
+
+/*
+** Bits of the sqlite3.dbOptFlags field that are used by the
+** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface to
+** selectively disable various optimizations.
+*/
+#define SQLITE_QueryFlattener 0x0001 /* Query flattening */
+#define SQLITE_ColumnCache 0x0002 /* Column cache */
+#define SQLITE_GroupByOrder 0x0004 /* GROUPBY cover of ORDERBY */
+#define SQLITE_FactorOutConst 0x0008 /* Constant factoring */
+#define SQLITE_IdxRealAsInt 0x0010 /* Store REAL as INT in indices */
+#define SQLITE_DistinctOpt 0x0020 /* DISTINCT using indexes */
+#define SQLITE_CoverIdxScan 0x0040 /* Covering index scans */
+#define SQLITE_OrderByIdxJoin 0x0080 /* ORDER BY of joins via index */
+#define SQLITE_SubqCoroutine 0x0100 /* Evaluate subqueries as coroutines */
+#define SQLITE_Transitive 0x0200 /* Transitive constraints */
+#define SQLITE_AllOpts 0xffff /* All optimizations */
+
+/*
+** Macros for testing whether or not optimizations are enabled or disabled.
+*/
+#ifndef SQLITE_OMIT_BUILTIN_TEST
+#define OptimizationDisabled(db, mask) (((db)->dbOptFlags&(mask))!=0)
+#define OptimizationEnabled(db, mask) (((db)->dbOptFlags&(mask))==0)
+#else
+#define OptimizationDisabled(db, mask) 0
+#define OptimizationEnabled(db, mask) 1
+#endif
/*
** Possible values for the sqlite.magic field.
@@ -10121,32 +10352,22 @@ struct Column {
char *zDflt; /* Original text of the default value */
char *zType; /* Data type for this column */
char *zColl; /* Collating sequence. If NULL, use the default */
- u8 notNull; /* True if there is a NOT NULL constraint */
- u8 isPrimKey; /* True if this column is part of the PRIMARY KEY */
+ u8 notNull; /* An OE_ code for handling a NOT NULL constraint */
char affinity; /* One of the SQLITE_AFF_... values */
-#ifndef SQLITE_OMIT_VIRTUALTABLE
- u8 isHidden; /* True if this column is 'hidden' */
-#endif
+ u16 colFlags; /* Boolean properties. See COLFLAG_ defines below */
};
+/* Allowed values for Column.colFlags:
+*/
+#define COLFLAG_PRIMKEY 0x0001 /* Column is part of the primary key */
+#define COLFLAG_HIDDEN 0x0002 /* A hidden column in a virtual table */
+
/*
** A "Collating Sequence" is defined by an instance of the following
** structure. Conceptually, a collating sequence consists of a name and
** a comparison routine that defines the order of that sequence.
**
-** There may two separate implementations of the collation function, one
-** that processes text in UTF-8 encoding (CollSeq.xCmp) and another that
-** processes text encoded in UTF-16 (CollSeq.xCmp16), using the machine
-** native byte order. When a collation sequence is invoked, SQLite selects
-** the version that will require the least expensive encoding
-** translations, if any.
-**
-** The CollSeq.pUser member variable is an extra parameter that passed in
-** as the first argument to the UTF-8 comparison function, xCmp.
-** CollSeq.pUser16 is the equivalent for the UTF-16 comparison function,
-** xCmp16.
-**
-** If both CollSeq.xCmp and CollSeq.xCmp16 are NULL, it means that the
+** If CollSeq.xCmp is NULL, it means that the
** collating sequence is undefined. Indices built on an undefined
** collating sequence may not be read or written.
*/
@@ -10284,28 +10505,28 @@ struct VTable {
*/
struct Table {
char *zName; /* Name of the table or view */
- int iPKey; /* If not negative, use aCol[iPKey] as the primary key */
- int nCol; /* Number of columns in this table */
Column *aCol; /* Information about each column */
Index *pIndex; /* List of SQL indexes on this table. */
- int tnum; /* Root BTree node for this table (see note above) */
- tRowcnt nRowEst; /* Estimated rows in table - from sqlite_stat1 table */
Select *pSelect; /* NULL for tables. Points to definition if a view. */
- u16 nRef; /* Number of pointers to this Table */
- u8 tabFlags; /* Mask of TF_* values */
- u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */
FKey *pFKey; /* Linked list of all foreign keys in this table */
char *zColAff; /* String defining the affinity of each column */
#ifndef SQLITE_OMIT_CHECK
ExprList *pCheck; /* All CHECK constraints */
#endif
+ tRowcnt nRowEst; /* 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 */
+ i16 nCol; /* Number of columns in this table */
+ u16 nRef; /* Number of pointers to this Table */
+ u8 tabFlags; /* Mask of TF_* values */
+ u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */
#ifndef SQLITE_OMIT_ALTERTABLE
int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */
#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
- VTable *pVTable; /* List of VTable objects. */
int nModuleArg; /* Number of arguments to the module */
char **azModuleArg; /* Text of all module args. [0] is module name */
+ VTable *pVTable; /* List of VTable objects. */
#endif
Trigger *pTrigger; /* List of triggers stored in pSchema */
Schema *pSchema; /* Schema that contains this table */
@@ -10329,7 +10550,7 @@ struct Table {
*/
#ifndef SQLITE_OMIT_VIRTUALTABLE
# define IsVirtual(X) (((X)->tabFlags & TF_Virtual)!=0)
-# define IsHiddenColumn(X) ((X)->isHidden)
+# define IsHiddenColumn(X) (((X)->colFlags & COLFLAG_HIDDEN)!=0)
#else
# define IsVirtual(X) 0
# define IsHiddenColumn(X) 0
@@ -10480,20 +10701,20 @@ struct UnpackedRecord {
** element.
*/
struct Index {
- char *zName; /* Name of this index */
- int *aiColumn; /* Which columns are used by this index. 1st is 0 */
- tRowcnt *aiRowEst; /* Result of ANALYZE: Est. rows selected by each column */
- Table *pTable; /* The SQL table being indexed */
- char *zColAff; /* String defining the affinity of each column */
- Index *pNext; /* The next index associated with the same table */
- Schema *pSchema; /* Schema containing this index */
- u8 *aSortOrder; /* Array of size Index.nColumn. True==DESC, False==ASC */
- char **azColl; /* Array of collation sequence names for index */
- int nColumn; /* Number of columns in the table used by this index */
- int tnum; /* Page containing root of this index in database file */
- u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
- u8 autoIndex; /* True if is automatically created (ex: by UNIQUE) */
- u8 bUnordered; /* Use this index for == or IN queries only */
+ char *zName; /* Name of this index */
+ int *aiColumn; /* Which columns are used by this index. 1st is 0 */
+ tRowcnt *aiRowEst; /* From ANALYZE: Est. rows selected by each column */
+ Table *pTable; /* The SQL table being indexed */
+ char *zColAff; /* String defining the affinity of each column */
+ Index *pNext; /* The next index associated with the same table */
+ Schema *pSchema; /* Schema containing this index */
+ u8 *aSortOrder; /* for each column: True==DESC, False==ASC */
+ char **azColl; /* Array of collation sequence names for index */
+ int tnum; /* DB Page containing root of this index */
+ u16 nColumn; /* Number of columns in table used by this index */
+ u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
+ unsigned autoIndex:2; /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */
+ unsigned bUnordered:1; /* Use this index for == or IN queries only */
#ifdef SQLITE_ENABLE_STAT3
int nSample; /* Number of elements in aSample[] */
tRowcnt avgEq; /* Average nEq value for key values not in aSample */
@@ -10674,13 +10895,15 @@ struct Expr {
ExprList *pList; /* Function arguments or in "<expr> IN (<expr-list)" */
Select *pSelect; /* Used for sub-selects and "<expr> IN (<select>)" */
} x;
- CollSeq *pColl; /* The collation type of the column or 0 */
/* If the EP_Reduced flag is set in the Expr.flags mask, then no
** space is allocated for the fields below this point. An attempt to
** access them will result in a segfault or malfunction.
*********************************************************************/
+#if SQLITE_MAX_EXPR_DEPTH>0
+ int nHeight; /* Height of the tree headed by this node */
+#endif
int iTable; /* TK_COLUMN: cursor number of table holding column
** TK_REGISTER: register number
** TK_TRIGGER: 1 -> new, 0 -> old */
@@ -10694,9 +10917,6 @@ struct Expr {
** TK_AGG_FUNCTION: nesting depth */
AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
Table *pTab; /* Table for TK_COLUMN expressions. */
-#if SQLITE_MAX_EXPR_DEPTH>0
- int nHeight; /* Height of the tree headed by this node */
-#endif
};
/*
@@ -10710,7 +10930,7 @@ struct Expr {
#define EP_VarSelect 0x0020 /* pSelect is correlated, not constant */
#define EP_DblQuoted 0x0040 /* token.z was originally in "..." */
#define EP_InfixFunc 0x0080 /* True for an infix function: LIKE, GLOB, etc */
-#define EP_ExpCollate 0x0100 /* Collating sequence specified explicitly */
+#define EP_Collate 0x0100 /* Tree contains a TK_COLLATE opeartor */
#define EP_FixedDest 0x0200 /* Result needed in a specific register */
#define EP_IntValue 0x0400 /* Integer value contained in u.iValue */
#define EP_xIsSelect 0x0800 /* x.pSelect is valid (otherwise x.pList is) */
@@ -10768,18 +10988,27 @@ struct Expr {
** list of "ID = expr" items in an UPDATE. A list of expressions can
** also be used as the argument to a function, in which case the a.zName
** field is not used.
+**
+** By default the Expr.zSpan field holds a human-readable description of
+** the expression that is used in the generation of error messages and
+** column labels. In this case, Expr.zSpan is typically the text of a
+** column expression as it exists in a SELECT statement. However, if
+** the bSpanIsTab flag is set, then zSpan is overloaded to mean the name
+** of the result column in the form: DATABASE.TABLE.COLUMN. This later
+** form is used for name resolution with nested FROM clauses.
*/
struct ExprList {
int nExpr; /* Number of expressions on the list */
int iECursor; /* VDBE Cursor associated with this ExprList */
struct ExprList_item { /* For each expression in the list */
- Expr *pExpr; /* The list of expressions */
- char *zName; /* Token associated with this expression */
- char *zSpan; /* Original text of the expression */
- u8 sortOrder; /* 1 for DESC or 0 for ASC */
- u8 done; /* A flag to indicate when processing is finished */
- u16 iOrderByCol; /* For ORDER BY, column number in result set */
- u16 iAlias; /* Index into Parse.aAlias[] for zName */
+ Expr *pExpr; /* The list of expressions */
+ char *zName; /* Token associated with this expression */
+ char *zSpan; /* Original text of the expression */
+ u8 sortOrder; /* 1 for DESC or 0 for ASC */
+ unsigned done :1; /* A flag to indicate when processing is finished */
+ unsigned bSpanIsTab :1; /* zSpan holds DB.TABLE.COLUMN */
+ u16 iOrderByCol; /* For ORDER BY, column number in result set */
+ u16 iAlias; /* Index into Parse.aAlias[] for zName */
} *a; /* Alloc a power of two greater or equal to nExpr */
};
@@ -10854,6 +11083,7 @@ struct SrcList {
i16 nSrc; /* Number of tables or subqueries in the FROM clause */
i16 nAlloc; /* Number of entries allocated in a[] below */
struct SrcList_item {
+ Schema *pSchema; /* Schema to which this item is fixed */
char *zDatabase; /* Name of database holding this table */
char *zName; /* Name of the table */
char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */
@@ -10862,8 +11092,9 @@ struct SrcList {
int addrFillSub; /* Address of subroutine to manifest a subquery */
int regReturn; /* Register holding return address of addrFillSub */
u8 jointype; /* Type of join between this able and the previous */
- u8 notIndexed; /* True if there is a NOT INDEXED clause */
- u8 isCorrelated; /* True if sub-query is correlated */
+ unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */
+ unsigned isCorrelated :1; /* True if sub-query is correlated */
+ unsigned viaCoroutine :1; /* Implemented as a co-routine */
#ifndef SQLITE_OMIT_EXPLAIN
u8 iSelectId; /* If pSelect!=0, the id of the sub-select in EQP */
#endif
@@ -10904,7 +11135,8 @@ struct SrcList {
*/
struct WherePlan {
u32 wsFlags; /* WHERE_* flags that describe the strategy */
- u32 nEq; /* Number of == constraints */
+ u16 nEq; /* Number of == constraints */
+ u16 nOBSat; /* Number of ORDER BY terms satisfied */
double nRow; /* Estimated number of rows (for EQP) */
union {
Index *pIdx; /* Index when WHERE_INDEXED is true */
@@ -10944,10 +11176,12 @@ struct WhereLevel {
struct InLoop {
int iCur; /* The VDBE cursor used by this IN operator */
int addrInTop; /* Top of the IN loop */
+ u8 eEndLoopOp; /* IN Loop terminator. OP_Next or OP_Prev */
} *aInLoop; /* Information about each nested IN operator */
} in; /* Used when plan.wsFlags&WHERE_IN_ABLE */
Index *pCovidx; /* Possible covering index for WHERE_MULTI_OR */
} u;
+ double rOptCost; /* "Optimal" cost for this level */
/* The following field is really not part of the current level. But
** we need a place to cache virtual table index information for each
@@ -10980,24 +11214,28 @@ struct WhereLevel {
** into the second half to give some continuity.
*/
struct WhereInfo {
- Parse *pParse; /* Parsing and code generating context */
- u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */
- u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE or DELETE */
- u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */
- u8 eDistinct;
- SrcList *pTabList; /* List of tables in the join */
- int iTop; /* The very beginning of the WHERE loop */
- int iContinue; /* Jump here to continue with next record */
- int iBreak; /* Jump here to break out of the loop */
- int nLevel; /* Number of nested loop */
- struct WhereClause *pWC; /* Decomposition of the WHERE clause */
- double savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */
- double nRowOut; /* Estimated number of output rows */
- WhereLevel a[1]; /* Information about each nest loop in WHERE */
+ Parse *pParse; /* Parsing and code generating context */
+ SrcList *pTabList; /* List of tables in the join */
+ u16 nOBSat; /* Number of ORDER BY terms satisfied by indices */
+ u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */
+ u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE/DELETE */
+ u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */
+ u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */
+ int iTop; /* The very beginning of the WHERE loop */
+ int iContinue; /* Jump here to continue with next record */
+ int iBreak; /* Jump here to break out of the loop */
+ int nLevel; /* Number of nested loop */
+ struct WhereClause *pWC; /* Decomposition of the WHERE clause */
+ double savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */
+ double nRowOut; /* Estimated number of output rows */
+ WhereLevel a[1]; /* Information about each nest loop in WHERE */
};
-#define WHERE_DISTINCT_UNIQUE 1
-#define WHERE_DISTINCT_ORDERED 2
+/* Allowed values for WhereInfo.eDistinct and DistinctCtx.eTnctType */
+#define WHERE_DISTINCT_NOOP 0 /* DISTINCT keyword not used */
+#define WHERE_DISTINCT_UNIQUE 1 /* No duplicates */
+#define WHERE_DISTINCT_ORDERED 2 /* All duplicates are adjacent */
+#define WHERE_DISTINCT_UNORDERED 3 /* Duplicates are scattered */
/*
** A NameContext defines a context in which to resolve table and column
@@ -11038,6 +11276,8 @@ struct NameContext {
#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_AsMaybe 0x10 /* Resolve to AS terms of the result set only
+ ** if no other resolution is available */
/*
** An instance of the following structure contains all information
@@ -11056,13 +11296,12 @@ struct NameContext {
** as the OP_OpenEphm instruction is coded because not
** enough information about the compound query is known at that point.
** The KeyInfo for addrOpenTran[0] and [1] contains collating sequences
-** for the result set. The KeyInfo for addrOpenTran[2] contains collating
+** for the result set. The KeyInfo for addrOpenEphm[2] contains collating
** sequences for the ORDER BY clause.
*/
struct Select {
ExprList *pEList; /* The fields of the result */
u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
- char affinity; /* MakeRecord with this affinity for SRT_Set */
u16 selFlags; /* Various SF_* values */
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
int addrOpenEphm[3]; /* OP_OpenEphem opcodes related to this select */
@@ -11083,14 +11322,16 @@ struct Select {
** Allowed values for Select.selFlags. The "SF" prefix stands for
** "Select Flag".
*/
-#define SF_Distinct 0x01 /* Output should be DISTINCT */
-#define SF_Resolved 0x02 /* Identifiers have been resolved */
-#define SF_Aggregate 0x04 /* Contains aggregate functions */
-#define SF_UsesEphemeral 0x08 /* Uses the OpenEphemeral opcode */
-#define SF_Expanded 0x10 /* sqlite3SelectExpand() called on this */
-#define SF_HasTypeInfo 0x20 /* FROM subqueries have Table metadata */
-#define SF_UseSorter 0x40 /* Sort using a sorter */
-#define SF_Values 0x80 /* Synthesized from VALUES clause */
+#define SF_Distinct 0x0001 /* Output should be DISTINCT */
+#define SF_Resolved 0x0002 /* Identifiers have been resolved */
+#define SF_Aggregate 0x0004 /* Contains aggregate functions */
+#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 */
+#define SF_UseSorter 0x0040 /* Sort using a sorter */
+#define SF_Values 0x0080 /* Synthesized from VALUES clause */
+#define SF_Materialize 0x0100 /* Force materialization of views */
+#define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */
/*
@@ -11113,13 +11354,12 @@ struct Select {
#define SRT_Coroutine 10 /* Generate a single row of result */
/*
-** A structure used to customize the behavior of sqlite3Select(). See
-** comments above sqlite3Select() for details.
+** An instance of this object describes where to put of the results of
+** a SELECT statement.
*/
-typedef struct SelectDest SelectDest;
struct SelectDest {
- u8 eDest; /* How to dispose of the results */
- u8 affSdst; /* Affinity used when eDest==SRT_Set */
+ u8 eDest; /* How to dispose of the results. On of SRT_* above. */
+ char affSdst; /* Affinity used when eDest==SRT_Set */
int iSDParm; /* A parameter used by the eDest disposal method */
int iSdst; /* Base register where results are written */
int nSdst; /* Number of registers allocated */
@@ -11320,6 +11560,7 @@ struct AuthContext {
#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_PERMUTE 0x01 /* OP_Compare: use the permutation */
/*
* Each trigger present in the database schema is stored as an instance of
@@ -11419,6 +11660,7 @@ struct TriggerStep {
typedef struct DbFixer DbFixer;
struct DbFixer {
Parse *pParse; /* The parsing context. Error messages written here */
+ Schema *pSchema; /* Fix items to this schema */
const char *zDb; /* Make sure all objects are contained in this database */
const char *zType; /* Type of the container - used for error messages */
const Token *pName; /* Name of the container - used for error messages */
@@ -11461,6 +11703,7 @@ struct Sqlite3Config {
int bCoreMutex; /* True to enable core mutexing */
int bFullMutex; /* True to enable full mutexing */
int bOpenUri; /* True to interpret filenames as URIs */
+ int bUseCis; /* Use covering indices for full-scans */
int mxStrlen; /* Maximum string length */
int szLookaside; /* Default lookaside buffer size */
int nLookaside; /* Default lookaside buffer count */
@@ -11470,6 +11713,8 @@ struct Sqlite3Config {
void *pHeap; /* Heap storage space */
int nHeap; /* Size of pHeap[] */
int mnReq, mxReq; /* Min and max heap requests sizes */
+ sqlite3_int64 szMmap; /* mmap() space per open file */
+ sqlite3_int64 mxMmap; /* Maximum value for szMmap */
void *pScratch; /* Scratch memory */
int szScratch; /* Size of each scratch buffer */
int nScratch; /* Number of scratch buffers */
@@ -11490,6 +11735,10 @@ struct Sqlite3Config {
void (*xLog)(void*,int,const char*); /* Function for logging */
void *pLogArg; /* First argument to xLog() */
int bLocaltimeFault; /* True to fail localtime() calls */
+#ifdef SQLITE_ENABLE_SQLLOG
+ void(*xSqllog)(void*,sqlite3*,const char*, int);
+ void *pSqllogArg;
+#endif
};
/*
@@ -11500,6 +11749,7 @@ struct Walker {
int (*xSelectCallback)(Walker*,Select*); /* Callback for SELECTs */
Parse *pParse; /* Parser context. */
int walkerDepth; /* Number of subqueries */
+ u8 bSelectDepthFirst; /* Do subqueries first */
union { /* Extra data for callback */
NameContext *pNC; /* Naming context */
int i; /* Integer value */
@@ -11777,6 +12027,7 @@ SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse);
# define sqlite3AutoincrementBegin(X)
# define sqlite3AutoincrementEnd(X)
#endif
+SQLITE_PRIVATE int sqlite3CodeCoroutine(Parse*, Select*, SelectDest*);
SQLITE_PRIVATE void sqlite3Insert(Parse*, SrcList*, ExprList*, Select*, IdList*, int);
SQLITE_PRIVATE void *sqlite3ArrayAllocate(sqlite3*,void*,int,int*,int*);
SQLITE_PRIVATE IdList *sqlite3IdListAppend(sqlite3*, IdList*, Token*);
@@ -11796,23 +12047,21 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*
SQLITE_PRIVATE void sqlite3DropIndex(Parse*, SrcList*, int);
SQLITE_PRIVATE int sqlite3Select(Parse*, Select*, SelectDest*);
SQLITE_PRIVATE Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*,
- Expr*,ExprList*,int,Expr*,Expr*);
+ Expr*,ExprList*,u16,Expr*,Expr*);
SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3*, Select*);
SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse*, SrcList*);
SQLITE_PRIVATE int sqlite3IsReadOnly(Parse*, Table*, int);
SQLITE_PRIVATE void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
-SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse *, SrcList *, Expr *, ExprList *, Expr *, Expr *, char *);
+SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,Expr*,char*);
#endif
SQLITE_PRIVATE void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
SQLITE_PRIVATE void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
-SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
- Parse*,SrcList*,Expr*,ExprList**,ExprList*,u16,int);
+SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int);
SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo*);
SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8);
SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int);
SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse*, int, int, int);
-SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse*, int, int, int);
SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse*, int, int, int);
SQLITE_PRIVATE void sqlite3ExprCachePush(Parse*);
SQLITE_PRIVATE void sqlite3ExprCachePop(Parse*, int);
@@ -11829,6 +12078,7 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse*, Expr*, int, int);
SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3*,const char*, const char*);
SQLITE_PRIVATE Table *sqlite3LocateTable(Parse*,int isView,const char*, const char*);
+SQLITE_PRIVATE Table *sqlite3LocateTableItem(Parse*,int isView,struct SrcList_item *);
SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3*,const char*, const char*);
SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*);
SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*);
@@ -11871,7 +12121,7 @@ SQLITE_PRIVATE int sqlite3OpenTableAndIndices(Parse*, Table*, int, int);
SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse*, int, int);
SQLITE_PRIVATE void sqlite3MultiWrite(Parse*);
SQLITE_PRIVATE void sqlite3MayAbort(Parse*);
-SQLITE_PRIVATE void sqlite3HaltConstraint(Parse*, int, char*, int);
+SQLITE_PRIVATE void sqlite3HaltConstraint(Parse*, int, int, char*, int);
SQLITE_PRIVATE Expr *sqlite3ExprDup(sqlite3*,Expr*,int);
SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int);
SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int);
@@ -11952,7 +12202,7 @@ SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*);
SQLITE_PRIVATE int sqlite3Atoi(const char*);
SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar);
SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte);
-SQLITE_PRIVATE u32 sqlite3Utf8Read(const u8*, const u8**);
+SQLITE_PRIVATE u32 sqlite3Utf8Read(const u8**);
/*
** Routines to read and write variable-length integers. These used to
@@ -11984,8 +12234,11 @@ SQLITE_PRIVATE int sqlite3VarintLen(u64 v);
** x = putVarint32( A, B );
**
*/
-#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)))
+#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)))
#define getVarint sqlite3GetVarint
#define putVarint sqlite3PutVarint
@@ -12000,13 +12253,20 @@ SQLITE_PRIVATE void sqlite3Error(sqlite3*, int, const char*,...);
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_DEBUG) || defined(SQLITE_TEST) || \
+ defined(SQLITE_DEBUG_OS_TRACE)
+SQLITE_PRIVATE const char *sqlite3ErrName(int);
+#endif
+
SQLITE_PRIVATE const char *sqlite3ErrStr(int);
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 *sqlite3ExprSetColl(Expr*, CollSeq*);
-SQLITE_PRIVATE Expr *sqlite3ExprSetCollByToken(Parse *pParse, Expr*, Token*);
+SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, Token*);
+SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*);
+SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr*);
SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *, CollSeq *);
SQLITE_PRIVATE int sqlite3CheckObjectName(Parse *, const char *);
SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *, int);
@@ -12053,13 +12313,14 @@ SQLITE_PRIVATE void sqlite3NestedParse(Parse*, const char*, ...);
SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*);
SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *, Expr *, int, int);
SQLITE_PRIVATE void sqlite3SelectPrep(Parse*, Select*, NameContext*);
+SQLITE_PRIVATE int sqlite3MatchSpanName(const char*, const char*, const char*, const char*);
SQLITE_PRIVATE int sqlite3ResolveExprNames(NameContext*, Expr*);
SQLITE_PRIVATE void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*);
SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*);
SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *, Table *, int, int);
SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *, Token *);
SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *, SrcList *);
-SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(sqlite3*, u8, CollSeq *, const char*);
+SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*);
SQLITE_PRIVATE char sqlite3AffinityType(const char*);
SQLITE_PRIVATE void sqlite3Analyze(Parse*, Token*, Token*);
SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler*);
@@ -12163,8 +12424,10 @@ SQLITE_PRIVATE void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*);
SQLITE_PRIVATE CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *);
SQLITE_PRIVATE int sqlite3TempInMemory(const sqlite3*);
SQLITE_PRIVATE const char *sqlite3JournalModename(int);
-SQLITE_PRIVATE int sqlite3Checkpoint(sqlite3*, int, int, int*, int*);
-SQLITE_PRIVATE int sqlite3WalDefaultHook(void*,sqlite3*,const char*,int);
+#ifndef SQLITE_OMIT_WAL
+SQLITE_PRIVATE int sqlite3Checkpoint(sqlite3*, int, int, int*, int*);
+SQLITE_PRIVATE int sqlite3WalDefaultHook(void*,sqlite3*,const char*,int);
+#endif
/* Declarations for functions in fkey.c. All of these are replaced by
** no-op macros if OMIT_FOREIGN_KEY is defined. In this case no foreign
@@ -12189,8 +12452,10 @@ SQLITE_PRIVATE FKey *sqlite3FkReferences(Table *);
#endif
#ifndef SQLITE_OMIT_FOREIGN_KEY
SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *, Table*);
+SQLITE_PRIVATE int sqlite3FkLocateIndex(Parse*,Table*,FKey*,Index**,int**);
#else
#define sqlite3FkDelete(a,b)
+ #define sqlite3FkLocateIndex(a,b,c,d,e)
#endif
@@ -12215,15 +12480,18 @@ SQLITE_PRIVATE void sqlite3EndBenignMalloc(void);
#define IN_INDEX_ROWID 1
#define IN_INDEX_EPH 2
-#define IN_INDEX_INDEX 3
+#define IN_INDEX_INDEX_ASC 3
+#define IN_INDEX_INDEX_DESC 4
SQLITE_PRIVATE int sqlite3FindInIndex(Parse *, Expr *, int*);
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
SQLITE_PRIVATE int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);
SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *);
SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *);
+SQLITE_PRIVATE int sqlite3JournalExists(sqlite3_file *p);
#else
#define sqlite3JournalSize(pVfs) ((pVfs)->szOsFile)
+ #define sqlite3JournalExists(p) 1
#endif
SQLITE_PRIVATE void sqlite3MemJournalOpen(sqlite3_file *);
@@ -12452,6 +12720,10 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
# define SQLITE_USE_URI 0
#endif
+#ifndef SQLITE_ALLOW_COVERING_INDEX_SCAN
+# define SQLITE_ALLOW_COVERING_INDEX_SCAN 1
+#endif
+
/*
** The following singleton contains the global configuration for
** the SQLite library.
@@ -12461,6 +12733,7 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
1, /* bCoreMutex */
SQLITE_THREADSAFE==1, /* bFullMutex */
SQLITE_USE_URI, /* bOpenUri */
+ SQLITE_ALLOW_COVERING_INDEX_SCAN, /* bUseCis */
0x7ffffffe, /* mxStrlen */
128, /* szLookaside */
500, /* nLookaside */
@@ -12470,6 +12743,8 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
(void*)0, /* pHeap */
0, /* nHeap */
0, 0, /* mnHeap, mxHeap */
+ SQLITE_DEFAULT_MMAP_SIZE, /* szMmap */
+ SQLITE_MAX_MMAP_SIZE, /* mxMmap */
(void*)0, /* pScratch */
0, /* szScratch */
0, /* nScratch */
@@ -12489,6 +12764,10 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
0, /* xLog */
0, /* pLogArg */
0, /* bLocaltimeFault */
+#ifdef SQLITE_ENABLE_SQLLOG
+ 0, /* xSqllog */
+ 0 /* pSqllogArg */
+#endif
};
@@ -12589,15 +12868,15 @@ static const char * const azCompileOpt[] = {
#ifdef SQLITE_COVERAGE_TEST
"COVERAGE_TEST",
#endif
-#ifdef SQLITE_CURDIR
- "CURDIR",
-#endif
#ifdef SQLITE_DEBUG
"DEBUG",
#endif
#ifdef 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
"DISABLE_DIRSYNC",
#endif
@@ -12688,6 +12967,9 @@ static const char * const azCompileOpt[] = {
#ifdef 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
@@ -12745,11 +13027,6 @@ static const char * const azCompileOpt[] = {
#ifdef SQLITE_OMIT_CHECK
"OMIT_CHECK",
#endif
-/* // redundant
-** #ifdef SQLITE_OMIT_COMPILEOPTION_DIAGS
-** "OMIT_COMPILEOPTION_DIAGS",
-** #endif
-*/
#ifdef SQLITE_OMIT_COMPLETE
"OMIT_COMPLETE",
#endif
@@ -12804,9 +13081,6 @@ static const char * const azCompileOpt[] = {
#ifdef SQLITE_OMIT_MEMORYDB
"OMIT_MEMORYDB",
#endif
-#ifdef SQLITE_OMIT_MERGE_SORT
- "OMIT_MERGE_SORT",
-#endif
#ifdef SQLITE_OMIT_OR_OPTIMIZATION
"OMIT_OR_OPTIMIZATION",
#endif
@@ -12879,6 +13153,9 @@ static const char * const azCompileOpt[] = {
#ifdef SQLITE_PROXY_DEBUG
"PROXY_DEBUG",
#endif
+#ifdef SQLITE_RTREE_INT_ONLY
+ "RTREE_INT_ONLY",
+#endif
#ifdef SQLITE_SECURE_DELETE
"SECURE_DELETE",
#endif
@@ -12891,13 +13168,13 @@ static const char * const azCompileOpt[] = {
#ifdef SQLITE_TCL
"TCL",
#endif
-#ifdef SQLITE_TEMP_STORE
+#if defined(SQLITE_TEMP_STORE) && !defined(SQLITE_TEMP_STORE_xc)
"TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE),
#endif
#ifdef SQLITE_TEST
"TEST",
#endif
-#ifdef SQLITE_THREADSAFE
+#if defined(SQLITE_THREADSAFE)
"THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE),
#endif
#ifdef SQLITE_USE_ALLOCA
@@ -12923,8 +13200,11 @@ SQLITE_API int sqlite3_compileoption_used(const char *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)
- && ( (azCompileOpt[i][n]==0) || (azCompileOpt[i][n]=='=') ) ) return 1;
+ if( sqlite3StrNICmp(zOptName, azCompileOpt[i], n)==0
+ && sqlite3CtypeMap[(unsigned char)azCompileOpt[i][n]]==0
+ ){
+ return 1;
+ }
}
return 0;
}
@@ -12982,6 +13262,14 @@ SQLITE_API const char *sqlite3_compileoption_get(int N){
#define _VDBEINT_H_
/*
+** 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.
@@ -13026,6 +13314,7 @@ struct VdbeCursor {
Bool isIndex; /* True if an index containing keys only - no data */
Bool isOrdered; /* True if the underlying table is BTREE_UNORDERED */
Bool isSorter; /* True if a new-style sorter */
+ Bool multiPseudo; /* Multi-register pseudo-cursor */
sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */
const sqlite3_module *pModule; /* Module for cursor pVtabCursor */
i64 seqCount; /* Sequence counter */
@@ -13085,7 +13374,7 @@ struct VdbeFrame {
VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */
void *token; /* Copy of SubProgram.token */
i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
- u16 nCursor; /* Number of entries in apCsr */
+ 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 */
@@ -13150,7 +13439,9 @@ struct Mem {
#define MEM_RowSet 0x0020 /* Value is a RowSet object */
#define MEM_Frame 0x0040 /* Value is a VdbeFrame object */
#define MEM_Invalid 0x0080 /* Value is undefined */
-#define MEM_TypeMask 0x00ff /* Mask of type bits */
+#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
@@ -13236,6 +13527,11 @@ struct Explain {
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 */
+
/*
** An instance of the virtual machine. This structure contains the complete
** state of the virtual machine.
@@ -13264,7 +13560,7 @@ struct Vdbe {
int nLabel; /* Number of labels used */
int *aLabel; /* Space to hold the labels */
u16 nResColumn; /* Number of columns in one row of the result set */
- u16 nCursor; /* Number of slots in apCsr[] */
+ 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 */
@@ -13277,15 +13573,16 @@ struct Vdbe {
int pc; /* The program counter */
int rc; /* Value to return */
u8 errorAction; /* Recovery action to do in case of an error */
- u8 explain; /* True if EXPLAIN present on SQL command */
- u8 changeCntOn; /* True to update the change-counter */
- u8 expired; /* True if the VM needs to be recompiled */
- u8 runOnlyOnce; /* Automatically expire on reset */
u8 minWriteFileFormat; /* Minimum file format for writable database files */
- u8 inVtabMethod; /* See comments above */
- u8 usesStmtJournal; /* True if uses a statement journal */
- u8 readOnly; /* True for read-only statements */
- u8 isPrepareV2; /* True if prepared with prepare_v2() */
+ 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 */
+ bft usesStmtJournal:1; /* True if uses a statement journal */
+ bft readOnly:1; /* True for read-only statements */
+ 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 */
@@ -13383,15 +13680,6 @@ SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *);
SQLITE_PRIVATE void sqlite3VdbeMemStoreType(Mem *pMem);
SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p);
-#ifdef SQLITE_OMIT_MERGE_SORT
-# define sqlite3VdbeSorterInit(Y,Z) SQLITE_OK
-# define sqlite3VdbeSorterWrite(X,Y,Z) SQLITE_OK
-# define sqlite3VdbeSorterClose(Y,Z)
-# define sqlite3VdbeSorterRowkey(Y,Z) SQLITE_OK
-# define sqlite3VdbeSorterRewind(X,Y,Z) SQLITE_OK
-# define sqlite3VdbeSorterNext(X,Y,Z) SQLITE_OK
-# define sqlite3VdbeSorterCompare(X,Y,Z) SQLITE_OK
-#else
SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *, VdbeCursor *);
SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *);
SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *);
@@ -13399,7 +13687,6 @@ 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 sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int *);
-#endif
#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0
SQLITE_PRIVATE void sqlite3VdbeEnter(Vdbe*);
@@ -13631,7 +13918,8 @@ SQLITE_API int sqlite3_db_status(
db->pnBytesFreed = &nByte;
for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){
- sqlite3VdbeDeleteObject(db, pVdbe);
+ sqlite3VdbeClearObject(db, pVdbe);
+ sqlite3DbFree(db, pVdbe);
}
db->pnBytesFreed = 0;
@@ -14947,6 +15235,26 @@ SQLITE_PRIVATE int sqlite3OsShmMap(
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);
+}
+#else
+/* No-op stubs to use when memory-mapped I/O is disabled */
+SQLITE_PRIVATE int sqlite3OsFetch(sqlite3_file *id, i64 iOff, int iAmt, void **pp){
+ *pp = 0;
+ return SQLITE_OK;
+}
+SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *id, i64 iOff, void *p){
+ return SQLITE_OK;
+}
+#endif
+
/*
** The next group of routines are convenience wrappers around the
** VFS methods.
@@ -20527,25 +20835,23 @@ static const unsigned char sqlite3Utf8Trans1[] = {
|| (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \
}
SQLITE_PRIVATE u32 sqlite3Utf8Read(
- const unsigned char *zIn, /* First byte of UTF-8 character */
- const unsigned char **pzNext /* Write first byte past UTF-8 char here */
+ const unsigned char **pz /* Pointer to string from which to read char */
){
unsigned int c;
/* Same as READ_UTF8() above but without the zTerm parameter.
** For this routine, we assume the UTF8 string is always zero-terminated.
*/
- c = *(zIn++);
+ c = *((*pz)++);
if( c>=0xc0 ){
c = sqlite3Utf8Trans1[c-0xc0];
- while( (*zIn & 0xc0)==0x80 ){
- c = (c<<6) + (0x3f & *(zIn++));
+ while( (*(*pz) & 0xc0)==0x80 ){
+ c = (c<<6) + (0x3f & *((*pz)++));
}
if( c<0x80
|| (c&0xFFFFF800)==0xD800
|| (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; }
}
- *pzNext = zIn;
return c;
}
@@ -20646,7 +20952,6 @@ SQLITE_PRIVATE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
if( desiredEnc==SQLITE_UTF16LE ){
/* UTF-8 -> UTF-16 Little-endian */
while( zIn<zTerm ){
- /* c = sqlite3Utf8Read(zIn, zTerm, (const u8**)&zIn); */
READ_UTF8(zIn, zTerm, c);
WRITE_UTF16LE(z, c);
}
@@ -20654,7 +20959,6 @@ SQLITE_PRIVATE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
assert( desiredEnc==SQLITE_UTF16BE );
/* UTF-8 -> UTF-16 Big-endian */
while( zIn<zTerm ){
- /* c = sqlite3Utf8Read(zIn, zTerm, (const u8**)&zIn); */
READ_UTF8(zIn, zTerm, c);
WRITE_UTF16BE(z, c);
}
@@ -20782,7 +21086,7 @@ SQLITE_PRIVATE int sqlite3Utf8To8(unsigned char *zIn){
u32 c;
while( zIn[0] && zOut<=zIn ){
- c = sqlite3Utf8Read(zIn, (const u8**)&zIn);
+ c = sqlite3Utf8Read((const u8**)&zIn);
if( c!=0xfffd ){
WRITE_UTF8(zOut, c);
}
@@ -20887,7 +21191,7 @@ SQLITE_PRIVATE void sqlite3UtfSelfTest(void){
assert( n>0 && n<=4 );
z[0] = 0;
z = zBuf;
- c = sqlite3Utf8Read(z, (const u8**)&z);
+ c = sqlite3Utf8Read((const u8**)&z);
t = i;
if( i>=0xD800 && i<=0xDFFF ) t = 0xFFFD;
if( (i&0xFFFFFFFE)==0xFFFE ) t = 0xFFFD;
@@ -21186,7 +21490,7 @@ SQLITE_API int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){
*/
SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){
#ifndef SQLITE_OMIT_FLOATING_POINT
- int incr = (enc==SQLITE_UTF8?1:2);
+ int incr;
const char *zEnd = z + length;
/* sign * significand * (10 ^ (esign * exponent)) */
int sign = 1; /* sign of significand */
@@ -21197,10 +21501,22 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
int eValid = 1; /* True exponent is either not used or is well-formed */
double result;
int nDigits = 0;
+ int nonNum = 0;
+ assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
*pResult = 0.0; /* Default return value, in case of an error */
- if( enc==SQLITE_UTF16BE ) z++;
+ if( enc==SQLITE_UTF8 ){
+ incr = 1;
+ }else{
+ int i;
+ incr = 2;
+ assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
+ for(i=3-enc; i<length && z[i]==0; i+=2){}
+ nonNum = i<length;
+ zEnd = z+i+enc-3;
+ z += (enc&1);
+ }
/* skip leading spaces */
while( z<zEnd && sqlite3Isspace(*z) ) z+=incr;
@@ -21333,7 +21649,7 @@ do_atof_calc:
*pResult = result;
/* return true if number and no extra non-whitespace chracters after */
- return z>=zEnd && nDigits>0 && eValid;
+ return z>=zEnd && nDigits>0 && eValid && nonNum==0;
#else
return !sqlite3Atoi64(z, pResult, length, enc);
#endif /* SQLITE_OMIT_FLOATING_POINT */
@@ -21382,21 +21698,33 @@ static int compare2pow63(const char *zNum, int incr){
** signed 64-bit integer, its negative -9223372036854665808 can be.
**
** If zNum is too big for a 64-bit integer and is not
-** 9223372036854665808 then return 1.
+** 9223372036854665808 or if zNum contains any non-numeric text,
+** then return 1.
**
** length is the number of bytes in the string (bytes, not characters).
** The string is not necessarily zero-terminated. The encoding is
** given by enc.
*/
SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
- int incr = (enc==SQLITE_UTF8?1:2);
+ int incr;
u64 u = 0;
int neg = 0; /* assume positive */
int i;
int c = 0;
+ int nonNum = 0;
const char *zStart;
const char *zEnd = zNum + length;
- if( enc==SQLITE_UTF16BE ) zNum++;
+ assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
+ if( enc==SQLITE_UTF8 ){
+ incr = 1;
+ }else{
+ incr = 2;
+ assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
+ for(i=3-enc; i<length && zNum[i]==0; i+=2){}
+ nonNum = i<length;
+ zEnd = zNum+i+enc-3;
+ zNum += (enc&1);
+ }
while( zNum<zEnd && sqlite3Isspace(*zNum) ) zNum+=incr;
if( zNum<zEnd ){
if( *zNum=='-' ){
@@ -21421,7 +21749,7 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc
testcase( i==18 );
testcase( i==19 );
testcase( i==20 );
- if( (c!=0 && &zNum[i]<zEnd) || (i==0 && zStart==zNum) || i>19*incr ){
+ if( (c!=0 && &zNum[i]<zEnd) || (i==0 && zStart==zNum) || i>19*incr || nonNum ){
/* zNum is empty or contains non-numeric text or is longer
** than 19 digits (thus guaranteeing that it is too large) */
return 1;
@@ -22305,7 +22633,7 @@ static void removeElementGivenHash(
}
sqlite3_free( elem );
pH->count--;
- if( pH->count<=0 ){
+ if( pH->count==0 ){
assert( pH->first==0 );
assert( pH->count==0 );
sqlite3HashClear(pH);
@@ -22603,6 +22931,13 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
*/
#if SQLITE_OS_UNIX /* This file is used on unix only */
+/* Use posix_fallocate() if it is available
+*/
+#if !defined(HAVE_POSIX_FALLOCATE) \
+ && (_XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L)
+# define HAVE_POSIX_FALLOCATE 1
+#endif
+
/*
** There are various methods for file locking used for concurrency
** control:
@@ -22676,7 +23011,7 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
/* #include <time.h> */
#include <sys/time.h>
#include <errno.h>
-#ifndef SQLITE_OMIT_WAL
+#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
#include <sys/mman.h>
#endif
@@ -22775,6 +23110,15 @@ struct unixFile {
const char *zPath; /* Name of the file */
unixShm *pShm; /* Shared memory segment information */
int szChunk; /* Configured by FCNTL_CHUNK_SIZE */
+ int nFetchOut; /* Number of outstanding xFetch refs */
+ sqlite3_int64 mmapSize; /* Usable size of mapping at pMapRegion */
+ sqlite3_int64 mmapSizeActual; /* Actual size of mapping at pMapRegion */
+ sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */
+ void *pMapRegion; /* Memory mapped region */
+#ifdef __QNXNTO__
+ int sectorSize; /* Device sector size */
+ int deviceCharacteristics; /* Precomputed device characteristics */
+#endif
#if SQLITE_ENABLE_LOCKING_STYLE
int openFlags; /* The flags specified at open() */
#endif
@@ -22795,7 +23139,9 @@ struct unixFile {
unsigned char transCntrChng; /* True if the transaction counter changed */
unsigned char dbUpdate; /* True if any part of database file changed */
unsigned char inNormalWrite; /* True if in a normal write operation */
+
#endif
+
#ifdef SQLITE_TEST
/* In test mode, increase the size of this structure a bit so that
** it is larger than the struct CrashFile defined in test6.c.
@@ -22819,6 +23165,7 @@ struct unixFile {
#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 */
/*
** Include code that is common to all os_*.c files
@@ -23061,6 +23408,17 @@ SQLITE_API int sqlite3_open_file_count = 0;
#endif
/*
+** HAVE_MREMAP defaults to true on Linux and false everywhere else.
+*/
+#if !defined(HAVE_MREMAP)
+# if defined(__linux__) && defined(_GNU_SOURCE)
+# define HAVE_MREMAP 1
+# else
+# define HAVE_MREMAP 0
+# endif
+#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.
@@ -23091,7 +23449,7 @@ static int openDirectory(const char*, int*);
** to all overrideable system calls.
*/
static struct unix_syscall {
- const char *zName; /* Name of the sytem call */
+ const char *zName; /* Name of the system call */
sqlite3_syscall_ptr pCurrent; /* Current value of the system call */
sqlite3_syscall_ptr pDefault; /* Default value */
} aSyscall[] = {
@@ -23166,11 +23524,7 @@ static struct unix_syscall {
#define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\
aSyscall[13].pCurrent)
-#if SQLITE_ENABLE_LOCKING_STYLE
{ "fchmod", (sqlite3_syscall_ptr)fchmod, 0 },
-#else
- { "fchmod", (sqlite3_syscall_ptr)0, 0 },
-#endif
#define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent)
#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
@@ -23195,8 +23549,18 @@ static struct unix_syscall {
{ "fchown", (sqlite3_syscall_ptr)posixFchown, 0 },
#define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent)
- { "umask", (sqlite3_syscall_ptr)umask, 0 },
-#define osUmask ((mode_t(*)(mode_t))aSyscall[21].pCurrent)
+ { "mmap", (sqlite3_syscall_ptr)mmap, 0 },
+#define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[21].pCurrent)
+
+ { "munmap", (sqlite3_syscall_ptr)munmap, 0 },
+#define osMunmap ((void*(*)(void*,size_t))aSyscall[22].pCurrent)
+
+#if HAVE_MREMAP
+ { "mremap", (sqlite3_syscall_ptr)mremap, 0 },
+#else
+ { "mremap", (sqlite3_syscall_ptr)0, 0 },
+#endif
+#define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[23].pCurrent)
}; /* End of the overrideable system calls */
@@ -23302,14 +23666,7 @@ static const char *unixNextSystemCall(sqlite3_vfs *p, const char *zName){
*/
static int robust_open(const char *z, int f, mode_t m){
int fd;
- mode_t m2;
- mode_t origM = 0;
- if( m==0 ){
- m2 = SQLITE_DEFAULT_FILE_PERMISSIONS;
- }else{
- m2 = m;
- origM = osUmask(0);
- }
+ mode_t m2 = m ? m : SQLITE_DEFAULT_FILE_PERMISSIONS;
do{
#if defined(O_CLOEXEC)
fd = osOpen(z,f|O_CLOEXEC,m2);
@@ -23317,12 +23674,20 @@ static int robust_open(const char *z, int f, mode_t m){
fd = osOpen(z,f,m2);
#endif
}while( fd<0 && errno==EINTR );
- if( m ){
- osUmask(origM);
- }
+ if( fd>=0 ){
+ if( m!=0 ){
+ struct stat statbuf;
+ if( osFstat(fd, &statbuf)==0
+ && statbuf.st_size==0
+ && (statbuf.st_mode&0777)!=m
+ ){
+ osFchmod(fd, m);
+ }
+ }
#if defined(FD_CLOEXEC) && (!defined(O_CLOEXEC) || O_CLOEXEC==0)
- if( fd>=0 ) osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
+ osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
#endif
+ }
return fd;
}
@@ -23528,7 +23893,6 @@ static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) {
}
-
/******************************************************************************
****************** Begin Unique File ID Utility Used By VxWorks ***************
**
@@ -23864,7 +24228,6 @@ static int unixLogErrorAtLine(
zErr = strerror(iErrno);
#endif
- assert( errcode!=SQLITE_OK );
if( zPath==0 ) zPath = "";
sqlite3_log(errcode,
"os_unix.c:%d: (%d) %s(%s) - %s",
@@ -24031,6 +24394,50 @@ static int findInodeInfo(
/*
+** Check a unixFile that is a database. Verify the following:
+**
+** (1) There is exactly one hard link on the file
+** (2) The file is not a symbolic link
+** (3) The file has not been renamed or unlinked
+**
+** Issue sqlite3_log(SQLITE_WARNING,...) messages if anything is not right.
+*/
+static void verifyDbFile(unixFile *pFile){
+ struct stat buf;
+ int rc;
+ if( pFile->ctrlFlags & UNIXFILE_WARNED ){
+ /* One or more of the following warnings have already been issued. Do not
+ ** repeat them so as not to clutter the error log */
+ return;
+ }
+ rc = osFstat(pFile->h, &buf);
+ if( rc!=0 ){
+ sqlite3_log(SQLITE_WARNING, "cannot fstat db file %s", pFile->zPath);
+ pFile->ctrlFlags |= UNIXFILE_WARNED;
+ return;
+ }
+ if( buf.st_nlink==0 && (pFile->ctrlFlags & UNIXFILE_DELETE)==0 ){
+ sqlite3_log(SQLITE_WARNING, "file unlinked while open: %s", pFile->zPath);
+ pFile->ctrlFlags |= UNIXFILE_WARNED;
+ return;
+ }
+ if( buf.st_nlink>1 ){
+ sqlite3_log(SQLITE_WARNING, "multiple links to file: %s", pFile->zPath);
+ pFile->ctrlFlags |= UNIXFILE_WARNED;
+ return;
+ }
+ if( pFile->pInode!=0
+ && ((rc = osStat(pFile->zPath, &buf))!=0
+ || buf.st_ino!=pFile->pInode->fileId.ino)
+ ){
+ sqlite3_log(SQLITE_WARNING, "file renamed while open: %s", pFile->zPath);
+ pFile->ctrlFlags |= UNIXFILE_WARNED;
+ return;
+ }
+}
+
+
+/*
** 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, set *pResOut
** to a non-zero value otherwise *pResOut is set to zero. The return value
@@ -24560,9 +24967,13 @@ end_unlock:
** the requested locking level, this routine is a no-op.
*/
static int unixUnlock(sqlite3_file *id, int eFileLock){
+ assert( eFileLock==SHARED_LOCK || ((unixFile *)id)->nFetchOut==0 );
return posixUnlock(id, eFileLock, 0);
}
+static int unixMapfile(unixFile *pFd, i64 nByte);
+static void unixUnmapfile(unixFile *pFd);
+
/*
** This function performs the parts of the "close file" operation
** common to all locking schemes. It closes the directory and file
@@ -24575,6 +24986,7 @@ static int unixUnlock(sqlite3_file *id, int eFileLock){
*/
static int closeUnixFile(sqlite3_file *id){
unixFile *pFile = (unixFile*)id;
+ unixUnmapfile(pFile);
if( pFile->h>=0 ){
robust_close(pFile, pFile->h, __LINE__);
pFile->h = -1;
@@ -24601,6 +25013,7 @@ static int closeUnixFile(sqlite3_file *id){
static int unixClose(sqlite3_file *id){
int rc = SQLITE_OK;
unixFile *pFile = (unixFile *)id;
+ verifyDbFile(pFile);
unixUnlock(id, NO_LOCK);
unixEnterMutex();
@@ -24669,7 +25082,7 @@ static int nolockClose(sqlite3_file *id) {
/******************************************************************************
************************* Begin dot-file Locking ******************************
**
-** The dotfile locking implementation uses the existance of separate lock
+** The dotfile locking implementation uses the existence of separate lock
** files (really a directory) to control access to the database. This works
** on just about every filesystem imaginable. But there are serious downsides:
**
@@ -24684,7 +25097,7 @@ static int nolockClose(sqlite3_file *id) {
**
** Dotfile locking works by creating a subdirectory in the same directory as
** the database and with the same name but with a ".lock" extension added.
-** The existance of a lock directory implies an EXCLUSIVE lock. All other
+** The existence of a lock directory implies an EXCLUSIVE lock. All other
** lock types (SHARED, RESERVED, PENDING) are mapped into EXCLUSIVE.
*/
@@ -24851,13 +25264,13 @@ static int dotlockUnlock(sqlite3_file *id, int eFileLock) {
** Close a file. Make sure the lock has been released before closing.
*/
static int dotlockClose(sqlite3_file *id) {
- int rc;
+ int rc = SQLITE_OK;
if( id ){
unixFile *pFile = (unixFile*)id;
dotlockUnlock(id, NO_LOCK);
sqlite3_free(pFile->lockingContext);
+ rc = closeUnixFile(id);
}
- rc = closeUnixFile(id);
return rc;
}
/****************** End of the dot-file lock implementation *******************
@@ -25061,10 +25474,12 @@ static int flockUnlock(sqlite3_file *id, int eFileLock) {
** Close a file.
*/
static int flockClose(sqlite3_file *id) {
+ int rc = SQLITE_OK;
if( id ){
flockUnlock(id, NO_LOCK);
+ rc = closeUnixFile(id);
}
- return closeUnixFile(id);
+ return rc;
}
#endif /* SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORK */
@@ -25775,6 +26190,8 @@ static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){
i64 newOffset;
#endif
TIMER_START;
+ assert( cnt==(cnt&0x1ffff) );
+ cnt &= 0x1ffff;
do{
#if defined(USE_PREAD)
got = osPread(id->h, pBuf, cnt, offset);
@@ -25828,6 +26245,8 @@ static int unixRead(
unixFile *pFile = (unixFile *)id;
int got;
assert( id );
+ assert( offset>=0 );
+ assert( amt>0 );
/* If this is a database file (not a journal, master-journal or temp
** file), the bytes in the locking range should never be read or written. */
@@ -25838,6 +26257,23 @@ static int unixRead(
);
#endif
+#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);
+ return SQLITE_OK;
+ }else{
+ int nCopy = pFile->mmapSize - offset;
+ memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], nCopy);
+ pBuf = &((u8 *)pBuf)[nCopy];
+ amt -= nCopy;
+ offset += nCopy;
+ }
+ }
+#endif
+
got = seekAndRead(pFile, offset, pBuf, amt);
if( got==amt ){
return SQLITE_OK;
@@ -25853,44 +26289,59 @@ static int unixRead(
}
/*
-** Seek to the offset in id->offset then read cnt bytes into pBuf.
-** Return the number of bytes actually read. Update the offset.
-**
-** To avoid stomping the errno value on a failed write the lastErrno value
-** is set before returning.
+** Attempt to seek the file-descriptor passed as the first argument to
+** absolute offset iOff, then attempt to write nBuf bytes of data from
+** pBuf to it. If an error occurs, return -1 and set *piErrno. Otherwise,
+** return the actual number of bytes written (which may be less than
+** nBuf).
*/
-static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){
- int got;
-#if (!defined(USE_PREAD) && !defined(USE_PREAD64))
- i64 newOffset;
-#endif
+static int seekAndWriteFd(
+ int fd, /* File descriptor to write to */
+ i64 iOff, /* File offset to begin writing at */
+ const void *pBuf, /* Copy data from this buffer to the file */
+ int nBuf, /* Size of buffer pBuf in bytes */
+ int *piErrno /* OUT: Error number if error occurs */
+){
+ int rc = 0; /* Value returned by system call */
+
+ assert( nBuf==(nBuf&0x1ffff) );
+ nBuf &= 0x1ffff;
TIMER_START;
+
#if defined(USE_PREAD)
- do{ got = osPwrite(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR );
+ do{ rc = osPwrite(fd, pBuf, nBuf, iOff); }while( rc<0 && errno==EINTR );
#elif defined(USE_PREAD64)
- do{ got = osPwrite64(id->h, pBuf, cnt, offset);}while( got<0 && errno==EINTR);
+ do{ rc = osPwrite64(fd, pBuf, nBuf, iOff);}while( rc<0 && errno==EINTR);
#else
do{
- newOffset = lseek(id->h, offset, SEEK_SET);
- SimulateIOError( newOffset-- );
- if( newOffset!=offset ){
- if( newOffset == -1 ){
- ((unixFile*)id)->lastErrno = errno;
- }else{
- ((unixFile*)id)->lastErrno = 0;
- }
+ i64 iSeek = lseek(fd, iOff, SEEK_SET);
+ SimulateIOError( iSeek-- );
+
+ if( iSeek!=iOff ){
+ if( piErrno ) *piErrno = (iSeek==-1 ? errno : 0);
return -1;
}
- got = osWrite(id->h, pBuf, cnt);
- }while( got<0 && errno==EINTR );
+ rc = osWrite(fd, pBuf, nBuf);
+ }while( rc<0 && errno==EINTR );
#endif
+
TIMER_END;
- if( got<0 ){
- ((unixFile*)id)->lastErrno = errno;
- }
+ OSTRACE(("WRITE %-3d %5d %7lld %llu\n", fd, rc, iOff, TIMER_ELAPSED));
- OSTRACE(("WRITE %-3d %5d %7lld %llu\n", id->h, got, offset, TIMER_ELAPSED));
- return got;
+ if( rc<0 && piErrno ) *piErrno = errno;
+ return rc;
+}
+
+
+/*
+** Seek to the offset in id->offset then read cnt bytes into pBuf.
+** Return the number of bytes actually read. Update the offset.
+**
+** To avoid stomping the errno value on a failed write the lastErrno value
+** is set before returning.
+*/
+static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){
+ return seekAndWriteFd(id->h, offset, pBuf, cnt, &id->lastErrno);
}
@@ -25940,6 +26391,23 @@ static int unixWrite(
}
#endif
+#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);
+ return SQLITE_OK;
+ }else{
+ int nCopy = pFile->mmapSize - offset;
+ memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, nCopy);
+ pBuf = &((u8 *)pBuf)[nCopy];
+ amt -= nCopy;
+ offset += nCopy;
+ }
+ }
+#endif
+
while( amt>0 && (wrote = seekAndWrite(pFile, offset, pBuf, amt))>0 ){
amt -= wrote;
offset += wrote;
@@ -26167,7 +26635,7 @@ static int unixSync(sqlite3_file *id, int flags){
}
/* Also fsync the directory containing the file if the DIRSYNC flag
- ** is set. This is a one-time occurrance. Many systems (examples: AIX)
+ ** is set. This is a one-time occurrence. Many systems (examples: AIX)
** are unable to fsync a directory, so ignore errors on the fsync.
*/
if( pFile->ctrlFlags & UNIXFILE_DIRSYNC ){
@@ -26222,6 +26690,14 @@ static int unixTruncate(sqlite3_file *id, i64 nByte){
}
#endif
+ /* If the file was just 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( nByte<pFile->mmapSize ){
+ pFile->mmapSize = nByte;
+ }
+
return SQLITE_OK;
}
}
@@ -26310,6 +26786,19 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
}
}
+ if( pFile->mmapSizeMax>0 && nByte>pFile->mmapSize ){
+ int rc;
+ if( pFile->szChunk<=0 ){
+ if( robust_ftruncate(pFile->h, nByte) ){
+ pFile->lastErrno = errno;
+ return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
+ }
+ }
+
+ rc = unixMapfile(pFile, nByte);
+ return rc;
+ }
+
return SQLITE_OK;
}
@@ -26329,6 +26818,9 @@ static void unixModeBit(unixFile *pFile, unsigned char mask, int *pArg){
}
}
+/* Forward declaration */
+static int unixGetTempname(int nBuf, char *zBuf);
+
/*
** Information and control of an open file handle.
*/
@@ -26366,6 +26858,26 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
*(char**)pArg = sqlite3_mprintf("%s", pFile->pVfs->zName);
return SQLITE_OK;
}
+ case SQLITE_FCNTL_TEMPFILENAME: {
+ char *zTFile = sqlite3_malloc( pFile->pVfs->mxPathname );
+ if( zTFile ){
+ unixGetTempname(pFile->pVfs->mxPathname, zTFile);
+ *(char**)pArg = zTFile;
+ }
+ return SQLITE_OK;
+ }
+ case SQLITE_FCNTL_MMAP_SIZE: {
+ i64 newLimit = *(i64*)pArg;
+ if( newLimit>sqlite3GlobalConfig.mxMmap ){
+ newLimit = sqlite3GlobalConfig.mxMmap;
+ }
+ *(i64*)pArg = pFile->mmapSizeMax;
+ if( newLimit>=0 ){
+ pFile->mmapSizeMax = newLimit;
+ if( newLimit<pFile->mmapSize ) pFile->mmapSize = newLimit;
+ }
+ return SQLITE_OK;
+ }
#ifdef SQLITE_DEBUG
/* The pager calls this method to signal that it has done
** a rollback and that the database is therefore unchanged and
@@ -26397,10 +26909,92 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
** a database and its journal file) that the sector size will be the
** same for both.
*/
-static int unixSectorSize(sqlite3_file *pFile){
- (void)pFile;
+#ifndef __QNXNTO__
+static int unixSectorSize(sqlite3_file *NotUsed){
+ UNUSED_PARAMETER(NotUsed);
return SQLITE_DEFAULT_SECTOR_SIZE;
}
+#endif
+
+/*
+** The following version of unixSectorSize() is optimized for QNX.
+*/
+#ifdef __QNXNTO__
+#include <sys/dcmd_blk.h>
+#include <sys/statvfs.h>
+static int unixSectorSize(sqlite3_file *id){
+ unixFile *pFile = (unixFile*)id;
+ if( pFile->sectorSize == 0 ){
+ struct statvfs fsInfo;
+
+ /* Set defaults for non-supported filesystems */
+ pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
+ pFile->deviceCharacteristics = 0;
+ if( fstatvfs(pFile->h, &fsInfo) == -1 ) {
+ return pFile->sectorSize;
+ }
+
+ if( !strcmp(fsInfo.f_basetype, "tmp") ) {
+ pFile->sectorSize = fsInfo.f_bsize;
+ pFile->deviceCharacteristics =
+ SQLITE_IOCAP_ATOMIC4K | /* All ram filesystem writes are atomic */
+ SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until
+ ** the write succeeds */
+ SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
+ ** so it is ordered */
+ 0;
+ }else if( strstr(fsInfo.f_basetype, "etfs") ){
+ pFile->sectorSize = fsInfo.f_bsize;
+ pFile->deviceCharacteristics =
+ /* etfs cluster size writes are atomic */
+ (pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) |
+ SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until
+ ** the write succeeds */
+ SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
+ ** so it is ordered */
+ 0;
+ }else if( !strcmp(fsInfo.f_basetype, "qnx6") ){
+ pFile->sectorSize = fsInfo.f_bsize;
+ pFile->deviceCharacteristics =
+ SQLITE_IOCAP_ATOMIC | /* All filesystem writes are atomic */
+ SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until
+ ** the write succeeds */
+ SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
+ ** so it is ordered */
+ 0;
+ }else if( !strcmp(fsInfo.f_basetype, "qnx4") ){
+ pFile->sectorSize = fsInfo.f_bsize;
+ pFile->deviceCharacteristics =
+ /* full bitset of atomics from max sector size and smaller */
+ ((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2 |
+ SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
+ ** so it is ordered */
+ 0;
+ }else if( strstr(fsInfo.f_basetype, "dos") ){
+ pFile->sectorSize = fsInfo.f_bsize;
+ pFile->deviceCharacteristics =
+ /* full bitset of atomics from max sector size and smaller */
+ ((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2 |
+ SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
+ ** so it is ordered */
+ 0;
+ }else{
+ pFile->deviceCharacteristics =
+ SQLITE_IOCAP_ATOMIC512 | /* blocks are atomic */
+ SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until
+ ** the write succeeds */
+ 0;
+ }
+ }
+ /* Last chance verification. If the sector size isn't a multiple of 512
+ ** then it isn't valid.*/
+ if( pFile->sectorSize % 512 != 0 ){
+ pFile->deviceCharacteristics = 0;
+ pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
+ }
+ return pFile->sectorSize;
+}
+#endif /* __QNXNTO__ */
/*
** Return the device characteristics for the file.
@@ -26417,11 +27011,15 @@ static int unixSectorSize(sqlite3_file *pFile){
*/
static int unixDeviceCharacteristics(sqlite3_file *id){
unixFile *p = (unixFile*)id;
+ int rc = 0;
+#ifdef __QNXNTO__
+ if( p->sectorSize==0 ) unixSectorSize(id);
+ rc = p->deviceCharacteristics;
+#endif
if( p->ctrlFlags & UNIXFILE_PSOW ){
- return SQLITE_IOCAP_POWERSAFE_OVERWRITE;
- }else{
- return 0;
+ rc |= SQLITE_IOCAP_POWERSAFE_OVERWRITE;
}
+ return rc;
}
#ifndef SQLITE_OMIT_WAL
@@ -26592,7 +27190,7 @@ static void unixShmPurge(unixFile *pFd){
sqlite3_mutex_free(p->mutex);
for(i=0; i<p->nRegion; i++){
if( p->h>=0 ){
- munmap(p->apRegion[i], p->szRegion);
+ osMunmap(p->apRegion[i], p->szRegion);
}else{
sqlite3_free(p->apRegion[i]);
}
@@ -26832,16 +27430,32 @@ static int unixShmMap(
if( sStat.st_size<nByte ){
/* The requested memory region does not exist. If bExtend is set to
** false, exit early. *pp will be set to NULL and SQLITE_OK returned.
- **
- ** Alternatively, if bExtend is true, use ftruncate() to allocate
- ** the requested memory region.
*/
- if( !bExtend ) goto shmpage_out;
- if( robust_ftruncate(pShmNode->h, nByte) ){
- rc = unixLogError(SQLITE_IOERR_SHMSIZE, "ftruncate",
- pShmNode->zFilename);
+ if( !bExtend ){
goto shmpage_out;
}
+
+ /* Alternatively, if bExtend is true, extend the file. Do this by
+ ** writing a single byte to the end of each (OS) page being
+ ** allocated or extended. Technically, we need only write to the
+ ** last page in order to extend the file. But writing to all new
+ ** pages forces the OS to allocate them immediately, which reduces
+ ** the chances of SIGBUS while accessing the mapped region later on.
+ */
+ else{
+ static const int pgsz = 4096;
+ int iPg;
+
+ /* Write to the last byte of each newly allocated or extended page */
+ assert( (nByte % pgsz)==0 );
+ for(iPg=(sStat.st_size/pgsz); iPg<(nByte/pgsz); iPg++){
+ if( seekAndWriteFd(pShmNode->h, iPg*pgsz + pgsz-1, "", 1, 0)!=1 ){
+ const char *zFile = pShmNode->zFilename;
+ rc = unixLogError(SQLITE_IOERR_SHMSIZE, "write", zFile);
+ goto shmpage_out;
+ }
+ }
+ }
}
}
@@ -26857,9 +27471,9 @@ static int unixShmMap(
while(pShmNode->nRegion<=iRegion){
void *pMem;
if( pShmNode->h>=0 ){
- pMem = mmap(0, szRegion,
+ pMem = osMmap(0, szRegion,
pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE,
- MAP_SHARED, pShmNode->h, pShmNode->nRegion*szRegion
+ MAP_SHARED, pShmNode->h, szRegion*(i64)pShmNode->nRegion
);
if( pMem==MAP_FAILED ){
rc = unixLogError(SQLITE_IOERR_SHMMAP, "mmap", pShmNode->zFilename);
@@ -27075,6 +27689,236 @@ static int unixShmUnmap(
#endif /* #ifndef SQLITE_OMIT_WAL */
/*
+** If it is currently memory mapped, unmap file pFd.
+*/
+static void unixUnmapfile(unixFile *pFd){
+ assert( pFd->nFetchOut==0 );
+#if SQLITE_MAX_MMAP_SIZE>0
+ if( pFd->pMapRegion ){
+ osMunmap(pFd->pMapRegion, pFd->mmapSizeActual);
+ pFd->pMapRegion = 0;
+ pFd->mmapSize = 0;
+ pFd->mmapSizeActual = 0;
+ }
+#endif
+}
+
+#if SQLITE_MAX_MMAP_SIZE>0
+/*
+** Return the system page size.
+*/
+static int unixGetPagesize(void){
+#if HAVE_MREMAP
+ return 512;
+#elif defined(_BSD_SOURCE)
+ return getpagesize();
+#else
+ return (int)sysconf(_SC_PAGESIZE);
+#endif
+}
+#endif /* SQLITE_MAX_MMAP_SIZE>0 */
+
+#if SQLITE_MAX_MMAP_SIZE>0
+/*
+** Attempt to set the size of the memory mapping maintained by file
+** descriptor pFd to nNew bytes. Any existing mapping is discarded.
+**
+** If successful, this function sets the following variables:
+**
+** unixFile.pMapRegion
+** unixFile.mmapSize
+** unixFile.mmapSizeActual
+**
+** If unsuccessful, an error message is logged via sqlite3_log() and
+** the three variables above are zeroed. In this case SQLite should
+** continue accessing the database using the xRead() and xWrite()
+** methods.
+*/
+static void unixRemapfile(
+ unixFile *pFd, /* File descriptor object */
+ i64 nNew /* Required mapping size */
+){
+ const char *zErr = "mmap";
+ int h = pFd->h; /* File descriptor open on db file */
+ u8 *pOrig = (u8 *)pFd->pMapRegion; /* Pointer to current file mapping */
+ i64 nOrig = pFd->mmapSizeActual; /* Size of pOrig region in bytes */
+ u8 *pNew = 0; /* Location of new mapping */
+ int flags = PROT_READ; /* Flags to pass to mmap() */
+
+ assert( pFd->nFetchOut==0 );
+ assert( nNew>pFd->mmapSize );
+ assert( nNew<=pFd->mmapSizeMax );
+ assert( nNew>0 );
+ assert( pFd->mmapSizeActual>=pFd->mmapSize );
+ assert( MAP_FAILED!=0 );
+
+ if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE;
+
+ if( pOrig ){
+ const int szSyspage = unixGetPagesize();
+ i64 nReuse = (pFd->mmapSize & ~(szSyspage-1));
+ u8 *pReq = &pOrig[nReuse];
+
+ /* Unmap any pages of the existing mapping that cannot be reused. */
+ if( nReuse!=nOrig ){
+ osMunmap(pReq, nOrig-nReuse);
+ }
+
+#if HAVE_MREMAP
+ pNew = osMremap(pOrig, nReuse, nNew, MREMAP_MAYMOVE);
+ zErr = "mremap";
+#else
+ pNew = osMmap(pReq, nNew-nReuse, flags, MAP_SHARED, h, nReuse);
+ if( pNew!=MAP_FAILED ){
+ if( pNew!=pReq ){
+ osMunmap(pNew, nNew - nReuse);
+ pNew = 0;
+ }else{
+ pNew = pOrig;
+ }
+ }
+#endif
+
+ /* The attempt to extend the existing mapping failed. Free it. */
+ if( pNew==MAP_FAILED || pNew==0 ){
+ osMunmap(pOrig, nReuse);
+ }
+ }
+
+ /* If pNew is still NULL, try to create an entirely new mapping. */
+ if( pNew==0 ){
+ pNew = osMmap(0, nNew, flags, MAP_SHARED, h, 0);
+ }
+
+ if( pNew==MAP_FAILED ){
+ pNew = 0;
+ nNew = 0;
+ unixLogError(SQLITE_OK, zErr, pFd->zPath);
+
+ /* If the mmap() above failed, assume that all subsequent mmap() calls
+ ** will probably fail too. Fall back to using xRead/xWrite exclusively
+ ** in this case. */
+ pFd->mmapSizeMax = 0;
+ }
+ pFd->pMapRegion = (void *)pNew;
+ pFd->mmapSize = pFd->mmapSizeActual = nNew;
+}
+#endif
+
+/*
+** 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_LIMIT, 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 int unixMapfile(unixFile *pFd, i64 nByte){
+#if SQLITE_MAX_MMAP_SIZE>0
+ i64 nMap = nByte;
+ int rc;
+
+ assert( nMap>=0 || pFd->nFetchOut==0 );
+ if( pFd->nFetchOut>0 ) return SQLITE_OK;
+
+ if( nMap<0 ){
+ struct stat statbuf; /* Low-level file information */
+ rc = osFstat(pFd->h, &statbuf);
+ if( rc!=SQLITE_OK ){
+ return SQLITE_IOERR_FSTAT;
+ }
+ nMap = statbuf.st_size;
+ }
+ if( nMap>pFd->mmapSizeMax ){
+ nMap = pFd->mmapSizeMax;
+ }
+
+ if( nMap!=pFd->mmapSize ){
+ if( nMap>0 ){
+ unixRemapfile(pFd, nMap);
+ }else{
+ unixUnmapfile(pFd);
+ }
+ }
+#endif
+
+ return SQLITE_OK;
+}
+
+/*
+** 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 unixUnfetch().
+*/
+static int unixFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
+#if SQLITE_MAX_MMAP_SIZE>0
+ unixFile *pFd = (unixFile *)fd; /* The underlying database file */
+#endif
+ *pp = 0;
+
+#if SQLITE_MAX_MMAP_SIZE>0
+ if( pFd->mmapSizeMax>0 ){
+ if( pFd->pMapRegion==0 ){
+ int rc = unixMapfile(pFd, -1);
+ if( rc!=SQLITE_OK ) return rc;
+ }
+ if( pFd->mmapSize >= iOff+nAmt ){
+ *pp = &((u8 *)pFd->pMapRegion)[iOff];
+ pFd->nFetchOut++;
+ }
+ }
+#endif
+ return SQLITE_OK;
+}
+
+/*
+** If the third argument is non-NULL, then this function releases a
+** reference obtained by an earlier call to unixFetch(). The second
+** argument passed to this function must be the same as the corresponding
+** argument that was passed to the unixFetch() 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 unixUnfetch(sqlite3_file *fd, i64 iOff, void *p){
+ unixFile *pFd = (unixFile *)fd; /* The underlying database file */
+ UNUSED_PARAMETER(iOff);
+
+ /* 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] );
+
+ if( p ){
+ pFd->nFetchOut--;
+ }else{
+ unixUnmapfile(pFd);
+ }
+
+ assert( pFd->nFetchOut>=0 );
+ return SQLITE_OK;
+}
+
+/*
** Here ends the implementation of all sqlite3_file methods.
**
********************** End sqlite3_file Methods *******************************
@@ -27132,7 +27976,9 @@ static const sqlite3_io_methods METHOD = { \
unixShmMap, /* xShmMap */ \
unixShmLock, /* xShmLock */ \
unixShmBarrier, /* xShmBarrier */ \
- unixShmUnmap /* xShmUnmap */ \
+ unixShmUnmap, /* xShmUnmap */ \
+ unixFetch, /* xFetch */ \
+ unixUnfetch, /* xUnfetch */ \
}; \
static const sqlite3_io_methods *FINDER##Impl(const char *z, unixFile *p){ \
UNUSED_PARAMETER(z); UNUSED_PARAMETER(p); \
@@ -27149,7 +27995,7 @@ static const sqlite3_io_methods *(*const FINDER)(const char*,unixFile *p) \
IOMETHODS(
posixIoFinder, /* Finder function name */
posixIoMethods, /* sqlite3_io_methods object name */
- 2, /* shared memory is enabled */
+ 3, /* shared memory and mmap are enabled */
unixClose, /* xClose method */
unixLock, /* xLock method */
unixUnlock, /* xUnlock method */
@@ -27400,11 +28246,12 @@ static int fillInUnixFile(
pNew->pVfs = pVfs;
pNew->zPath = zFilename;
pNew->ctrlFlags = (u8)ctrlFlags;
+ pNew->mmapSizeMax = sqlite3GlobalConfig.szMmap;
if( sqlite3_uri_boolean(((ctrlFlags & UNIXFILE_URI) ? zFilename : 0),
"psow", SQLITE_POWERSAFE_OVERWRITE) ){
pNew->ctrlFlags |= UNIXFILE_PSOW;
}
- if( memcmp(pVfs->zName,"unix-excl",10)==0 ){
+ if( strcmp(pVfs->zName,"unix-excl")==0 ){
pNew->ctrlFlags |= UNIXFILE_EXCL;
}
@@ -27436,7 +28283,7 @@ static int fillInUnixFile(
unixEnterMutex();
rc = findInodeInfo(pNew, &pNew->pInode);
if( rc!=SQLITE_OK ){
- /* If an error occured in findInodeInfo(), close the file descriptor
+ /* If an error occurred in findInodeInfo(), close the file descriptor
** immediately, before releasing the mutex. findInodeInfo() may fail
** in two scenarios:
**
@@ -27535,15 +28382,15 @@ static int fillInUnixFile(
if( h>=0 ) robust_close(pNew, h, __LINE__);
h = -1;
osUnlink(zFilename);
- isDelete = 0;
+ pNew->ctrlFlags |= UNIXFILE_DELETE;
}
- if( isDelete ) pNew->ctrlFlags |= UNIXFILE_DELETE;
#endif
if( rc!=SQLITE_OK ){
if( h>=0 ) robust_close(pNew, h, __LINE__);
}else{
pNew->pMethod = pLockingStyle;
OpenCounter(+1);
+ verifyDbFile(pNew);
}
return rc;
}
@@ -28043,8 +28890,13 @@ static int unixDelete(
int rc = SQLITE_OK;
UNUSED_PARAMETER(NotUsed);
SimulateIOError(return SQLITE_IOERR_DELETE);
- if( osUnlink(zPath)==(-1) && errno!=ENOENT ){
- return unixLogError(SQLITE_IOERR_DELETE, "unlink", zPath);
+ if( osUnlink(zPath)==(-1) ){
+ if( errno==ENOENT ){
+ rc = SQLITE_IOERR_DELETE_NOENT;
+ }else{
+ rc = unixLogError(SQLITE_IOERR_DELETE, "unlink", zPath);
+ }
+ return rc;
}
#ifndef SQLITE_DISABLE_DIRSYNC
if( (dirSync & 1)!=0 ){
@@ -28069,7 +28921,7 @@ static int unixDelete(
}
/*
-** Test the existance of or access permissions of file zPath. The
+** Test the existence of or access permissions of file zPath. The
** test performed depends on the value of flags:
**
** SQLITE_ACCESS_EXISTS: Return 1 if the file exists
@@ -29632,7 +30484,7 @@ SQLITE_API int sqlite3_os_init(void){
/* Double-check that the aSyscall[] array has been constructed
** correctly. See ticket [bb3a86e890c8e96ab] */
- assert( ArraySize(aSyscall)==22 );
+ assert( ArraySize(aSyscall)==24 );
/* Register all VFSes defined in the aVfs[] array */
for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
@@ -29890,6 +30742,66 @@ SQLITE_API int sqlite3_open_file_count = 0;
/************** Continuing where we left off in os_win.c *********************/
/*
+** Compiling and using WAL mode requires several APIs that are only
+** available in Windows platforms based on the NT kernel.
+*/
+#if !SQLITE_OS_WINNT && !defined(SQLITE_OMIT_WAL)
+# error "WAL mode requires support from the Windows NT kernel, compile\
+ with SQLITE_OMIT_WAL."
+#endif
+
+/*
+** Are most of the Win32 ANSI APIs available (i.e. with certain exceptions
+** based on the sub-platform)?
+*/
+#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
+# define SQLITE_WIN32_HAS_ANSI
+#endif
+
+/*
+** Are most of the Win32 Unicode APIs available (i.e. with certain exceptions
+** based on the sub-platform)?
+*/
+#if SQLITE_OS_WINCE || SQLITE_OS_WINNT || SQLITE_OS_WINRT
+# define SQLITE_WIN32_HAS_WIDE
+#endif
+
+/*
+** 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)?
+*/
+#if SQLITE_WIN32_FILEMAPPING_API && !defined(SQLITE_OMIT_WAL)
+/*
+** Two of the file mapping APIs are different under WinRT. Figure out which
+** set we need.
+*/
+#if SQLITE_OS_WINRT
+WINBASEAPI HANDLE WINAPI CreateFileMappingFromApp(HANDLE, \
+ LPSECURITY_ATTRIBUTES, ULONG, ULONG64, LPCWSTR);
+
+WINBASEAPI LPVOID WINAPI MapViewOfFileFromApp(HANDLE, ULONG, ULONG64, SIZE_T);
+#else
+#if defined(SQLITE_WIN32_HAS_ANSI)
+WINBASEAPI HANDLE WINAPI CreateFileMappingA(HANDLE, LPSECURITY_ATTRIBUTES, \
+ DWORD, DWORD, DWORD, LPCSTR);
+#endif /* defined(SQLITE_WIN32_HAS_ANSI) */
+
+#if defined(SQLITE_WIN32_HAS_WIDE)
+WINBASEAPI HANDLE WINAPI CreateFileMappingW(HANDLE, LPSECURITY_ATTRIBUTES, \
+ DWORD, DWORD, DWORD, LPCWSTR);
+#endif /* defined(SQLITE_WIN32_HAS_WIDE) */
+
+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.
+*/
+WINBASEAPI BOOL WINAPI UnmapViewOfFile(LPCVOID);
+#endif /* SQLITE_WIN32_FILEMAPPING_API && !defined(SQLITE_OMIT_WAL) */
+
+/*
** Macro to find the minimum of two numeric values.
*/
#ifndef MIN
@@ -29955,11 +30867,20 @@ struct winFile {
winceLock local; /* Locks obtained by this instance of winFile */
winceLock *shared; /* Global shared lock memory for the file */
#endif
+#if SQLITE_MAX_MMAP_SIZE>0
+ int nFetchOut; /* Number of outstanding xFetch references */
+ HANDLE hMap; /* Handle for accessing memory mapping */
+ void *pMapRegion; /* Area memory mapped */
+ sqlite3_int64 mmapSize; /* Usable size of mapped region */
+ sqlite3_int64 mmapSizeActual; /* Actual size of mapped region */
+ sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */
+#endif
};
/*
** Allowed values for winFile.ctrlFlags
*/
+#define WINFILE_RDONLY 0x02 /* Connection is read only */
#define WINFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */
#define WINFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */
@@ -30094,14 +31015,6 @@ SQLITE_API int sqlite3_os_type = 0;
static int sqlite3_os_type = 0;
#endif
-#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
-# define SQLITE_WIN32_HAS_ANSI
-#endif
-
-#if SQLITE_OS_WINCE || SQLITE_OS_WINNT || SQLITE_OS_WINRT
-# define SQLITE_WIN32_HAS_WIDE
-#endif
-
#ifndef SYSCALL
# define SYSCALL sqlite3_syscall_ptr
#endif
@@ -30121,7 +31034,7 @@ static int sqlite3_os_type = 0;
** to all overrideable system calls.
*/
static struct win_syscall {
- const char *zName; /* Name of the sytem call */
+ const char *zName; /* Name of the system call */
sqlite3_syscall_ptr pCurrent; /* Current value of the system call */
sqlite3_syscall_ptr pDefault; /* Default value */
} aSyscall[] = {
@@ -30173,6 +31086,16 @@ static struct win_syscall {
#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))
+ { "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))
{ "CreateFileMappingW", (SYSCALL)CreateFileMappingW, 0 },
@@ -30181,7 +31104,7 @@ static struct win_syscall {
#endif
#define osCreateFileMappingW ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \
- DWORD,DWORD,DWORD,LPCWSTR))aSyscall[6].pCurrent)
+ DWORD,DWORD,DWORD,LPCWSTR))aSyscall[7].pCurrent)
#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
{ "CreateMutexW", (SYSCALL)CreateMutexW, 0 },
@@ -30190,7 +31113,7 @@ static struct win_syscall {
#endif
#define osCreateMutexW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,BOOL, \
- LPCWSTR))aSyscall[7].pCurrent)
+ LPCWSTR))aSyscall[8].pCurrent)
#if defined(SQLITE_WIN32_HAS_ANSI)
{ "DeleteFileA", (SYSCALL)DeleteFileA, 0 },
@@ -30198,7 +31121,7 @@ static struct win_syscall {
{ "DeleteFileA", (SYSCALL)0, 0 },
#endif
-#define osDeleteFileA ((BOOL(WINAPI*)(LPCSTR))aSyscall[8].pCurrent)
+#define osDeleteFileA ((BOOL(WINAPI*)(LPCSTR))aSyscall[9].pCurrent)
#if defined(SQLITE_WIN32_HAS_WIDE)
{ "DeleteFileW", (SYSCALL)DeleteFileW, 0 },
@@ -30206,7 +31129,7 @@ static struct win_syscall {
{ "DeleteFileW", (SYSCALL)0, 0 },
#endif
-#define osDeleteFileW ((BOOL(WINAPI*)(LPCWSTR))aSyscall[9].pCurrent)
+#define osDeleteFileW ((BOOL(WINAPI*)(LPCWSTR))aSyscall[10].pCurrent)
#if SQLITE_OS_WINCE
{ "FileTimeToLocalFileTime", (SYSCALL)FileTimeToLocalFileTime, 0 },
@@ -30215,7 +31138,7 @@ static struct win_syscall {
#endif
#define osFileTimeToLocalFileTime ((BOOL(WINAPI*)(CONST FILETIME*, \
- LPFILETIME))aSyscall[10].pCurrent)
+ LPFILETIME))aSyscall[11].pCurrent)
#if SQLITE_OS_WINCE
{ "FileTimeToSystemTime", (SYSCALL)FileTimeToSystemTime, 0 },
@@ -30224,11 +31147,11 @@ static struct win_syscall {
#endif
#define osFileTimeToSystemTime ((BOOL(WINAPI*)(CONST FILETIME*, \
- LPSYSTEMTIME))aSyscall[11].pCurrent)
+ LPSYSTEMTIME))aSyscall[12].pCurrent)
{ "FlushFileBuffers", (SYSCALL)FlushFileBuffers, 0 },
-#define osFlushFileBuffers ((BOOL(WINAPI*)(HANDLE))aSyscall[12].pCurrent)
+#define osFlushFileBuffers ((BOOL(WINAPI*)(HANDLE))aSyscall[13].pCurrent)
#if defined(SQLITE_WIN32_HAS_ANSI)
{ "FormatMessageA", (SYSCALL)FormatMessageA, 0 },
@@ -30237,7 +31160,7 @@ static struct win_syscall {
#endif
#define osFormatMessageA ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPSTR, \
- DWORD,va_list*))aSyscall[13].pCurrent)
+ DWORD,va_list*))aSyscall[14].pCurrent)
#if defined(SQLITE_WIN32_HAS_WIDE)
{ "FormatMessageW", (SYSCALL)FormatMessageW, 0 },
@@ -30246,15 +31169,19 @@ static struct win_syscall {
#endif
#define osFormatMessageW ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPWSTR, \
- DWORD,va_list*))aSyscall[14].pCurrent)
+ 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[15].pCurrent)
+#define osFreeLibrary ((BOOL(WINAPI*)(HMODULE))aSyscall[16].pCurrent)
{ "GetCurrentProcessId", (SYSCALL)GetCurrentProcessId, 0 },
-#define osGetCurrentProcessId ((DWORD(WINAPI*)(VOID))aSyscall[16].pCurrent)
+#define osGetCurrentProcessId ((DWORD(WINAPI*)(VOID))aSyscall[17].pCurrent)
#if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_ANSI)
{ "GetDiskFreeSpaceA", (SYSCALL)GetDiskFreeSpaceA, 0 },
@@ -30263,7 +31190,7 @@ static struct win_syscall {
#endif
#define osGetDiskFreeSpaceA ((BOOL(WINAPI*)(LPCSTR,LPDWORD,LPDWORD,LPDWORD, \
- LPDWORD))aSyscall[17].pCurrent)
+ LPDWORD))aSyscall[18].pCurrent)
#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
{ "GetDiskFreeSpaceW", (SYSCALL)GetDiskFreeSpaceW, 0 },
@@ -30272,7 +31199,7 @@ static struct win_syscall {
#endif
#define osGetDiskFreeSpaceW ((BOOL(WINAPI*)(LPCWSTR,LPDWORD,LPDWORD,LPDWORD, \
- LPDWORD))aSyscall[18].pCurrent)
+ LPDWORD))aSyscall[19].pCurrent)
#if defined(SQLITE_WIN32_HAS_ANSI)
{ "GetFileAttributesA", (SYSCALL)GetFileAttributesA, 0 },
@@ -30280,7 +31207,7 @@ static struct win_syscall {
{ "GetFileAttributesA", (SYSCALL)0, 0 },
#endif
-#define osGetFileAttributesA ((DWORD(WINAPI*)(LPCSTR))aSyscall[19].pCurrent)
+#define osGetFileAttributesA ((DWORD(WINAPI*)(LPCSTR))aSyscall[20].pCurrent)
#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
{ "GetFileAttributesW", (SYSCALL)GetFileAttributesW, 0 },
@@ -30288,7 +31215,7 @@ static struct win_syscall {
{ "GetFileAttributesW", (SYSCALL)0, 0 },
#endif
-#define osGetFileAttributesW ((DWORD(WINAPI*)(LPCWSTR))aSyscall[20].pCurrent)
+#define osGetFileAttributesW ((DWORD(WINAPI*)(LPCWSTR))aSyscall[21].pCurrent)
#if defined(SQLITE_WIN32_HAS_WIDE)
{ "GetFileAttributesExW", (SYSCALL)GetFileAttributesExW, 0 },
@@ -30297,7 +31224,7 @@ static struct win_syscall {
#endif
#define osGetFileAttributesExW ((BOOL(WINAPI*)(LPCWSTR,GET_FILEEX_INFO_LEVELS, \
- LPVOID))aSyscall[21].pCurrent)
+ LPVOID))aSyscall[22].pCurrent)
#if !SQLITE_OS_WINRT
{ "GetFileSize", (SYSCALL)GetFileSize, 0 },
@@ -30305,7 +31232,7 @@ static struct win_syscall {
{ "GetFileSize", (SYSCALL)0, 0 },
#endif
-#define osGetFileSize ((DWORD(WINAPI*)(HANDLE,LPDWORD))aSyscall[22].pCurrent)
+#define osGetFileSize ((DWORD(WINAPI*)(HANDLE,LPDWORD))aSyscall[23].pCurrent)
#if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_ANSI)
{ "GetFullPathNameA", (SYSCALL)GetFullPathNameA, 0 },
@@ -30314,7 +31241,7 @@ static struct win_syscall {
#endif
#define osGetFullPathNameA ((DWORD(WINAPI*)(LPCSTR,DWORD,LPSTR, \
- LPSTR*))aSyscall[23].pCurrent)
+ LPSTR*))aSyscall[24].pCurrent)
#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
{ "GetFullPathNameW", (SYSCALL)GetFullPathNameW, 0 },
@@ -30323,12 +31250,13 @@ static struct win_syscall {
#endif
#define osGetFullPathNameW ((DWORD(WINAPI*)(LPCWSTR,DWORD,LPWSTR, \
- LPWSTR*))aSyscall[24].pCurrent)
+ LPWSTR*))aSyscall[25].pCurrent)
{ "GetLastError", (SYSCALL)GetLastError, 0 },
-#define osGetLastError ((DWORD(WINAPI*)(VOID))aSyscall[25].pCurrent)
+#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 },
@@ -30337,9 +31265,12 @@ static struct win_syscall {
** 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[26].pCurrent)
+ LPCSTR))aSyscall[27].pCurrent)
#if !SQLITE_OS_WINRT
{ "GetSystemInfo", (SYSCALL)GetSystemInfo, 0 },
@@ -30347,11 +31278,11 @@ static struct win_syscall {
{ "GetSystemInfo", (SYSCALL)0, 0 },
#endif
-#define osGetSystemInfo ((VOID(WINAPI*)(LPSYSTEM_INFO))aSyscall[27].pCurrent)
+#define osGetSystemInfo ((VOID(WINAPI*)(LPSYSTEM_INFO))aSyscall[28].pCurrent)
{ "GetSystemTime", (SYSCALL)GetSystemTime, 0 },
-#define osGetSystemTime ((VOID(WINAPI*)(LPSYSTEMTIME))aSyscall[28].pCurrent)
+#define osGetSystemTime ((VOID(WINAPI*)(LPSYSTEMTIME))aSyscall[29].pCurrent)
#if !SQLITE_OS_WINCE
{ "GetSystemTimeAsFileTime", (SYSCALL)GetSystemTimeAsFileTime, 0 },
@@ -30360,7 +31291,7 @@ static struct win_syscall {
#endif
#define osGetSystemTimeAsFileTime ((VOID(WINAPI*)( \
- LPFILETIME))aSyscall[29].pCurrent)
+ LPFILETIME))aSyscall[30].pCurrent)
#if defined(SQLITE_WIN32_HAS_ANSI)
{ "GetTempPathA", (SYSCALL)GetTempPathA, 0 },
@@ -30368,7 +31299,7 @@ static struct win_syscall {
{ "GetTempPathA", (SYSCALL)0, 0 },
#endif
-#define osGetTempPathA ((DWORD(WINAPI*)(DWORD,LPSTR))aSyscall[30].pCurrent)
+#define osGetTempPathA ((DWORD(WINAPI*)(DWORD,LPSTR))aSyscall[31].pCurrent)
#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
{ "GetTempPathW", (SYSCALL)GetTempPathW, 0 },
@@ -30376,7 +31307,7 @@ static struct win_syscall {
{ "GetTempPathW", (SYSCALL)0, 0 },
#endif
-#define osGetTempPathW ((DWORD(WINAPI*)(DWORD,LPWSTR))aSyscall[31].pCurrent)
+#define osGetTempPathW ((DWORD(WINAPI*)(DWORD,LPWSTR))aSyscall[32].pCurrent)
#if !SQLITE_OS_WINRT
{ "GetTickCount", (SYSCALL)GetTickCount, 0 },
@@ -30384,7 +31315,7 @@ static struct win_syscall {
{ "GetTickCount", (SYSCALL)0, 0 },
#endif
-#define osGetTickCount ((DWORD(WINAPI*)(VOID))aSyscall[32].pCurrent)
+#define osGetTickCount ((DWORD(WINAPI*)(VOID))aSyscall[33].pCurrent)
#if defined(SQLITE_WIN32_HAS_ANSI)
{ "GetVersionExA", (SYSCALL)GetVersionExA, 0 },
@@ -30393,12 +31324,12 @@ static struct win_syscall {
#endif
#define osGetVersionExA ((BOOL(WINAPI*)( \
- LPOSVERSIONINFOA))aSyscall[33].pCurrent)
+ LPOSVERSIONINFOA))aSyscall[34].pCurrent)
{ "HeapAlloc", (SYSCALL)HeapAlloc, 0 },
#define osHeapAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD, \
- SIZE_T))aSyscall[34].pCurrent)
+ SIZE_T))aSyscall[35].pCurrent)
#if !SQLITE_OS_WINRT
{ "HeapCreate", (SYSCALL)HeapCreate, 0 },
@@ -30407,7 +31338,7 @@ static struct win_syscall {
#endif
#define osHeapCreate ((HANDLE(WINAPI*)(DWORD,SIZE_T, \
- SIZE_T))aSyscall[35].pCurrent)
+ SIZE_T))aSyscall[36].pCurrent)
#if !SQLITE_OS_WINRT
{ "HeapDestroy", (SYSCALL)HeapDestroy, 0 },
@@ -30415,21 +31346,21 @@ static struct win_syscall {
{ "HeapDestroy", (SYSCALL)0, 0 },
#endif
-#define osHeapDestroy ((BOOL(WINAPI*)(HANDLE))aSyscall[36].pCurrent)
+#define osHeapDestroy ((BOOL(WINAPI*)(HANDLE))aSyscall[37].pCurrent)
{ "HeapFree", (SYSCALL)HeapFree, 0 },
-#define osHeapFree ((BOOL(WINAPI*)(HANDLE,DWORD,LPVOID))aSyscall[37].pCurrent)
+#define osHeapFree ((BOOL(WINAPI*)(HANDLE,DWORD,LPVOID))aSyscall[38].pCurrent)
{ "HeapReAlloc", (SYSCALL)HeapReAlloc, 0 },
#define osHeapReAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD,LPVOID, \
- SIZE_T))aSyscall[38].pCurrent)
+ SIZE_T))aSyscall[39].pCurrent)
{ "HeapSize", (SYSCALL)HeapSize, 0 },
#define osHeapSize ((SIZE_T(WINAPI*)(HANDLE,DWORD, \
- LPCVOID))aSyscall[39].pCurrent)
+ LPCVOID))aSyscall[40].pCurrent)
#if !SQLITE_OS_WINRT
{ "HeapValidate", (SYSCALL)HeapValidate, 0 },
@@ -30438,23 +31369,24 @@ static struct win_syscall {
#endif
#define osHeapValidate ((BOOL(WINAPI*)(HANDLE,DWORD, \
- LPCVOID))aSyscall[40].pCurrent)
+ LPCVOID))aSyscall[41].pCurrent)
-#if defined(SQLITE_WIN32_HAS_ANSI)
+#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[41].pCurrent)
+#define osLoadLibraryA ((HMODULE(WINAPI*)(LPCSTR))aSyscall[42].pCurrent)
-#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
+#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[42].pCurrent)
+#define osLoadLibraryW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[43].pCurrent)
#if !SQLITE_OS_WINRT
{ "LocalFree", (SYSCALL)LocalFree, 0 },
@@ -30462,7 +31394,7 @@ static struct win_syscall {
{ "LocalFree", (SYSCALL)0, 0 },
#endif
-#define osLocalFree ((HLOCAL(WINAPI*)(HLOCAL))aSyscall[43].pCurrent)
+#define osLocalFree ((HLOCAL(WINAPI*)(HLOCAL))aSyscall[44].pCurrent)
#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
{ "LockFile", (SYSCALL)LockFile, 0 },
@@ -30472,7 +31404,7 @@ static struct win_syscall {
#ifndef osLockFile
#define osLockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
- DWORD))aSyscall[44].pCurrent)
+ DWORD))aSyscall[45].pCurrent)
#endif
#if !SQLITE_OS_WINCE
@@ -30483,7 +31415,7 @@ static struct win_syscall {
#ifndef osLockFileEx
#define osLockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD,DWORD, \
- LPOVERLAPPED))aSyscall[45].pCurrent)
+ LPOVERLAPPED))aSyscall[46].pCurrent)
#endif
#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && !defined(SQLITE_OMIT_WAL))
@@ -30493,26 +31425,26 @@ static struct win_syscall {
#endif
#define osMapViewOfFile ((LPVOID(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
- SIZE_T))aSyscall[46].pCurrent)
+ SIZE_T))aSyscall[47].pCurrent)
{ "MultiByteToWideChar", (SYSCALL)MultiByteToWideChar, 0 },
#define osMultiByteToWideChar ((int(WINAPI*)(UINT,DWORD,LPCSTR,int,LPWSTR, \
- int))aSyscall[47].pCurrent)
+ int))aSyscall[48].pCurrent)
{ "QueryPerformanceCounter", (SYSCALL)QueryPerformanceCounter, 0 },
#define osQueryPerformanceCounter ((BOOL(WINAPI*)( \
- LARGE_INTEGER*))aSyscall[48].pCurrent)
+ LARGE_INTEGER*))aSyscall[49].pCurrent)
{ "ReadFile", (SYSCALL)ReadFile, 0 },
#define osReadFile ((BOOL(WINAPI*)(HANDLE,LPVOID,DWORD,LPDWORD, \
- LPOVERLAPPED))aSyscall[49].pCurrent)
+ LPOVERLAPPED))aSyscall[50].pCurrent)
{ "SetEndOfFile", (SYSCALL)SetEndOfFile, 0 },
-#define osSetEndOfFile ((BOOL(WINAPI*)(HANDLE))aSyscall[50].pCurrent)
+#define osSetEndOfFile ((BOOL(WINAPI*)(HANDLE))aSyscall[51].pCurrent)
#if !SQLITE_OS_WINRT
{ "SetFilePointer", (SYSCALL)SetFilePointer, 0 },
@@ -30521,7 +31453,7 @@ static struct win_syscall {
#endif
#define osSetFilePointer ((DWORD(WINAPI*)(HANDLE,LONG,PLONG, \
- DWORD))aSyscall[51].pCurrent)
+ DWORD))aSyscall[52].pCurrent)
#if !SQLITE_OS_WINRT
{ "Sleep", (SYSCALL)Sleep, 0 },
@@ -30529,12 +31461,12 @@ static struct win_syscall {
{ "Sleep", (SYSCALL)0, 0 },
#endif
-#define osSleep ((VOID(WINAPI*)(DWORD))aSyscall[52].pCurrent)
+#define osSleep ((VOID(WINAPI*)(DWORD))aSyscall[53].pCurrent)
{ "SystemTimeToFileTime", (SYSCALL)SystemTimeToFileTime, 0 },
#define osSystemTimeToFileTime ((BOOL(WINAPI*)(CONST SYSTEMTIME*, \
- LPFILETIME))aSyscall[53].pCurrent)
+ LPFILETIME))aSyscall[54].pCurrent)
#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
{ "UnlockFile", (SYSCALL)UnlockFile, 0 },
@@ -30544,7 +31476,7 @@ static struct win_syscall {
#ifndef osUnlockFile
#define osUnlockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
- DWORD))aSyscall[54].pCurrent)
+ DWORD))aSyscall[55].pCurrent)
#endif
#if !SQLITE_OS_WINCE
@@ -30554,7 +31486,7 @@ static struct win_syscall {
#endif
#define osUnlockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
- LPOVERLAPPED))aSyscall[55].pCurrent)
+ LPOVERLAPPED))aSyscall[56].pCurrent)
#if SQLITE_OS_WINCE || !defined(SQLITE_OMIT_WAL)
{ "UnmapViewOfFile", (SYSCALL)UnmapViewOfFile, 0 },
@@ -30562,17 +31494,17 @@ static struct win_syscall {
{ "UnmapViewOfFile", (SYSCALL)0, 0 },
#endif
-#define osUnmapViewOfFile ((BOOL(WINAPI*)(LPCVOID))aSyscall[56].pCurrent)
+#define osUnmapViewOfFile ((BOOL(WINAPI*)(LPCVOID))aSyscall[57].pCurrent)
{ "WideCharToMultiByte", (SYSCALL)WideCharToMultiByte, 0 },
#define osWideCharToMultiByte ((int(WINAPI*)(UINT,DWORD,LPCWSTR,int,LPSTR,int, \
- LPCSTR,LPBOOL))aSyscall[57].pCurrent)
+ LPCSTR,LPBOOL))aSyscall[58].pCurrent)
{ "WriteFile", (SYSCALL)WriteFile, 0 },
#define osWriteFile ((BOOL(WINAPI*)(HANDLE,LPCVOID,DWORD,LPDWORD, \
- LPOVERLAPPED))aSyscall[58].pCurrent)
+ LPOVERLAPPED))aSyscall[59].pCurrent)
#if SQLITE_OS_WINRT
{ "CreateEventExW", (SYSCALL)CreateEventExW, 0 },
@@ -30581,7 +31513,7 @@ static struct win_syscall {
#endif
#define osCreateEventExW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,LPCWSTR, \
- DWORD,DWORD))aSyscall[59].pCurrent)
+ DWORD,DWORD))aSyscall[60].pCurrent)
#if !SQLITE_OS_WINRT
{ "WaitForSingleObject", (SYSCALL)WaitForSingleObject, 0 },
@@ -30590,7 +31522,7 @@ static struct win_syscall {
#endif
#define osWaitForSingleObject ((DWORD(WINAPI*)(HANDLE, \
- DWORD))aSyscall[60].pCurrent)
+ DWORD))aSyscall[61].pCurrent)
#if SQLITE_OS_WINRT
{ "WaitForSingleObjectEx", (SYSCALL)WaitForSingleObjectEx, 0 },
@@ -30599,7 +31531,7 @@ static struct win_syscall {
#endif
#define osWaitForSingleObjectEx ((DWORD(WINAPI*)(HANDLE,DWORD, \
- BOOL))aSyscall[61].pCurrent)
+ BOOL))aSyscall[62].pCurrent)
#if SQLITE_OS_WINRT
{ "SetFilePointerEx", (SYSCALL)SetFilePointerEx, 0 },
@@ -30608,7 +31540,7 @@ static struct win_syscall {
#endif
#define osSetFilePointerEx ((BOOL(WINAPI*)(HANDLE,LARGE_INTEGER, \
- PLARGE_INTEGER,DWORD))aSyscall[62].pCurrent)
+ PLARGE_INTEGER,DWORD))aSyscall[63].pCurrent)
#if SQLITE_OS_WINRT
{ "GetFileInformationByHandleEx", (SYSCALL)GetFileInformationByHandleEx, 0 },
@@ -30617,7 +31549,7 @@ static struct win_syscall {
#endif
#define osGetFileInformationByHandleEx ((BOOL(WINAPI*)(HANDLE, \
- FILE_INFO_BY_HANDLE_CLASS,LPVOID,DWORD))aSyscall[63].pCurrent)
+ FILE_INFO_BY_HANDLE_CLASS,LPVOID,DWORD))aSyscall[64].pCurrent)
#if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_WAL)
{ "MapViewOfFileFromApp", (SYSCALL)MapViewOfFileFromApp, 0 },
@@ -30626,7 +31558,7 @@ static struct win_syscall {
#endif
#define osMapViewOfFileFromApp ((LPVOID(WINAPI*)(HANDLE,ULONG,ULONG64, \
- SIZE_T))aSyscall[64].pCurrent)
+ SIZE_T))aSyscall[65].pCurrent)
#if SQLITE_OS_WINRT
{ "CreateFile2", (SYSCALL)CreateFile2, 0 },
@@ -30635,16 +31567,16 @@ static struct win_syscall {
#endif
#define osCreateFile2 ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD,DWORD, \
- LPCREATEFILE2_EXTENDED_PARAMETERS))aSyscall[65].pCurrent)
+ LPCREATEFILE2_EXTENDED_PARAMETERS))aSyscall[66].pCurrent)
-#if SQLITE_OS_WINRT
+#if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_LOAD_EXTENSION)
{ "LoadPackagedLibrary", (SYSCALL)LoadPackagedLibrary, 0 },
#else
{ "LoadPackagedLibrary", (SYSCALL)0, 0 },
#endif
#define osLoadPackagedLibrary ((HMODULE(WINAPI*)(LPCWSTR, \
- DWORD))aSyscall[66].pCurrent)
+ DWORD))aSyscall[67].pCurrent)
#if SQLITE_OS_WINRT
{ "GetTickCount64", (SYSCALL)GetTickCount64, 0 },
@@ -30652,7 +31584,7 @@ static struct win_syscall {
{ "GetTickCount64", (SYSCALL)0, 0 },
#endif
-#define osGetTickCount64 ((ULONGLONG(WINAPI*)(VOID))aSyscall[67].pCurrent)
+#define osGetTickCount64 ((ULONGLONG(WINAPI*)(VOID))aSyscall[68].pCurrent)
#if SQLITE_OS_WINRT
{ "GetNativeSystemInfo", (SYSCALL)GetNativeSystemInfo, 0 },
@@ -30661,7 +31593,7 @@ static struct win_syscall {
#endif
#define osGetNativeSystemInfo ((VOID(WINAPI*)( \
- LPSYSTEM_INFO))aSyscall[68].pCurrent)
+ LPSYSTEM_INFO))aSyscall[69].pCurrent)
#if defined(SQLITE_WIN32_HAS_ANSI)
{ "OutputDebugStringA", (SYSCALL)OutputDebugStringA, 0 },
@@ -30669,7 +31601,7 @@ static struct win_syscall {
{ "OutputDebugStringA", (SYSCALL)0, 0 },
#endif
-#define osOutputDebugStringA ((VOID(WINAPI*)(LPCSTR))aSyscall[69].pCurrent)
+#define osOutputDebugStringA ((VOID(WINAPI*)(LPCSTR))aSyscall[70].pCurrent)
#if defined(SQLITE_WIN32_HAS_WIDE)
{ "OutputDebugStringW", (SYSCALL)OutputDebugStringW, 0 },
@@ -30677,11 +31609,11 @@ static struct win_syscall {
{ "OutputDebugStringW", (SYSCALL)0, 0 },
#endif
-#define osOutputDebugStringW ((VOID(WINAPI*)(LPCWSTR))aSyscall[70].pCurrent)
+#define osOutputDebugStringW ((VOID(WINAPI*)(LPCWSTR))aSyscall[71].pCurrent)
{ "GetProcessHeap", (SYSCALL)GetProcessHeap, 0 },
-#define osGetProcessHeap ((HANDLE(WINAPI*)(VOID))aSyscall[71].pCurrent)
+#define osGetProcessHeap ((HANDLE(WINAPI*)(VOID))aSyscall[72].pCurrent)
#if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_WAL)
{ "CreateFileMappingFromApp", (SYSCALL)CreateFileMappingFromApp, 0 },
@@ -30690,7 +31622,7 @@ static struct win_syscall {
#endif
#define osCreateFileMappingFromApp ((HANDLE(WINAPI*)(HANDLE, \
- LPSECURITY_ATTRIBUTES,ULONG,ULONG64,LPCWSTR))aSyscall[72].pCurrent)
+ LPSECURITY_ATTRIBUTES,ULONG,ULONG64,LPCWSTR))aSyscall[73].pCurrent)
}; /* End of the overrideable system calls */
@@ -30782,7 +31714,7 @@ static const char *winNextSystemCall(sqlite3_vfs *p, const char *zName){
** (if available).
*/
-SQLITE_API void sqlite3_win32_write_debug(char *zBuf, int nBuf){
+SQLITE_API void 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. */
@@ -30848,6 +31780,8 @@ SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds){
*/
#if SQLITE_OS_WINCE || SQLITE_OS_WINRT
# define isNT() (1)
+#elif !defined(SQLITE_WIN32_HAS_WIDE)
+# define isNT() (0)
#else
static int isNT(void){
if( sqlite3_os_type==0 ){
@@ -30858,7 +31792,7 @@ SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds){
}
return sqlite3_os_type==2;
}
-#endif /* SQLITE_OS_WINCE */
+#endif
#ifdef SQLITE_WIN32_MALLOC
/*
@@ -31068,7 +32002,7 @@ static LPWSTR utf8ToUnicode(const char *zFilename){
if( nChar==0 ){
return 0;
}
- zWideFilename = sqlite3_malloc( nChar*sizeof(zWideFilename[0]) );
+ zWideFilename = sqlite3MallocZero( nChar*sizeof(zWideFilename[0]) );
if( zWideFilename==0 ){
return 0;
}
@@ -31093,7 +32027,7 @@ static char *unicodeToUtf8(LPCWSTR zWideFilename){
if( nByte == 0 ){
return 0;
}
- zFilename = sqlite3_malloc( nByte );
+ zFilename = sqlite3MallocZero( nByte );
if( zFilename==0 ){
return 0;
}
@@ -31123,7 +32057,7 @@ static LPWSTR mbcsToUnicode(const char *zFilename){
if( nByte==0 ){
return 0;
}
- zMbcsFilename = sqlite3_malloc( nByte*sizeof(zMbcsFilename[0]) );
+ zMbcsFilename = sqlite3MallocZero( nByte*sizeof(zMbcsFilename[0]) );
if( zMbcsFilename==0 ){
return 0;
}
@@ -31152,7 +32086,7 @@ static char *unicodeToMbcs(LPCWSTR zWideFilename){
if( nByte == 0 ){
return 0;
}
- zFilename = sqlite3_malloc( nByte );
+ zFilename = sqlite3MallocZero( nByte );
if( zFilename==0 ){
return 0;
}
@@ -31306,7 +32240,7 @@ static int getLastErrorMsg(DWORD lastErrno, int nBuf, char *zBuf){
}
#endif
if( 0 == dwLen ){
- sqlite3_snprintf(nBuf, zBuf, "OsError 0x%x (%u)", lastErrno, lastErrno);
+ 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);
@@ -31349,7 +32283,7 @@ static int winLogErrorAtLine(
for(i=0; zMsg[i] && zMsg[i]!='\r' && zMsg[i]!='\n'; i++){}
zMsg[i] = 0;
sqlite3_log(errcode,
- "os_win.c:%d: (%d) %s(%s) - %s",
+ "os_win.c:%d: (%lu) %s(%s) - %s",
iLine, lastErrno, zFunc, zPath, zMsg
);
@@ -31413,9 +32347,10 @@ static void logIoerr(int nRetry){
/*************************************************************************
** This section contains code for WinCE only.
*/
+#if !defined(SQLITE_MSVC_LOCALTIME_API) || !SQLITE_MSVC_LOCALTIME_API
/*
-** Windows CE does not have a localtime() function. So create a
-** substitute.
+** 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)
@@ -31439,6 +32374,7 @@ struct tm *__cdecl localtime(const time_t *t)
y.tm_sec = pTm.wSecond;
return &y;
}
+#endif
#define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-(int)offsetof(winFile,h)]
@@ -31460,15 +32396,17 @@ static void winceMutexAcquire(HANDLE h){
** Create the mutex and shared memory used for locking in the file
** descriptor pFile
*/
-static BOOL winceCreateLock(const char *zFilename, winFile *pFile){
+static int winceCreateLock(const char *zFilename, winFile *pFile){
LPWSTR zTok;
LPWSTR zName;
+ DWORD lastErrno;
+ BOOL bLogged = FALSE;
BOOL bInit = TRUE;
zName = utf8ToUnicode(zFilename);
if( zName==0 ){
/* out of memory */
- return FALSE;
+ return SQLITE_IOERR_NOMEM;
}
/* Initialize the local lockdata */
@@ -31485,9 +32423,10 @@ static BOOL winceCreateLock(const char *zFilename, winFile *pFile){
pFile->hMutex = osCreateMutexW(NULL, FALSE, zName);
if (!pFile->hMutex){
pFile->lastErrno = osGetLastError();
- winLogError(SQLITE_ERROR, pFile->lastErrno, "winceCreateLock1", zFilename);
+ winLogError(SQLITE_IOERR, pFile->lastErrno,
+ "winceCreateLock1", zFilename);
sqlite3_free(zName);
- return FALSE;
+ return SQLITE_IOERR;
}
/* Acquire the mutex before continuing */
@@ -31504,41 +32443,49 @@ static BOOL winceCreateLock(const char *zFilename, winFile *pFile){
/* Set a flag that indicates we're the first to create the memory so it
** must be zero-initialized */
- if (osGetLastError() == ERROR_ALREADY_EXISTS){
+ lastErrno = osGetLastError();
+ if (lastErrno == ERROR_ALREADY_EXISTS){
bInit = FALSE;
}
sqlite3_free(zName);
/* If we succeeded in making the shared memory handle, map it. */
- if (pFile->hShared){
+ 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){
+ if( !pFile->shared ){
pFile->lastErrno = osGetLastError();
- winLogError(SQLITE_ERROR, pFile->lastErrno,
- "winceCreateLock2", zFilename);
+ winLogError(SQLITE_IOERR, pFile->lastErrno,
+ "winceCreateLock2", zFilename);
+ bLogged = TRUE;
osCloseHandle(pFile->hShared);
pFile->hShared = NULL;
}
}
/* If shared memory could not be created, then close the mutex and fail */
- if (pFile->hShared == NULL){
+ 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 FALSE;
+ return SQLITE_IOERR;
}
/* Initialize the shared memory if we're supposed to */
- if (bInit) {
+ if( bInit ){
memset(pFile->shared, 0, sizeof(winceLock));
}
winceMutexRelease(pFile->hMutex);
- return TRUE;
+ return SQLITE_OK;
}
/*
@@ -31617,7 +32564,8 @@ static BOOL winceLockFile(
}
/* Want a pending lock? */
- else if (dwFileOffsetLow == (DWORD)PENDING_BYTE && nNumberOfBytesToLockLow == 1){
+ 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;
@@ -31627,7 +32575,8 @@ static BOOL winceLockFile(
}
/* Want a reserved lock? */
- else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE && nNumberOfBytesToLockLow == 1){
+ else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE
+ && nNumberOfBytesToLockLow == 1){
if (pFile->shared->bReserved == 0) {
pFile->shared->bReserved = TRUE;
pFile->local.bReserved = TRUE;
@@ -31670,7 +32619,8 @@ static BOOL winceUnlockFile(
/* Did we just have a reader lock? */
else if (pFile->local.nReaders){
- assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE || nNumberOfBytesToUnlockLow == 1);
+ assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE
+ || nNumberOfBytesToUnlockLow == 1);
pFile->local.nReaders --;
if (pFile->local.nReaders == 0)
{
@@ -31681,7 +32631,8 @@ static BOOL winceUnlockFile(
}
/* Releasing a pending lock */
- else if (dwFileOffsetLow == (DWORD)PENDING_BYTE && nNumberOfBytesToUnlockLow == 1){
+ else if (dwFileOffsetLow == (DWORD)PENDING_BYTE
+ && nNumberOfBytesToUnlockLow == 1){
if (pFile->local.bPending){
pFile->local.bPending = FALSE;
pFile->shared->bPending = FALSE;
@@ -31689,7 +32640,8 @@ static BOOL winceUnlockFile(
}
}
/* Releasing a reserved lock */
- else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE && nNumberOfBytesToUnlockLow == 1){
+ else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE
+ && nNumberOfBytesToUnlockLow == 1){
if (pFile->local.bReserved) {
pFile->local.bReserved = FALSE;
pFile->shared->bReserved = FALSE;
@@ -31792,6 +32744,8 @@ static int seekWinFile(winFile *pFile, sqlite3_int64 iOffset){
DWORD dwRet; /* Value returned by SetFilePointer() */
DWORD lastErrno; /* Value returned by GetLastError() */
+ OSTRACE(("SEEK file=%p, offset=%lld\n", pFile->h, iOffset));
+
upperBits = (LONG)((iOffset>>32) & 0x7fffffff);
lowerBits = (LONG)(iOffset & 0xffffffff);
@@ -31799,7 +32753,7 @@ static int seekWinFile(winFile *pFile, sqlite3_int64 iOffset){
** 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 occured, it is also necessary to call
+ ** whether an error has actually occurred, it is also necessary to call
** GetLastError().
*/
dwRet = osSetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
@@ -31809,9 +32763,11 @@ static int seekWinFile(winFile *pFile, sqlite3_int64 iOffset){
pFile->lastErrno = lastErrno;
winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno,
"seekWinFile", 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
/*
@@ -31828,13 +32784,20 @@ static int seekWinFile(winFile *pFile, sqlite3_int64 iOffset){
pFile->lastErrno = osGetLastError();
winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno,
"seekWinFile", 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 methods */
+static int winUnmapfile(winFile*);
+#endif
+
/*
** Close a file.
**
@@ -31854,7 +32817,14 @@ static int winClose(sqlite3_file *id){
#ifndef SQLITE_OMIT_WAL
assert( pFile->pShm==0 );
#endif
- OSTRACE(("CLOSE %d\n", pFile->h));
+ assert( pFile->h!=NULL && pFile->h!=INVALID_HANDLE_VALUE );
+ OSTRACE(("CLOSE file=%p\n", pFile->h));
+
+#if SQLITE_MAX_MMAP_SIZE>0
+ rc = winUnmapfile(pFile);
+ if( rc!=SQLITE_OK ) return rc;
+#endif
+
do{
rc = osCloseHandle(pFile->h);
/* SimulateIOError( rc=0; cnt=MX_CLOSE_ATTEMPT; ); */
@@ -31874,11 +32844,11 @@ static int winClose(sqlite3_file *id){
sqlite3_free(pFile->zDeleteOnClose);
}
#endif
- OSTRACE(("CLOSE %d %s\n", pFile->h, rc ? "ok" : "failed"));
if( rc ){
pFile->h = NULL;
}
OpenCounter(-1);
+ OSTRACE(("CLOSE file=%p, rc=%s\n", pFile->h, rc ? "ok" : "failed"));
return rc ? SQLITE_OK
: winLogError(SQLITE_IOERR_CLOSE, osGetLastError(),
"winClose", pFile->zPath);
@@ -31903,11 +32873,33 @@ static int winRead(
int nRetry = 0; /* Number of retrys */
assert( id!=0 );
+ assert( amt>0 );
+ assert( offset>=0 );
SimulateIOError(return SQLITE_IOERR_READ);
- OSTRACE(("READ %d lock=%d\n", pFile->h, pFile->locktype));
+ OSTRACE(("READ file=%p, buffer=%p, amount=%d, offset=%lld, lock=%d\n",
+ 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 file=%p, rc=SQLITE_OK\n", 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
if( seekWinFile(pFile, offset) ){
+ OSTRACE(("READ file=%p, rc=SQLITE_FULL\n", pFile->h));
return SQLITE_FULL;
}
while( !osReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
@@ -31921,6 +32913,7 @@ static int winRead(
DWORD lastErrno;
if( retryIoerr(&nRetry, &lastErrno) ) continue;
pFile->lastErrno = lastErrno;
+ OSTRACE(("READ file=%p, rc=SQLITE_IOERR_READ\n", pFile->h));
return winLogError(SQLITE_IOERR_READ, pFile->lastErrno,
"winRead", pFile->zPath);
}
@@ -31928,9 +32921,11 @@ static int winRead(
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));
return SQLITE_IOERR_SHORT_READ;
}
+ OSTRACE(("READ file=%p, rc=SQLITE_OK\n", pFile->h));
return SQLITE_OK;
}
@@ -31944,7 +32939,7 @@ static int winWrite(
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 occured, else false */
+ int rc = 0; /* True if error has occurred, else false */
winFile *pFile = (winFile*)id; /* File handle */
int nRetry = 0; /* Number of retries */
@@ -31953,7 +32948,26 @@ static int winWrite(
SimulateIOError(return SQLITE_IOERR_WRITE);
SimulateDiskfullError(return SQLITE_FULL);
- OSTRACE(("WRITE %d lock=%d\n", pFile->h, pFile->locktype));
+ OSTRACE(("WRITE file=%p, buffer=%p, amount=%d, offset=%lld, lock=%d\n",
+ pFile->h, pBuf, amt, offset, pFile->locktype));
+
+#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 file=%p, rc=SQLITE_OK\n", 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
#if SQLITE_OS_WINCE
rc = seekWinFile(pFile, offset);
@@ -31984,7 +32998,8 @@ static int winWrite(
if( retryIoerr(&nRetry, &lastErrno) ) continue;
break;
}
- if( nWrite<=0 ){
+ assert( nWrite==0 || nWrite<=(DWORD)nRem );
+ if( nWrite==0 || nWrite>(DWORD)nRem ){
lastErrno = osGetLastError();
break;
}
@@ -32005,13 +33020,16 @@ 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));
return SQLITE_FULL;
}
+ OSTRACE(("WRITE file=%p, rc=SQLITE_IOERR_WRITE\n", pFile->h));
return winLogError(SQLITE_IOERR_WRITE, pFile->lastErrno,
"winWrite", pFile->zPath);
}else{
logIoerr(nRetry);
}
+ OSTRACE(("WRITE file=%p, rc=SQLITE_OK\n", pFile->h));
return SQLITE_OK;
}
@@ -32021,11 +33039,12 @@ static int winWrite(
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 );
-
- OSTRACE(("TRUNCATE %d %lld\n", pFile->h, nByte));
SimulateIOError(return SQLITE_IOERR_TRUNCATE);
+ OSTRACE(("TRUNCATE file=%p, size=%lld, lock=%d\n",
+ 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
@@ -32039,14 +33058,25 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
/* SetEndOfFile() returns non-zero when successful, or zero when it fails. */
if( seekWinFile(pFile, nByte) ){
rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno,
- "winTruncate1", pFile->zPath);
- }else if( 0==osSetEndOfFile(pFile->h) ){
- pFile->lastErrno = osGetLastError();
+ "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);
+ "winTruncate2", pFile->zPath);
+ }
+
+#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;
}
+#endif
- OSTRACE(("TRUNCATE %d %lld %s\n", pFile->h, nByte, rc ? "failed" : "ok"));
+ OSTRACE(("TRUNCATE file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc)));
return rc;
}
@@ -32086,13 +33116,14 @@ static int winSync(sqlite3_file *id, int flags){
|| (flags&0x0F)==SQLITE_SYNC_FULL
);
- OSTRACE(("SYNC %d lock=%d\n", pFile->h, pFile->locktype));
-
/* 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 file=%p, flags=%x, lock=%d\n",
+ pFile->h, flags, pFile->locktype));
+
#ifndef SQLITE_TEST
UNUSED_PARAMETER(flags);
#else
@@ -32111,9 +33142,11 @@ static int winSync(sqlite3_file *id, int flags){
rc = osFlushFileBuffers(pFile->h);
SimulateIOError( rc=FALSE );
if( rc ){
+ OSTRACE(("SYNC file=%p, rc=SQLITE_OK\n", pFile->h));
return SQLITE_OK;
}else{
pFile->lastErrno = osGetLastError();
+ OSTRACE(("SYNC file=%p, rc=SQLITE_IOERR_FSYNC\n", pFile->h));
return winLogError(SQLITE_IOERR_FSYNC, pFile->lastErrno,
"winSync", pFile->zPath);
}
@@ -32128,7 +33161,10 @@ static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){
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));
+
#if SQLITE_OS_WINRT
{
FILE_STANDARD_INFO info;
@@ -32157,6 +33193,8 @@ static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){
}
}
#endif
+ OSTRACE(("SIZE file=%p, pSize=%p, *pSize=%lld, rc=%s\n",
+ pFile->h, pSize, *pSize, sqlite3ErrName(rc)));
return rc;
}
@@ -32198,6 +33236,7 @@ static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){
*/
static int getReadLock(winFile *pFile){
int res;
+ OSTRACE(("READ-LOCK file=%p, lock=%d\n", pFile->h, pFile->locktype));
if( isNT() ){
#if SQLITE_OS_WINCE
/*
@@ -32223,6 +33262,7 @@ static int getReadLock(winFile *pFile){
pFile->lastErrno = osGetLastError();
/* No need to log a failure to lock */
}
+ OSTRACE(("READ-LOCK file=%p, rc=%s\n", pFile->h, sqlite3ErrName(res)));
return res;
}
@@ -32232,6 +33272,7 @@ static int getReadLock(winFile *pFile){
static int unlockReadLock(winFile *pFile){
int res;
DWORD lastErrno;
+ OSTRACE(("READ-UNLOCK file=%p, lock=%d\n", pFile->h, pFile->locktype));
if( isNT() ){
res = winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
}
@@ -32245,6 +33286,7 @@ static int unlockReadLock(winFile *pFile){
winLogError(SQLITE_IOERR_UNLOCK, pFile->lastErrno,
"unlockReadLock", pFile->zPath);
}
+ OSTRACE(("READ-UNLOCK file=%p, rc=%s\n", pFile->h, sqlite3ErrName(res)));
return res;
}
@@ -32283,14 +33325,15 @@ static int winLock(sqlite3_file *id, int locktype){
DWORD lastErrno = NO_ERROR;
assert( id!=0 );
- OSTRACE(("LOCK %d %d was %d(%d)\n",
- pFile->h, locktype, pFile->locktype, pFile->sharedLockByte));
+ OSTRACE(("LOCK file=%p, oldLock=%d(%d), newLock=%d\n",
+ pFile->h, pFile->locktype, pFile->sharedLockByte, locktype));
/* 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;
}
@@ -32318,7 +33361,8 @@ static int winLock(sqlite3_file *id, int locktype){
** 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.
*/
- OSTRACE(("could not get a PENDING lock. cnt=%d\n", cnt));
+ OSTRACE(("LOCK-PENDING-FAIL file=%p, count=%d, rc=%s\n",
+ pFile->h, cnt, sqlite3ErrName(res)));
if( cnt ) sqlite3_win32_sleep(1);
}
gotPendingLock = res;
@@ -32363,14 +33407,12 @@ static int winLock(sqlite3_file *id, int locktype){
if( locktype==EXCLUSIVE_LOCK && res ){
assert( pFile->locktype>=SHARED_LOCK );
res = unlockReadLock(pFile);
- OSTRACE(("unreadlock = %d\n", res));
res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, SHARED_FIRST, 0,
SHARED_SIZE, 0);
if( res ){
newLocktype = EXCLUSIVE_LOCK;
}else{
lastErrno = osGetLastError();
- OSTRACE(("error-code = %d\n", lastErrno));
getReadLock(pFile);
}
}
@@ -32388,12 +33430,14 @@ static int winLock(sqlite3_file *id, int locktype){
if( res ){
rc = SQLITE_OK;
}else{
- OSTRACE(("LOCK FAILED %d trying for %d but got %d\n", pFile->h,
- locktype, newLocktype));
+ OSTRACE(("LOCK-FAIL file=%p, wanted=%d, got=%d\n",
+ pFile->h, locktype, newLocktype));
pFile->lastErrno = lastErrno;
rc = SQLITE_BUSY;
}
pFile->locktype = (u8)newLocktype;
+ OSTRACE(("LOCK file=%p, lock=%d, rc=%s\n",
+ pFile->h, pFile->locktype, sqlite3ErrName(rc)));
return rc;
}
@@ -32407,20 +33451,23 @@ static int winCheckReservedLock(sqlite3_file *id, int *pResOut){
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 ){
rc = 1;
- OSTRACE(("TEST WR-LOCK %d %d (local)\n", pFile->h, rc));
+ OSTRACE(("TEST-WR-LOCK file=%p, rc=%d (local)\n", pFile->h, rc));
}else{
- rc = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, RESERVED_BYTE, 0, 1, 0);
+ rc = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS,RESERVED_BYTE, 0, 1, 0);
if( rc ){
winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0);
}
rc = !rc;
- OSTRACE(("TEST WR-LOCK %d %d (remote)\n", pFile->h, rc));
+ OSTRACE(("TEST-WR-LOCK file=%p, rc=%d (remote)\n", pFile->h, rc));
}
*pResOut = rc;
+ OSTRACE(("TEST-WR-LOCK file=%p, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n",
+ pFile->h, pResOut, *pResOut));
return SQLITE_OK;
}
@@ -32441,8 +33488,8 @@ static int winUnlock(sqlite3_file *id, int locktype){
int rc = SQLITE_OK;
assert( pFile!=0 );
assert( locktype<=SHARED_LOCK );
- OSTRACE(("UNLOCK %d to %d was %d(%d)\n", pFile->h, locktype,
- pFile->locktype, pFile->sharedLockByte));
+ 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);
@@ -32463,6 +33510,8 @@ static int winUnlock(sqlite3_file *id, int locktype){
winUnlockFile(&pFile->h, PENDING_BYTE, 0, 1, 0);
}
pFile->locktype = (u8)locktype;
+ OSTRACE(("UNLOCK file=%p, lock=%d, rc=%s\n",
+ pFile->h, pFile->locktype, sqlite3ErrName(rc)));
return rc;
}
@@ -32482,22 +33531,29 @@ static void winModeBit(winFile *pFile, unsigned char mask, int *pArg){
}
}
+/* Forward declaration */
+static int getTempname(int nBuf, char *zBuf);
+
/*
** 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: {
@@ -32512,20 +33568,25 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
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("win32");
+ OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
return SQLITE_OK;
}
case SQLITE_FCNTL_WIN32_AV_RETRY: {
@@ -32540,9 +33601,32 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
}else{
a[1] = win32IoerrRetryDelay;
}
+ OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
+ return SQLITE_OK;
+ }
+ case SQLITE_FCNTL_TEMPFILENAME: {
+ char *zTFile = sqlite3MallocZero( pFile->pVfs->mxPathname );
+ if( zTFile ){
+ getTempname(pFile->pVfs->mxPathname, zTFile);
+ *(char**)pArg = zTFile;
+ }
+ OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
return SQLITE_OK;
}
+#if SQLITE_MAX_MMAP_SIZE>0
+ case SQLITE_FCNTL_MMAP_SIZE: {
+ i64 newLimit = *(i64*)pArg;
+ if( newLimit>sqlite3GlobalConfig.mxMmap ){
+ newLimit = sqlite3GlobalConfig.mxMmap;
+ }
+ *(i64*)pArg = pFile->mmapSizeMax;
+ if( newLimit>=0 ) pFile->mmapSizeMax = newLimit;
+ OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
+ return SQLITE_OK;
+ }
+#endif
}
+ OSTRACE(("FCNTL file=%p, rc=SQLITE_NOTFOUND\n", pFile->h));
return SQLITE_NOTFOUND;
}
@@ -32570,8 +33654,6 @@ static int winDeviceCharacteristics(sqlite3_file *id){
((p->ctrlFlags & WINFILE_PSOW)?SQLITE_IOCAP_POWERSAFE_OVERWRITE:0);
}
-#ifndef SQLITE_OMIT_WAL
-
/*
** Windows will only let you create file view mappings
** on allocation size granularity boundaries.
@@ -32580,6 +33662,8 @@ static int winDeviceCharacteristics(sqlite3_file *id){
*/
SYSTEM_INFO winSysInfo;
+#ifndef SQLITE_OMIT_WAL
+
/*
** Helper functions to obtain and relinquish the global mutex. The
** global mutex is used to protect the winLockInfo objects used by
@@ -32703,6 +33787,9 @@ static int winShmSystemLock(
/* Access to the winShmNode object is serialized by the caller */
assert( sqlite3_mutex_held(pFile->mutex) || pFile->nRef==0 );
+ OSTRACE(("SHM-LOCK file=%p, lock=%d, offset=%d, size=%d\n",
+ pFile->hFile.h, lockType, ofst, nByte));
+
/* Release/Acquire the system-level lock */
if( lockType==_SHM_UNLCK ){
rc = winUnlockFile(&pFile->hFile.h, ofst, 0, nByte, 0);
@@ -32720,11 +33807,9 @@ static int winShmSystemLock(
rc = SQLITE_BUSY;
}
- OSTRACE(("SHM-LOCK %d %s %s 0x%08lx\n",
- pFile->hFile.h,
- rc==SQLITE_OK ? "ok" : "failed",
- lockType==_SHM_UNLCK ? "UnlockFileEx" : "LockFileEx",
- pFile->lastErrno));
+ 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;
}
@@ -32744,6 +33829,8 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
winShmNode *p;
BOOL bRc;
assert( winShmMutexHeld() );
+ OSTRACE(("SHM-PURGE pid=%lu, deleteFlag=%d\n",
+ osGetCurrentProcessId(), deleteFlag));
pp = &winShmNodeList;
while( (p = *pp)!=0 ){
if( p->nRef==0 ){
@@ -32751,15 +33838,13 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
if( p->mutex ) sqlite3_mutex_free(p->mutex);
for(i=0; i<p->nRegion; i++){
bRc = osUnmapViewOfFile(p->aRegion[i].pMap);
- OSTRACE(("SHM-PURGE pid-%d unmap region=%d %s\n",
- (int)osGetCurrentProcessId(), i,
- bRc ? "ok" : "failed"));
+ OSTRACE(("SHM-PURGE-UNMAP pid=%lu, region=%d, rc=%s\n",
+ osGetCurrentProcessId(), i, bRc ? "ok" : "failed"));
bRc = osCloseHandle(p->aRegion[i].hMap);
- OSTRACE(("SHM-PURGE pid-%d close region=%d %s\n",
- (int)osGetCurrentProcessId(), i,
- bRc ? "ok" : "failed"));
+ OSTRACE(("SHM-PURGE-CLOSE pid=%lu, region=%d, rc=%s\n",
+ osGetCurrentProcessId(), i, bRc ? "ok" : "failed"));
}
- if( p->hFile.h != INVALID_HANDLE_VALUE ){
+ if( p->hFile.h!=NULL && p->hFile.h!=INVALID_HANDLE_VALUE ){
SimulateIOErrorBenign(1);
winClose((sqlite3_file *)&p->hFile);
SimulateIOErrorBenign(0);
@@ -32799,16 +33884,14 @@ static int winOpenSharedMemory(winFile *pDbFd){
/* Allocate space for the new sqlite3_shm object. Also speculatively
** allocate space for a new winShmNode and filename.
*/
- p = sqlite3_malloc( sizeof(*p) );
+ p = sqlite3MallocZero( sizeof(*p) );
if( p==0 ) return SQLITE_IOERR_NOMEM;
- memset(p, 0, sizeof(*p));
nName = sqlite3Strlen30(pDbFd->zPath);
- pNew = sqlite3_malloc( sizeof(*pShmNode) + nName + 17 );
+ pNew = sqlite3MallocZero( sizeof(*pShmNode) + nName + 17 );
if( pNew==0 ){
sqlite3_free(p);
return SQLITE_IOERR_NOMEM;
}
- memset(pNew, 0, sizeof(*pNew) + nName + 17);
pNew->zFilename = (char*)&pNew[1];
sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath);
sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename);
@@ -32841,7 +33924,7 @@ static int winOpenSharedMemory(winFile *pDbFd){
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, /* Mode flags */
+ SQLITE_OPEN_WAL | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
0);
if( SQLITE_OK!=rc ){
goto shm_open_err;
@@ -33038,9 +34121,9 @@ static int winShmLock(
}
}
sqlite3_mutex_leave(pShmNode->mutex);
- OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x %s\n",
- p->id, (int)osGetCurrentProcessId(), p->sharedMask, p->exclMask,
- rc ? "failed" : "ok"));
+ 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;
}
@@ -33145,20 +34228,24 @@ static int winShmMap(
pShmNode->aRegion = apNew;
while( pShmNode->nRegion<=iRegion ){
- HANDLE hMap; /* file-mapping handle */
+ 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
);
-#else
+#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 pid-%d create region=%d nbyte=%d %s\n",
- (int)osGetCurrentProcessId(), pShmNode->nRegion, nByte,
+ 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;
@@ -33172,8 +34259,8 @@ static int winShmMap(
0, iOffset - iOffsetShift, szRegion + iOffsetShift
);
#endif
- OSTRACE(("SHM-MAP pid-%d map region=%d offset=%d size=%d %s\n",
- (int)osGetCurrentProcessId(), pShmNode->nRegion, iOffset,
+ 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 ){
@@ -33211,6 +34298,230 @@ shmpage_out:
#endif /* #ifndef SQLITE_OMIT_WAL */
/*
+** Cleans up the mapped region of the specified file, if any.
+*/
+#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,
+ "winUnmap1", 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,
+ "winUnmap2", pFile->zPath);
+ }
+ pFile->hMap = NULL;
+ }
+ OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, rc=SQLITE_OK\n",
+ osGetCurrentProcessId(), pFile));
+ 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.
+**
+** 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 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;
+ }
+ }
+ if( nMap>pFd->mmapSizeMax ){
+ nMap = pFd->mmapSizeMax;
+ }
+ nMap &= ~(sqlite3_int64)(winSysInfo.dwPageSize - 1);
+
+ 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,
+ "winMapfile", pFd->zPath);
+ /* Log the error, but continue normal operation using xRead/xWrite */
+ OSTRACE(("MAP-FILE-CREATE pid=%lu, pFile=%p, rc=SQLITE_IOERR_MMAP\n",
+ osGetCurrentProcessId(), pFd));
+ return SQLITE_OK;
+ }
+ assert( (nMap % winSysInfo.dwPageSize)==0 );
+#if SQLITE_OS_WINRT
+ pNew = osMapViewOfFileFromApp(pFd->hMap, flags, 0, nMap);
+#else
+ assert( sizeof(SIZE_T)==sizeof(sqlite3_int64) || nMap<=0xffffffff );
+ pNew = osMapViewOfFile(pFd->hMap, flags, 0, 0, (SIZE_T)nMap);
+#endif
+ if( pNew==NULL ){
+ osCloseHandle(pFd->hMap);
+ pFd->hMap = NULL;
+ pFd->lastErrno = osGetLastError();
+ winLogError(SQLITE_IOERR_MMAP, pFd->lastErrno,
+ "winMapfile", pFd->zPath);
+ OSTRACE(("MAP-FILE-MAP pid=%lu, pFile=%p, rc=SQLITE_IOERR_MMAP\n",
+ osGetCurrentProcessId(), pFd));
+ return SQLITE_OK;
+ }
+ pFd->pMapRegion = pNew;
+ pFd->mmapSize = nMap;
+ pFd->mmapSizeActual = nMap;
+ }
+
+ OSTRACE(("MAP-FILE pid=%lu, pFile=%p, rc=SQLITE_OK\n",
+ osGetCurrentProcessId(), pFd));
+ return SQLITE_OK;
+}
+#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 this function does return a pointer, the caller must eventually
+** release the reference by calling winUnfetch().
+*/
+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;
+
+ 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;
+ }
+ }
+ if( pFd->mmapSize >= iOff+nAmt ){
+ *pp = &((u8 *)pFd->pMapRegion)[iOff];
+ pFd->nFetchOut++;
+ }
+ }
+#endif
+
+ 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{
+ /* 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
+ ** performance. */
+ winUnmapfile(pFd);
+ }
+
+ assert( pFd->nFetchOut>=0 );
+#endif
+
+ OSTRACE(("UNFETCH pid=%lu, pFile=%p, rc=SQLITE_OK\n",
+ osGetCurrentProcessId(), fd));
+ return SQLITE_OK;
+}
+
+/*
** Here ends the implementation of all sqlite3_file methods.
**
********************** End sqlite3_file Methods *******************************
@@ -33221,7 +34532,7 @@ shmpage_out:
** sqlite3_file for win32.
*/
static const sqlite3_io_methods winIoMethod = {
- 2, /* iVersion */
+ 3, /* iVersion */
winClose, /* xClose */
winRead, /* xRead */
winWrite, /* xWrite */
@@ -33237,7 +34548,9 @@ static const sqlite3_io_methods winIoMethod = {
winShmMap, /* xShmMap */
winShmLock, /* xShmLock */
winShmBarrier, /* xShmBarrier */
- winShmUnmap /* xShmUnmap */
+ winShmUnmap, /* xShmUnmap */
+ winFetch, /* xFetch */
+ winUnfetch /* xUnfetch */
};
/****************************************************************************
@@ -33301,6 +34614,7 @@ static int getTempname(int nBuf, char *zBuf){
sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zMulti);
sqlite3_free(zMulti);
}else{
+ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
return SQLITE_IOERR_NOMEM;
}
}
@@ -33314,6 +34628,7 @@ static int getTempname(int nBuf, char *zBuf){
sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zUtf8);
sqlite3_free(zUtf8);
}else{
+ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
return SQLITE_IOERR_NOMEM;
}
}
@@ -33326,6 +34641,7 @@ static int getTempname(int nBuf, char *zBuf){
nTempPath = sqlite3Strlen30(zTempPath);
if( (nTempPath + sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX) + 18) >= nBuf ){
+ OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n"));
return SQLITE_ERROR;
}
@@ -33343,8 +34659,8 @@ static int getTempname(int nBuf, char *zBuf){
zBuf[j] = 0;
zBuf[j+1] = 0;
- OSTRACE(("TEMP FILENAME: %s\n", zBuf));
- return SQLITE_OK;
+ OSTRACE(("TEMP-FILENAME name=%s, rc=SQLITE_OK\n", zBuf));
+ return SQLITE_OK;
}
/*
@@ -33413,9 +34729,7 @@ static int winOpen(
int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE);
int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE);
int isCreate = (flags & SQLITE_OPEN_CREATE);
-#ifndef NDEBUG
int isReadonly = (flags & SQLITE_OPEN_READONLY);
-#endif
int isReadWrite = (flags & SQLITE_OPEN_READWRITE);
#ifndef NDEBUG
@@ -33426,6 +34740,9 @@ static int winOpen(
));
#endif
+ 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
@@ -33452,8 +34769,9 @@ static int winOpen(
|| eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
);
- assert( id!=0 );
- UNUSED_PARAMETER(pVfs);
+ assert( pFile!=0 );
+ memset(pFile, 0, sizeof(winFile));
+ pFile->h = INVALID_HANDLE_VALUE;
#if SQLITE_OS_WINRT
if( !sqlite3_temp_directory ){
@@ -33462,15 +34780,15 @@ static int winOpen(
}
#endif
- pFile->h = INVALID_HANDLE_VALUE;
-
/* If the second argument to this function is NULL, generate a
** temporary file name to use
*/
if( !zUtf8Name ){
assert(isDelete && !isOpenJournal);
+ memset(zTmpname, 0, MAX_PATH+2);
rc = getTempname(MAX_PATH+2, zTmpname);
if( rc!=SQLITE_OK ){
+ OSTRACE(("OPEN name=%s, rc=%s", zUtf8Name, sqlite3ErrName(rc)));
return rc;
}
zUtf8Name = zTmpname;
@@ -33486,11 +34804,13 @@ static int winOpen(
/* Convert the filename to the system encoding. */
zConverted = convertUtf8Filename(zUtf8Name);
if( zConverted==0 ){
+ OSTRACE(("OPEN name=%s, rc=SQLITE_IOERR_NOMEM", zUtf8Name));
return SQLITE_IOERR_NOMEM;
}
if( winIsDir(zConverted) ){
sqlite3_free(zConverted);
+ OSTRACE(("OPEN name=%s, rc=SQLITE_CANTOPEN_ISDIR", zUtf8Name));
return SQLITE_CANTOPEN_ISDIR;
}
@@ -33581,9 +34901,8 @@ static int winOpen(
#endif
logIoerr(cnt);
- OSTRACE(("OPEN %d %s 0x%lx %s\n",
- h, zName, dwDesiredAccess,
- h==INVALID_HANDLE_VALUE ? "failed" : "ok"));
+ 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;
@@ -33591,7 +34910,9 @@ static int winOpen(
sqlite3_free(zConverted);
if( isReadWrite && !isExclusive ){
return winOpen(pVfs, zName, id,
- ((flags|SQLITE_OPEN_READONLY)&~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)), pOutFlags);
+ ((flags|SQLITE_OPEN_READONLY) &
+ ~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)),
+ pOutFlags);
}else{
return SQLITE_CANTOPEN_BKPT;
}
@@ -33605,26 +34926,18 @@ static int winOpen(
}
}
- memset(pFile, 0, sizeof(*pFile));
- pFile->pMethod = &winIoMethod;
- pFile->h = h;
- pFile->lastErrno = NO_ERROR;
- pFile->pVfs = pVfs;
-#ifndef SQLITE_OMIT_WAL
- pFile->pShm = 0;
-#endif
- pFile->zPath = zName;
- if( sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE) ){
- pFile->ctrlFlags |= WINFILE_PSOW;
- }
+ 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
- && !winceCreateLock(zName, pFile)
+ && (rc = winceCreateLock(zName, pFile))!=SQLITE_OK
){
osCloseHandle(h);
sqlite3_free(zConverted);
- return SQLITE_CANTOPEN_BKPT;
+ OSTRACE(("OPEN-CE-LOCK name=%s, rc=%s\n", zName, sqlite3ErrName(rc)));
+ return rc;
}
if( isTemp ){
pFile->zDeleteOnClose = zConverted;
@@ -33634,6 +34947,25 @@ static int winOpen(
sqlite3_free(zConverted);
}
+ 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
+
OpenCounter(+1);
return rc;
}
@@ -33664,6 +34996,8 @@ static int winDelete(
UNUSED_PARAMETER(syncDir);
SimulateIOError(return SQLITE_IOERR_DELETE);
+ OSTRACE(("DELETE name=%s, syncDir=%d\n", zFilename, syncDir));
+
zConverted = convertUtf8Filename(zFilename);
if( zConverted==0 ){
return SQLITE_IOERR_NOMEM;
@@ -33677,14 +35011,26 @@ static int winDelete(
&sAttrData) ){
attr = sAttrData.dwFileAttributes;
}else{
- rc = SQLITE_OK; /* Already gone? */
+ 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;
}
#else
attr = osGetFileAttributesW(zConverted);
#endif
if ( attr==INVALID_FILE_ATTRIBUTES ){
- rc = SQLITE_OK; /* Already gone? */
+ 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 ){
@@ -33706,7 +35052,13 @@ static int winDelete(
do {
attr = osGetFileAttributesA(zConverted);
if ( attr==INVALID_FILE_ATTRIBUTES ){
- rc = SQLITE_OK; /* Already gone? */
+ 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 ){
@@ -33724,19 +35076,19 @@ static int winDelete(
} while(1);
}
#endif
- if( rc ){
+ if( rc && rc!=SQLITE_IOERR_DELETE_NOENT ){
rc = winLogError(SQLITE_IOERR_DELETE, lastErrno,
"winDelete", zFilename);
}else{
logIoerr(cnt);
}
sqlite3_free(zConverted);
- OSTRACE(("DELETE \"%s\" %s\n", zFilename, (rc ? "failed" : "ok" )));
+ OSTRACE(("DELETE name=%s, rc=%s\n", zFilename, sqlite3ErrName(rc)));
return rc;
}
/*
-** Check the existance and status of a file.
+** Check the existence and status of a file.
*/
static int winAccess(
sqlite3_vfs *pVfs, /* Not used on win32 */
@@ -33751,8 +35103,12 @@ static int winAccess(
UNUSED_PARAMETER(pVfs);
SimulateIOError( return SQLITE_IOERR_ACCESS; );
+ OSTRACE(("ACCESS name=%s, flags=%x, pResOut=%p\n",
+ zFilename, flags, pResOut));
+
zConverted = convertUtf8Filename(zFilename);
if( zConverted==0 ){
+ OSTRACE(("ACCESS name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename));
return SQLITE_IOERR_NOMEM;
}
if( isNT() ){
@@ -33803,6 +35159,8 @@ static int winAccess(
assert(!"Invalid flags argument");
}
*pResOut = rc;
+ OSTRACE(("ACCESS name=%s, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n",
+ zFilename, pResOut, *pResOut));
return SQLITE_OK;
}
@@ -33870,16 +35228,12 @@ static int winFullPathname(
*/
char zOut[MAX_PATH+1];
memset(zOut, 0, MAX_PATH+1);
- cygwin_conv_to_win32_path(zRelative, zOut); /* POSIX to Win32 */
+ cygwin_conv_path(CCP_POSIX_TO_WIN_A|CCP_RELATIVE, zRelative, zOut,
+ MAX_PATH+1);
sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s\\%s",
sqlite3_data_directory, zOut);
}else{
- /*
- ** NOTE: The Cygwin docs state that the maximum length needed
- ** for the buffer passed to cygwin_conv_to_full_win32_path
- ** is MAX_PATH.
- */
- cygwin_conv_to_full_win32_path(zRelative, zFull);
+ cygwin_conv_path(CCP_POSIX_TO_WIN_A, zRelative, zFull, nFull);
}
return SQLITE_OK;
#endif
@@ -33904,7 +35258,7 @@ static int winFullPathname(
#endif
#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__)
- int nByte;
+ DWORD nByte;
void *zConverted;
char *zOut;
@@ -33938,13 +35292,27 @@ static int winFullPathname(
}
if( isNT() ){
LPWSTR zTemp;
- nByte = osGetFullPathNameW((LPCWSTR)zConverted, 0, 0, 0) + 3;
- zTemp = sqlite3_malloc( nByte*sizeof(zTemp[0]) );
+ nByte = osGetFullPathNameW((LPCWSTR)zConverted, 0, 0, 0);
+ if( nByte==0 ){
+ winLogError(SQLITE_ERROR, osGetLastError(),
+ "GetFullPathNameW1", zConverted);
+ sqlite3_free(zConverted);
+ return SQLITE_CANTOPEN_FULLPATH;
+ }
+ nByte += 3;
+ zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) );
if( zTemp==0 ){
sqlite3_free(zConverted);
return SQLITE_IOERR_NOMEM;
}
- osGetFullPathNameW((LPCWSTR)zConverted, nByte, zTemp, 0);
+ nByte = osGetFullPathNameW((LPCWSTR)zConverted, nByte, zTemp, 0);
+ if( nByte==0 ){
+ winLogError(SQLITE_ERROR, osGetLastError(),
+ "GetFullPathNameW2", zConverted);
+ sqlite3_free(zConverted);
+ sqlite3_free(zTemp);
+ return SQLITE_CANTOPEN_FULLPATH;
+ }
sqlite3_free(zConverted);
zOut = unicodeToUtf8(zTemp);
sqlite3_free(zTemp);
@@ -33952,13 +35320,27 @@ static int winFullPathname(
#ifdef SQLITE_WIN32_HAS_ANSI
else{
char *zTemp;
- nByte = osGetFullPathNameA((char*)zConverted, 0, 0, 0) + 3;
- zTemp = sqlite3_malloc( nByte*sizeof(zTemp[0]) );
+ nByte = osGetFullPathNameA((char*)zConverted, 0, 0, 0);
+ if( nByte==0 ){
+ winLogError(SQLITE_ERROR, osGetLastError(),
+ "GetFullPathNameA1", zConverted);
+ sqlite3_free(zConverted);
+ return SQLITE_CANTOPEN_FULLPATH;
+ }
+ nByte += 3;
+ zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) );
if( zTemp==0 ){
sqlite3_free(zConverted);
return SQLITE_IOERR_NOMEM;
}
- osGetFullPathNameA((char*)zConverted, nByte, zTemp, 0);
+ nByte = osGetFullPathNameA((char*)zConverted, nByte, zTemp, 0);
+ if( nByte==0 ){
+ winLogError(SQLITE_ERROR, osGetLastError(),
+ "GetFullPathNameA2", zConverted);
+ sqlite3_free(zConverted);
+ sqlite3_free(zTemp);
+ return SQLITE_CANTOPEN_FULLPATH;
+ }
sqlite3_free(zConverted);
zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
sqlite3_free(zTemp);
@@ -34009,9 +35391,9 @@ static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
UNUSED_PARAMETER(pVfs);
getLastErrorMsg(osGetLastError(), nBuf, zBufOut);
}
-static void (*winDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol))(void){
+static void (*winDlSym(sqlite3_vfs *pVfs,void *pH,const char *zSym))(void){
UNUSED_PARAMETER(pVfs);
- return (void(*)(void))osGetProcAddressA((HANDLE)pHandle, zSymbol);
+ return (void(*)(void))osGetProcAddressA((HANDLE)pH, zSym);
}
static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){
UNUSED_PARAMETER(pVfs);
@@ -34109,7 +35491,8 @@ static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){
#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;
+ (sqlite3_int64)2000000000 + (sqlite3_int64)2000000000 +
+ (sqlite3_int64)294967296;
#if SQLITE_OS_WINCE
SYSTEMTIME time;
@@ -34216,9 +35599,8 @@ SQLITE_API int sqlite3_os_init(void){
/* Double-check that the aSyscall[] array has been constructed
** correctly. See ticket [bb3a86e890c8e96ab] */
- assert( ArraySize(aSyscall)==73 );
+ assert( ArraySize(aSyscall)==74 );
-#ifndef SQLITE_OMIT_WAL
/* get memory map allocation granularity */
memset(&winSysInfo, 0, sizeof(SYSTEM_INFO));
#if SQLITE_OS_WINRT
@@ -34226,8 +35608,8 @@ SQLITE_API int sqlite3_os_init(void){
#else
osGetSystemInfo(&winSysInfo);
#endif
- assert(winSysInfo.dwAllocationGranularity > 0);
-#endif
+ assert( winSysInfo.dwAllocationGranularity>0 );
+ assert( winSysInfo.dwPageSize>0 );
sqlite3_vfs_register(&winVfs, 1);
return SQLITE_OK;
@@ -34235,7 +35617,7 @@ SQLITE_API int sqlite3_os_init(void){
SQLITE_API int sqlite3_os_end(void){
#if SQLITE_OS_WINRT
- if( sleepObj != NULL ){
+ if( sleepObj!=NULL ){
osCloseHandle(sleepObj);
sleepObj = NULL;
}
@@ -34320,7 +35702,7 @@ SQLITE_API int sqlite3_os_end(void){
/*
** A bitmap is an instance of the following structure.
**
-** This bitmap records the existance of zero or more bits
+** 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.
@@ -36864,7 +38246,6 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, u8 iBatch, sqlite3_int64 i
# define sqlite3WalClose(w,x,y,z) 0
# define sqlite3WalBeginReadTransaction(y,z) 0
# define sqlite3WalEndReadTransaction(z)
-# define sqlite3WalRead(v,w,x,y,z) 0
# define sqlite3WalDbsize(y) 0
# define sqlite3WalBeginWriteTransaction(y) 0
# define sqlite3WalEndWriteTransaction(x) 0
@@ -36877,6 +38258,7 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, u8 iBatch, sqlite3_int64 i
# 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
@@ -36904,7 +38286,8 @@ 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 sqlite3WalRead(Wal *pWal, Pgno pgno, int *pInWal, int nOut, u8 *pOut);
+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);
@@ -37222,7 +38605,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
** * 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 occured, all that remains is to finalize the journal to
+** 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.
**
@@ -37470,7 +38853,7 @@ struct PagerSavepoint {
**
** doNotSpill, doNotSyncSpill
**
-** These two boolean variables control the behaviour of cache-spills
+** These two boolean 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).
**
@@ -37604,6 +38987,11 @@ struct Pager {
PagerSavepoint *aSavepoint; /* Array of active savepoints */
int nSavepoint; /* Number of elements in aSavepoint[] */
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) */
/*
** End of the routinely-changing class members
***************************************************************************/
@@ -37715,6 +39103,16 @@ static const unsigned char aJournalMagic[] = {
#endif
/*
+** 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).
*/
#define PAGER_MAX_PGNO 2147483647
@@ -38348,7 +39746,7 @@ static int writeJournalHdr(Pager *pPager){
memset(zHeader, 0, sizeof(aJournalMagic)+4);
}
- /* The random check-hash initialiser */
+ /* The random check-hash initializer */
sqlite3_randomness(sizeof(pPager->cksumInit), &pPager->cksumInit);
put32bits(&zHeader[sizeof(aJournalMagic)+4], pPager->cksumInit);
/* The initial database size */
@@ -38787,6 +40185,8 @@ static int pager_error(Pager *pPager, int rc){
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
@@ -38840,7 +40240,7 @@ static int pager_error(Pager *pPager, int rc){
** to the first error encountered (the journal finalization one) is
** returned.
*/
-static int pager_end_transaction(Pager *pPager, int hasMaster){
+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 */
@@ -38890,12 +40290,13 @@ static int pager_end_transaction(Pager *pPager, int hasMaster){
** 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( !pPager->tempFile ){
+ if( bDelete ){
rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
}
}
@@ -38925,7 +40326,17 @@ static int pager_end_transaction(Pager *pPager, int hasMaster){
*/
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( !pPager->exclusiveMode
&& (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0))
){
@@ -38964,7 +40375,7 @@ static void pagerUnlockAndRollback(Pager *pPager){
sqlite3EndBenignMalloc();
}else if( !pPager->exclusiveMode ){
assert( pPager->eState==PAGER_READER );
- pager_end_transaction(pPager, 0);
+ pager_end_transaction(pPager, 0, 0);
}
}
pager_unlock(pPager);
@@ -39188,7 +40599,7 @@ static int pager_playback_one_page(
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);
+ rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst);
if( pgno>pPager->dbFileSize ){
pPager->dbFileSize = pgno;
}
@@ -39459,6 +40870,21 @@ static int pager_truncate(Pager *pPager, Pgno nPage){
}
/*
+** 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 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;
+}
+
+/*
** 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
@@ -39493,14 +40919,7 @@ static void setSectorSize(Pager *pPager){
** call will segfault. */
pPager->sectorSize = 512;
}else{
- pPager->sectorSize = sqlite3OsSectorSize(pPager->fd);
- if( pPager->sectorSize<32 ){
- pPager->sectorSize = 512;
- }
- if( pPager->sectorSize>MAX_SECTOR_SIZE ){
- assert( MAX_SECTOR_SIZE>=512 );
- pPager->sectorSize = MAX_SECTOR_SIZE;
- }
+ pPager->sectorSize = sqlite3SectorSize(pPager->fd);
}
}
@@ -39571,6 +40990,7 @@ static int pager_playback(Pager *pPager, int isHot){
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.
@@ -39671,7 +41091,9 @@ static int pager_playback(Pager *pPager, int isHot){
needPagerReset = 0;
}
rc = pager_playback_one_page(pPager,&pPager->journalOff,0,1,0);
- if( rc!=SQLITE_OK ){
+ if( rc==SQLITE_OK ){
+ nPlayback++;
+ }else{
if( rc==SQLITE_DONE ){
pPager->journalOff = szJ;
break;
@@ -39731,7 +41153,7 @@ end_playback:
rc = sqlite3PagerSync(pPager);
}
if( rc==SQLITE_OK ){
- rc = pager_end_transaction(pPager, zMaster[0]!='\0');
+ rc = pager_end_transaction(pPager, zMaster[0]!='\0', 0);
testcase( rc!=SQLITE_OK );
}
if( rc==SQLITE_OK && zMaster[0] && res ){
@@ -39741,6 +41163,10 @@ end_playback:
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
@@ -39762,11 +41188,10 @@ end_playback:
** If an IO error occurs, then the IO error is returned to the caller.
** Otherwise, SQLITE_OK is returned.
*/
-static int readDbPage(PgHdr *pPg){
+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 isInWal = 0; /* True if page is in log file */
int pgsz = pPager->pageSize; /* Number of bytes to read */
assert( pPager->eState>=PAGER_READER && !MEMDB );
@@ -39778,11 +41203,13 @@ static int readDbPage(PgHdr *pPg){
return SQLITE_OK;
}
- if( pagerUseWal(pPager) ){
+#ifndef SQLITE_OMIT_WAL
+ if( iFrame ){
/* Try to pull the page from the write-ahead log. */
- rc = sqlite3WalRead(pPager->pWal, pgno, &isInWal, pgsz, pPg->pData);
- }
- if( rc==SQLITE_OK && !isInWal ){
+ 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 ){
@@ -39861,12 +41288,17 @@ static int pagerUndoCallback(void *pCtx, Pgno iPg){
Pager *pPager = (Pager *)pCtx;
PgHdr *pPg;
+ assert( pagerUseWal(pPager) );
pPg = sqlite3PagerLookup(pPager, iPg);
if( pPg ){
if( sqlite3PcachePageRefcount(pPg)==1 ){
sqlite3PcacheDrop(pPg);
}else{
- rc = readDbPage(pPg);
+ 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);
}
@@ -40010,6 +41442,7 @@ static int pagerBeginReadTransaction(Pager *pPager){
rc = sqlite3WalBeginReadTransaction(pPager->pWal, &changed);
if( rc!=SQLITE_OK || changed ){
pager_reset(pPager);
+ if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0);
}
return rc;
@@ -40100,6 +41533,7 @@ static int pagerOpenWalIfPresent(Pager *pPager){
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(
@@ -40271,6 +41705,29 @@ SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager *pPager, int 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) ){
+ sqlite3_int64 sz;
+ pPager->bUseFetch = (fd->pMethods->iVersion>=3) && pPager->szMmap>0;
+ sz = pPager->szMmap;
+ sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_MMAP_SIZE, &sz);
+ }
+#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);
+}
+
+/*
** Free as much memory as possible from the pager.
*/
SQLITE_PRIVATE void sqlite3PagerShrink(Pager *pPager){
@@ -40417,9 +41874,16 @@ 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;
+
+ 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);
+ }
}
/*
@@ -40498,6 +41962,7 @@ SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nR
assert( nReserve>=0 && nReserve<1000 );
pPager->nReserve = (i16)nReserve;
pagerReportSize(pPager);
+ pagerFixMaplimit(pPager);
}
return rc;
}
@@ -40651,7 +42116,7 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){
** 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 behaviour would be to restore the current
+** 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
@@ -40675,12 +42140,26 @@ static void assertTruncateConstraint(Pager *pPager){
** 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;
- assertTruncateConstraint(pPager);
+
+ /* 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. */
}
@@ -40710,6 +42189,81 @@ static int pagerSyncHotJournal(Pager *pPager){
}
/*
+** 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;
+ }
+
+ 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;
+
+ 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);
+ }
+}
+
+
+/*
** Shutdown the page cache. Free all memory and close all files.
**
** If a transaction was in progress when this routine is called, that
@@ -40729,6 +42283,7 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager){
assert( assert_pager_state(pPager) );
disable_simulated_io_errors();
sqlite3BeginBenignMalloc();
+ pagerFreeMapHdrs(pPager);
/* pPager->errCode = 0; */
pPager->exclusiveMode = 0;
#ifndef SQLITE_OMIT_WAL
@@ -40990,7 +42545,9 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
** file size will be.
*/
assert( rc!=SQLITE_OK || isOpen(pPager->fd) );
- if( rc==SQLITE_OK && pPager->dbSize>pPager->dbHintSize ){
+ if( rc==SQLITE_OK
+ && (pList->pDirty ? pPager->dbSize : pList->pgno+1)>pPager->dbHintSize
+ ){
sqlite3_int64 szFile = pPager->pageSize * (sqlite3_int64)pPager->dbSize;
sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_SIZE_HINT, &szFile);
pPager->dbHintSize = pPager->dbSize;
@@ -41397,7 +42954,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
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+1);
+ memcpy(&pPager->zJournal[nPathname], "-journal\000", 8+2);
sqlite3FileSuffix3(pPager->zFilename, pPager->zJournal);
#ifndef SQLITE_OMIT_WAL
pPager->zWal = &pPager->zJournal[nPathname+8+1];
@@ -41544,6 +43101,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
/* 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;
@@ -41733,6 +43291,11 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
goto failed;
}
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
@@ -41830,9 +43393,11 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
);
}
- if( !pPager->tempFile
- && (pPager->pBackup || sqlite3PcachePagecount(pPager->pPCache)>0)
- ){
+ 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
@@ -41858,7 +43423,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
if( nPage>0 ){
IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers)));
rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24);
- if( rc!=SQLITE_OK ){
+ if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){
goto failed;
}
}else{
@@ -41867,6 +43432,16 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
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);
+ }
}
}
@@ -41908,7 +43483,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
** nothing to rollback, so this routine is a no-op.
*/
static void pagerUnlockIfUnused(Pager *pPager){
- if( (sqlite3PcacheRefCount(pPager->pPCache)==0) ){
+ if( pPager->nMmapOut==0 && (sqlite3PcacheRefCount(pPager->pPCache)==0) ){
pagerUnlockAndRollback(pPager);
}
}
@@ -41967,13 +43542,27 @@ 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 noContent /* Do not bother reading content from disk if true */
+ int flags /* PAGER_ACQUIRE_XXX flags */
){
- int rc;
- PgHdr *pPg;
+ int rc = SQLITE_OK;
+ PgHdr *pPg = 0;
+ u32 iFrame = 0; /* Frame to read from WAL file */
+ const int noContent = (flags & PAGER_ACQUIRE_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_ACQUIRE_READONLY))
+#ifdef SQLITE_HAS_CODEC
+ && pPager->xCodec==0
+#endif
+ );
assert( pPager->eState>=PAGER_READER );
assert( assert_pager_state(pPager) );
+ assert( noContent==0 || bMmapOk==0 );
if( pgno==0 ){
return SQLITE_CORRUPT_BKPT;
@@ -41984,6 +43573,39 @@ SQLITE_PRIVATE int sqlite3PagerAcquire(
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( iFrame==0 && bMmapOk ){
+ 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 ){
+ (void)sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &pPg);
+ }
+ 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;
+ }
+ }
+
rc = sqlite3PcacheFetch(pPager->pPCache, pgno, 1, ppPage);
}
@@ -42042,9 +43664,13 @@ SQLITE_PRIVATE int sqlite3PagerAcquire(
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);
+ rc = readDbPage(pPg, iFrame);
if( rc!=SQLITE_OK ){
goto pager_acquire_err;
}
@@ -42097,7 +43723,11 @@ SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
SQLITE_PRIVATE void sqlite3PagerUnref(DbPage *pPg){
if( pPg ){
Pager *pPager = pPg->pPager;
- sqlite3PcacheRelease(pPg);
+ if( pPg->flags & PGHDR_MMAP ){
+ pagerReleaseMapPage(pPg);
+ }else{
+ sqlite3PcacheRelease(pPg);
+ }
pagerUnlockIfUnused(pPager);
}
}
@@ -42432,6 +44062,7 @@ SQLITE_PRIVATE int sqlite3PagerWrite(DbPage *pDbPage){
Pager *pPager = pPg->pPager;
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) );
@@ -42599,7 +44230,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
# define DIRECT_MODE isDirectMode
#endif
- if( !pPager->changeCountDone && pPager->dbSize>0 ){
+ if( !pPager->changeCountDone && ALWAYS(pPager->dbSize>0) ){
PgHdr *pPgHdr; /* Reference to page 1 */
assert( !pPager->tempFile && isOpen(pPager->fd) );
@@ -42631,6 +44262,11 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
pPager->aStat[PAGER_STAT_WRITE]++;
}
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;
}
}else{
@@ -42817,38 +44453,6 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
#endif
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
- /* If this transaction has made the database smaller, then all pages
- ** being discarded by the truncation must be written to the journal
- ** file. This can only happen in auto-vacuum mode.
- **
- ** Before reading the pages with page numbers larger than the
- ** current value of Pager.dbSize, set dbSize back to the value
- ** that it took at the start of the transaction. Otherwise, the
- ** calls to sqlite3PagerGet() return zeroed pages instead of
- ** reading data from the database file.
- */
- #ifndef SQLITE_OMIT_AUTOVACUUM
- if( pPager->dbSize<pPager->dbOrigSize
- && pPager->journalMode!=PAGER_JOURNALMODE_OFF
- ){
- Pgno i; /* Iterator variable */
- const Pgno iSkip = PAGER_MJ_PGNO(pPager); /* Pending lock page */
- const Pgno dbSize = pPager->dbSize; /* Database image size */
- pPager->dbSize = pPager->dbOrigSize;
- for( i=dbSize+1; i<=pPager->dbOrigSize; i++ ){
- if( !sqlite3BitvecTest(pPager->pInJournal, i) && i!=iSkip ){
- PgHdr *pPage; /* Page to journal */
- rc = sqlite3PagerGet(pPager, i, &pPage);
- if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
- rc = sqlite3PagerWrite(pPage);
- sqlite3PagerUnref(pPage);
- if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
- }
- }
- pPager->dbSize = dbSize;
- }
- #endif
-
/* 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.
@@ -42876,11 +44480,14 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
goto commit_phase_one_exit;
}
sqlite3PcacheCleanAll(pPager->pPCache);
-
- /* If the file on disk is not the same size as the database image,
- ** then use pager_truncate to grow or shrink the file here.
- */
- if( pPager->dbSize!=pPager->dbFileSize ){
+
+ /* 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);
@@ -42953,7 +44560,7 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager *pPager){
}
PAGERTRACE(("COMMIT %d\n", PAGERID(pPager)));
- rc = pager_end_transaction(pPager, pPager->setMaster);
+ rc = pager_end_transaction(pPager, pPager->setMaster, 1);
return pager_error(pPager, rc);
}
@@ -42998,11 +44605,11 @@ SQLITE_PRIVATE int sqlite3PagerRollback(Pager *pPager){
if( pagerUseWal(pPager) ){
int rc2;
rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, -1);
- rc2 = pager_end_transaction(pPager, pPager->setMaster);
+ 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);
+ 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.
@@ -43017,7 +44624,7 @@ SQLITE_PRIVATE int sqlite3PagerRollback(Pager *pPager){
}
assert( pPager->eState==PAGER_READER || rc!=SQLITE_OK );
- assert( rc==SQLITE_OK || rc==SQLITE_FULL
+ assert( rc==SQLITE_OK || rc==SQLITE_FULL || rc==SQLITE_CORRUPT
|| rc==SQLITE_NOMEM || (rc&0xFF)==SQLITE_IOERR );
/* If an error occurs during a ROLLBACK, we can no longer trust the pager
@@ -43400,7 +45007,8 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
*/
if( (pPg->flags&PGHDR_NEED_SYNC) && !isCommit ){
needSyncPgno = pPg->pgno;
- assert( pageInJournal(pPg) || pPg->pgno>pPager->dbOrigSize );
+ assert( pPager->journalMode==PAGER_JOURNALMODE_OFF ||
+ pageInJournal(pPg) || pPg->pgno>pPager->dbOrigSize );
assert( pPg->flags&PGHDR_DIRTY );
}
@@ -43750,11 +45358,12 @@ static int pagerOpenWal(Pager *pPager){
** (e.g. due to malloc() failure), return an error code.
*/
if( rc==SQLITE_OK ){
- rc = sqlite3WalOpen(pPager->pVfs,
+ rc = sqlite3WalOpen(pPager->pVfs,
pPager->fd, pPager->zWal, pPager->exclusiveMode,
pPager->journalSizeLimit, &pPager->pWal
);
}
+ pagerFixMaplimit(pPager);
return rc;
}
@@ -43845,11 +45454,14 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager){
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
/*
** A read-lock must be held on the pager when this function is called. If
@@ -43879,8 +45491,6 @@ SQLITE_PRIVATE void *sqlite3PagerCodec(PgHdr *pPg){
}
#endif /* SQLITE_HAS_CODEC */
-#endif /* !SQLITE_OMIT_WAL */
-
#endif /* SQLITE_OMIT_DISKIO */
/************** End of pager.c ***********************************************/
@@ -45093,8 +46703,9 @@ finished:
** checkpointing the log file.
*/
if( pWal->hdr.nPage ){
- sqlite3_log(SQLITE_OK, "Recovered %d frames from WAL file %s",
- pWal->hdr.nPage, pWal->zWalName
+ sqlite3_log(SQLITE_NOTICE_RECOVER_WAL,
+ "recovered %d frames from WAL file %s",
+ pWal->hdr.mxFrame, pWal->zWalName
);
}
}
@@ -45608,8 +47219,8 @@ static int walCheckpoint(
rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
}
- /* If the database file may grow as a result of this checkpoint, hint
- ** about the eventual size of the db file to the VFS layer.
+ /* 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);
@@ -45619,6 +47230,7 @@ static int walCheckpoint(
}
}
+
/* Iterate through the contents of the WAL, copying data to the db file. */
while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
i64 iOffset;
@@ -46173,19 +47785,17 @@ SQLITE_PRIVATE void sqlite3WalEndReadTransaction(Wal *pWal){
}
/*
-** Read a page from the WAL, if it is present in the WAL and if the
-** current read transaction is configured to use the WAL.
+** 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.
**
-** The *pInWal is set to 1 if the requested page is in the WAL and
-** has been loaded. Or *pInWal is set to 0 if the page was not in
-** the WAL and needs to be read out of the database.
+** 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 sqlite3WalRead(
+SQLITE_PRIVATE int sqlite3WalFindFrame(
Wal *pWal, /* WAL handle */
Pgno pgno, /* Database page number to read data for */
- int *pInWal, /* OUT: True if data is read from WAL */
- int nOut, /* Size of buffer pOut in bytes */
- u8 *pOut /* Buffer to write page data to */
+ u32 *piRead /* OUT: Frame number (or zero) */
){
u32 iRead = 0; /* If !=0, WAL frame to return data from */
u32 iLast = pWal->hdr.mxFrame; /* Last page in WAL for this reader */
@@ -46201,7 +47811,7 @@ SQLITE_PRIVATE int sqlite3WalRead(
** WAL were empty.
*/
if( iLast==0 || pWal->readLock==0 ){
- *pInWal = 0;
+ *piRead = 0;
return SQLITE_OK;
}
@@ -46272,26 +47882,31 @@ SQLITE_PRIVATE int sqlite3WalRead(
}
#endif
- /* If iRead is non-zero, then it is the log frame number that contains the
- ** required page. Read and return data from the log file.
- */
- if( iRead ){
- int sz;
- i64 iOffset;
- sz = pWal->hdr.szPage;
- sz = (sz&0xfe00) + ((sz&0x0001)<<16);
- testcase( sz<=32768 );
- testcase( sz>=65536 );
- iOffset = walFrameOffset(iRead, sz) + WAL_FRAME_HDRSIZE;
- *pInWal = 1;
- /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
- return sqlite3OsRead(pWal->pWalFd, pOut, (nOut>sz ? sz : nOut), iOffset);
- }
-
- *pInWal = 0;
+ *piRead = iRead;
return SQLITE_OK;
}
+/*
+** 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 sqlite3WalReadFrame(
+ Wal *pWal, /* WAL handle */
+ u32 iRead, /* Frame to read */
+ int nOut, /* Size of buffer pOut in bytes */
+ u8 *pOut /* Buffer to write page data to */
+){
+ int sz;
+ i64 iOffset;
+ sz = pWal->hdr.szPage;
+ sz = (sz&0xfe00) + ((sz&0x0001)<<16);
+ testcase( sz<=32768 );
+ testcase( sz>=65536 );
+ 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);
+}
/*
** Return the size of the database in pages (or zero, if unknown).
@@ -46404,7 +48019,7 @@ SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *p
assert( walFramePgno(pWal, iFrame)!=1 );
rc = xUndo(pUndoCtx, walFramePgno(pWal, iFrame));
}
- walCleanupHash(pWal);
+ if( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal);
}
assert( rc==SQLITE_OK );
return rc;
@@ -46714,7 +48329,7 @@ SQLITE_PRIVATE int sqlite3WalFrames(
*/
if( isCommit && (sync_flags & WAL_SYNC_TRANSACTIONS)!=0 ){
if( pWal->padToSectorBoundary ){
- int sectorSize = sqlite3OsSectorSize(pWal->pWalFd);
+ int sectorSize = sqlite3SectorSize(pWal->pWalFd);
w.iSyncPoint = ((iOffset+sectorSize-1)/sectorSize)*sectorSize;
while( iOffset<w.iSyncPoint ){
rc = walWriteOneFrame(&w, pLast, nTruncate, iOffset);
@@ -46838,6 +48453,9 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint(
/* 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);
+ }
}
/* Copy data from the log to the database file. */
@@ -47404,6 +49022,7 @@ struct BtShared {
#ifndef SQLITE_OMIT_AUTOVACUUM
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
u8 inTransaction; /* Transaction state */
u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */
@@ -47970,6 +49589,25 @@ int sqlite3BtreeTrace=1; /* True to enable tracing */
*/
#define get2byteNotZero(X) (((((int)get2byte(X))-1)&0xffff)+1)
+/*
+** Values passed as the 5th argument to allocateBtreePage()
+*/
+#define BTALLOC_ANY 0 /* Allocate any page */
+#define BTALLOC_EXACT 1 /* Allocate exact page if possible */
+#define BTALLOC_LE 2 /* Allocate any page <= the parameter */
+
+/*
+** Macro IfNotOmitAV(x) returns (x) if SQLITE_OMIT_AUTOVACUUM is not
+** defined, or 0 if it is. For example:
+**
+** bIncrVacuum = IfNotOmitAV(pBtShared->incrVacuum);
+*/
+#ifndef SQLITE_OMIT_AUTOVACUUM
+#define IfNotOmitAV(expr) (expr)
+#else
+#define IfNotOmitAV(expr) 0
+#endif
+
#ifndef SQLITE_OMIT_SHARED_CACHE
/*
** A list of BtShared objects that are eligible for participation
@@ -48484,6 +50122,19 @@ static void btreeClearHasContent(BtShared *pBt){
}
/*
+** Release all of the apPage[] pages for a cursor.
+*/
+static void btreeReleaseAllCursorPages(BtCursor *pCur){
+ int i;
+ for(i=0; i<=pCur->iPage; i++){
+ releasePage(pCur->apPage[i]);
+ pCur->apPage[i] = 0;
+ }
+ pCur->iPage = -1;
+}
+
+
+/*
** Save the current cursor position in the variables BtCursor.nKey
** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK.
**
@@ -48522,12 +50173,7 @@ static int saveCursorPosition(BtCursor *pCur){
assert( !pCur->apPage[0]->intKey || !pCur->pKey );
if( rc==SQLITE_OK ){
- int i;
- for(i=0; i<=pCur->iPage; i++){
- releasePage(pCur->apPage[i]);
- pCur->apPage[i] = 0;
- }
- pCur->iPage = -1;
+ btreeReleaseAllCursorPages(pCur);
pCur->eState = CURSOR_REQUIRESEEK;
}
@@ -48545,11 +50191,15 @@ static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){
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) &&
- p->eState==CURSOR_VALID ){
- int rc = saveCursorPosition(p);
- if( SQLITE_OK!=rc ){
- return rc;
+ if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) ){
+ if( p->eState==CURSOR_VALID ){
+ int rc = saveCursorPosition(p);
+ if( SQLITE_OK!=rc ){
+ return rc;
+ }
+ }else{
+ testcase( p->iPage>0 );
+ btreeReleaseAllCursorPages(p);
}
}
}
@@ -49477,13 +51127,17 @@ static int btreeGetPage(
BtShared *pBt, /* The btree */
Pgno pgno, /* Number of the page to fetch */
MemPage **ppPage, /* Return the page in this parameter */
- int noContent /* Do not load page content if true */
+ int noContent, /* Do not load page content if true */
+ int bReadonly /* True if a read-only (mmap) page is ok */
){
int rc;
DbPage *pDbPage;
+ int flags = (noContent ? PAGER_ACQUIRE_NOCONTENT : 0)
+ | (bReadonly ? PAGER_ACQUIRE_READONLY : 0);
+ assert( noContent==0 || bReadonly==0 );
assert( sqlite3_mutex_held(pBt->mutex) );
- rc = sqlite3PagerAcquire(pBt->pPager, pgno, (DbPage**)&pDbPage, noContent);
+ rc = sqlite3PagerAcquire(pBt->pPager, pgno, (DbPage**)&pDbPage, flags);
if( rc ) return rc;
*ppPage = btreePageFromDbPage(pDbPage, pgno, pBt);
return SQLITE_OK;
@@ -49526,9 +51180,10 @@ SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree *p){
** may remain unchanged, or it may be set to an invalid value.
*/
static int getAndInitPage(
- BtShared *pBt, /* The database file */
- Pgno pgno, /* Number of the page to get */
- MemPage **ppPage /* Write the page pointer here */
+ BtShared *pBt, /* The database file */
+ Pgno pgno, /* Number of the page to get */
+ MemPage **ppPage, /* Write the page pointer here */
+ int bReadonly /* True if a read-only (mmap) page is ok */
){
int rc;
assert( sqlite3_mutex_held(pBt->mutex) );
@@ -49536,7 +51191,7 @@ static int getAndInitPage(
if( pgno>btreePagecount(pBt) ){
rc = SQLITE_CORRUPT_BKPT;
}else{
- rc = btreeGetPage(pBt, pgno, ppPage, 0);
+ rc = btreeGetPage(pBt, pgno, ppPage, 0, bReadonly);
if( rc==SQLITE_OK ){
rc = btreeInitPage(*ppPage);
if( rc!=SQLITE_OK ){
@@ -49767,6 +51422,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
rc = sqlite3PagerOpen(pVfs, &pBt->pPager, zFilename,
EXTRA_SIZE, flags, vfsFlags, pageReinit);
if( rc==SQLITE_OK ){
+ sqlite3PagerSetMmapLimit(pBt->pPager, db->szMmap);
rc = sqlite3PagerReadFileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader);
}
if( rc!=SQLITE_OK ){
@@ -50034,6 +51690,19 @@ SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){
}
/*
+** Change the limit on the amount of the database file that may be
+** memory mapped.
+*/
+SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree *p, sqlite3_int64 szMmap){
+ BtShared *pBt = p->pBt;
+ assert( sqlite3_mutex_held(p->db->mutex) );
+ sqlite3BtreeEnter(p);
+ sqlite3PagerSetMmapLimit(pBt->pPager, szMmap);
+ sqlite3BtreeLeave(p);
+ return SQLITE_OK;
+}
+
+/*
** Change the way data is synced to disk in order to increase or decrease
** how well the database resists damage due to OS crashes and power
** failures. Level 1 is the same as asynchronous (no syncs() occur and
@@ -50127,6 +51796,24 @@ 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
+** held.
+**
+** This is useful in one special case in the backup API code where it is
+** known that the shared b-tree mutex is held, but the mutex on the
+** database handle that owns *p is not. In this case if sqlite3BtreeEnter()
+** were to be called, it might collide with some other operation on the
+** database handle that owns *p, causing undefined behavior.
+*/
+SQLITE_PRIVATE int sqlite3BtreeGetReserveNoMutex(Btree *p){
+ assert( sqlite3_mutex_held(p->pBt->mutex) );
+ return p->pBt->pageSize - p->pBt->usableSize;
+}
+#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
@@ -50240,7 +51927,7 @@ static int lockBtree(BtShared *pBt){
assert( pBt->pPage1==0 );
rc = sqlite3PagerSharedLock(pBt->pPager);
if( rc!=SQLITE_OK ) return rc;
- rc = btreeGetPage(pBt, 1, &pPage1, 0);
+ rc = btreeGetPage(pBt, 1, &pPage1, 0, 0);
if( rc!=SQLITE_OK ) return rc;
/* Do some checking to help insure the file we opened really is
@@ -50376,6 +52063,29 @@ page1_init_failed:
return rc;
}
+#ifndef NDEBUG
+/*
+** Return the number of cursors open on pBt. This is for use
+** in assert() expressions, so it is only compiled if NDEBUG is not
+** defined.
+**
+** Only write cursors are counted if wrOnly is true. If wrOnly is
+** 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
+** have been tripped into the CURSOR_FAULT state are not counted.
+*/
+static int countValidCursors(BtShared *pBt, int wrOnly){
+ BtCursor *pCur;
+ int r = 0;
+ for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
+ if( (wrOnly==0 || pCur->wrFlag) && pCur->eState!=CURSOR_FAULT ) r++;
+ }
+ return r;
+}
+#endif
+
/*
** If there are no outstanding cursors and we are not in the middle
** of a transaction but there is a read lock on the database, then
@@ -50386,7 +52096,7 @@ page1_init_failed:
*/
static void unlockBtreeIfUnused(BtShared *pBt){
assert( sqlite3_mutex_held(pBt->mutex) );
- assert( pBt->pCursor==0 || pBt->inTransaction>TRANS_NONE );
+ assert( countValidCursors(pBt,0)==0 || pBt->inTransaction>TRANS_NONE );
if( pBt->inTransaction==TRANS_NONE && pBt->pPage1!=0 ){
assert( pBt->pPage1->aData );
assert( sqlite3PagerRefcount(pBt->pPager)==1 );
@@ -50441,6 +52151,20 @@ static int newDatabase(BtShared *pBt){
}
/*
+** Initialize the first page of the database file (creating a database
+** consisting of a single page and no schema objects). Return SQLITE_OK
+** if successful, or an SQLite error code otherwise.
+*/
+SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p){
+ int rc;
+ sqlite3BtreeEnter(p);
+ p->pBt->nPage = 0;
+ rc = newDatabase(p->pBt);
+ sqlite3BtreeLeave(p);
+ return rc;
+}
+
+/*
** Attempt to start a new transaction. A write-transaction
** is started if the second argument is nonzero, otherwise a read-
** transaction. If the second argument is 2 or more and exclusive
@@ -50490,6 +52214,7 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
if( p->inTrans==TRANS_WRITE || (p->inTrans==TRANS_READ && !wrflag) ){
goto trans_begun;
}
+ assert( IfNotOmitAV(pBt->bDoTruncate)==0 );
/* Write transactions are not possible on a read-only database */
if( (pBt->btsFlags & BTS_READ_ONLY)!=0 && wrflag ){
@@ -50784,7 +52509,7 @@ static int relocatePage(
** iPtrPage.
*/
if( eType!=PTRMAP_ROOTPAGE ){
- rc = btreeGetPage(pBt, iPtrPage, &pPtrPage, 0);
+ rc = btreeGetPage(pBt, iPtrPage, &pPtrPage, 0, 0);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -50806,24 +52531,23 @@ static int relocatePage(
static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8);
/*
-** Perform a single step of an incremental-vacuum. If successful,
-** return SQLITE_OK. If there is no work to do (and therefore no
-** point in calling this function again), return SQLITE_DONE.
+** Perform a single step of an incremental-vacuum. If successful, return
+** SQLITE_OK. If there is no work to do (and therefore no point in
+** 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
+** that the last page of the file currently in use is no longer in use.
**
-** More specificly, 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
+** were this function called until it returns SQLITE_DONE.
**
-** If the nFin parameter is non-zero, this function assumes
-** that the caller will keep calling incrVacuumStep() until
-** it returns SQLITE_DONE or an error, and that nFin is the
-** number of pages the database file will contain after this
-** process is complete. If nFin is zero, it is assumed that
-** incrVacuumStep() will be called a finite amount of times
-** which may or may not empty the freelist. A full autovacuum
-** has nFin>0. A "PRAGMA incremental_vacuum" has nFin==0.
+** 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
+** operation, or false for an incremental vacuum.
*/
-static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
+static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){
Pgno nFreeList; /* Number of pages still on the free-list */
int rc;
@@ -50848,15 +52572,15 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
}
if( eType==PTRMAP_FREEPAGE ){
- if( nFin==0 ){
+ if( bCommit==0 ){
/* Remove the page from the files free-list. This is not required
- ** if nFin is non-zero. In that case, the free-list will be
+ ** if bCommit is non-zero. In that case, the free-list will be
** truncated to zero after this function returns, so it doesn't
** matter if it still contains some garbage entries.
*/
Pgno iFreePg;
MemPage *pFreePg;
- rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iLastPg, 1);
+ rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iLastPg, BTALLOC_EXACT);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -50866,34 +52590,37 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
} else {
Pgno iFreePg; /* Index of free page to move pLastPg to */
MemPage *pLastPg;
+ u8 eMode = BTALLOC_ANY; /* Mode parameter for allocateBtreePage() */
+ Pgno iNear = 0; /* nearby parameter for allocateBtreePage() */
- rc = btreeGetPage(pBt, iLastPg, &pLastPg, 0);
+ rc = btreeGetPage(pBt, iLastPg, &pLastPg, 0, 0);
if( rc!=SQLITE_OK ){
return rc;
}
- /* If nFin is zero, this loop runs exactly once and page pLastPg
+ /* If bCommit is zero, this loop runs exactly once and page pLastPg
** is swapped with the first free page pulled off the free list.
**
- ** On the other hand, if nFin is greater than zero, then keep
+ ** On the other hand, if bCommit is greater than zero, then keep
** looping until a free-page located within the first nFin pages
** of the file is found.
*/
+ if( bCommit==0 ){
+ eMode = BTALLOC_LE;
+ iNear = nFin;
+ }
do {
MemPage *pFreePg;
- rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, 0, 0);
+ rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iNear, eMode);
if( rc!=SQLITE_OK ){
releasePage(pLastPg);
return rc;
}
releasePage(pFreePg);
- }while( nFin!=0 && iFreePg>nFin );
+ }while( bCommit && iFreePg>nFin );
assert( iFreePg<iLastPg );
- rc = sqlite3PagerWrite(pLastPg->pDbPage);
- if( rc==SQLITE_OK ){
- rc = relocatePage(pBt, pLastPg, eType, iPtrPage, iFreePg, nFin!=0);
- }
+ rc = relocatePage(pBt, pLastPg, eType, iPtrPage, iFreePg, bCommit);
releasePage(pLastPg);
if( rc!=SQLITE_OK ){
return rc;
@@ -50901,30 +52628,40 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
}
}
- if( nFin==0 ){
- iLastPg--;
- while( iLastPg==PENDING_BYTE_PAGE(pBt)||PTRMAP_ISPAGE(pBt, iLastPg) ){
- if( PTRMAP_ISPAGE(pBt, iLastPg) ){
- MemPage *pPg;
- rc = btreeGetPage(pBt, iLastPg, &pPg, 0);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- rc = sqlite3PagerWrite(pPg->pDbPage);
- releasePage(pPg);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- }
+ if( bCommit==0 ){
+ do {
iLastPg--;
- }
- sqlite3PagerTruncateImage(pBt->pPager, iLastPg);
+ }while( iLastPg==PENDING_BYTE_PAGE(pBt) || PTRMAP_ISPAGE(pBt, iLastPg) );
+ pBt->bDoTruncate = 1;
pBt->nPage = iLastPg;
}
return SQLITE_OK;
}
/*
+** The database opened by the first argument is an auto-vacuum database
+** nOrig pages in size containing nFree free pages. Return the expected
+** size of the database in pages following an auto-vacuum operation.
+*/
+static Pgno finalDbSize(BtShared *pBt, Pgno nOrig, Pgno nFree){
+ int nEntry; /* Number of entries on one ptrmap page */
+ Pgno nPtrmap; /* Number of PtrMap pages to be freed */
+ Pgno nFin; /* Return value */
+
+ nEntry = pBt->usableSize/5;
+ nPtrmap = (nFree-nOrig+PTRMAP_PAGENO(pBt, nOrig)+nEntry)/nEntry;
+ nFin = nOrig - nFree - nPtrmap;
+ if( nOrig>PENDING_BYTE_PAGE(pBt) && nFin<PENDING_BYTE_PAGE(pBt) ){
+ nFin--;
+ }
+ while( PTRMAP_ISPAGE(pBt, nFin) || nFin==PENDING_BYTE_PAGE(pBt) ){
+ nFin--;
+ }
+
+ return nFin;
+}
+
+/*
** A write-transaction must be opened before calling this function.
** It performs a single unit of work towards an incremental vacuum.
**
@@ -50941,11 +52678,24 @@ SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *p){
if( !pBt->autoVacuum ){
rc = SQLITE_DONE;
}else{
- invalidateAllOverflowCache(pBt);
- rc = incrVacuumStep(pBt, 0, btreePagecount(pBt));
- if( rc==SQLITE_OK ){
- rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
- put4byte(&pBt->pPage1->aData[28], pBt->nPage);
+ Pgno nOrig = btreePagecount(pBt);
+ Pgno nFree = get4byte(&pBt->pPage1->aData[36]);
+ Pgno nFin = finalDbSize(pBt, nOrig, nFree);
+
+ if( nOrig<nFin ){
+ rc = SQLITE_CORRUPT_BKPT;
+ }else if( nFree>0 ){
+ rc = saveAllCursors(pBt, 0, 0);
+ if( rc==SQLITE_OK ){
+ invalidateAllOverflowCache(pBt);
+ rc = incrVacuumStep(pBt, nFin, nOrig, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
+ put4byte(&pBt->pPage1->aData[28], pBt->nPage);
+ }
+ }else{
+ rc = SQLITE_DONE;
}
}
sqlite3BtreeLeave(p);
@@ -50972,9 +52722,7 @@ static int autoVacuumCommit(BtShared *pBt){
if( !pBt->incrVacuum ){
Pgno nFin; /* Number of pages in database after autovacuuming */
Pgno nFree; /* Number of pages on the freelist initially */
- Pgno nPtrmap; /* Number of PtrMap pages to be freed */
Pgno iFree; /* The next page to be freed */
- int nEntry; /* Number of entries on one ptrmap page */
Pgno nOrig; /* Database size before freeing */
nOrig = btreePagecount(pBt);
@@ -50987,26 +52735,20 @@ static int autoVacuumCommit(BtShared *pBt){
}
nFree = get4byte(&pBt->pPage1->aData[36]);
- nEntry = pBt->usableSize/5;
- nPtrmap = (nFree-nOrig+PTRMAP_PAGENO(pBt, nOrig)+nEntry)/nEntry;
- nFin = nOrig - nFree - nPtrmap;
- if( nOrig>PENDING_BYTE_PAGE(pBt) && nFin<PENDING_BYTE_PAGE(pBt) ){
- nFin--;
- }
- while( PTRMAP_ISPAGE(pBt, nFin) || nFin==PENDING_BYTE_PAGE(pBt) ){
- nFin--;
- }
+ nFin = finalDbSize(pBt, nOrig, nFree);
if( nFin>nOrig ) return SQLITE_CORRUPT_BKPT;
-
+ if( nFin<nOrig ){
+ rc = saveAllCursors(pBt, 0, 0);
+ }
for(iFree=nOrig; iFree>nFin && rc==SQLITE_OK; iFree--){
- rc = incrVacuumStep(pBt, nFin, iFree);
+ rc = incrVacuumStep(pBt, nFin, iFree, 1);
}
if( (rc==SQLITE_DONE || rc==SQLITE_OK) && nFree>0 ){
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
put4byte(&pBt->pPage1->aData[32], 0);
put4byte(&pBt->pPage1->aData[36], 0);
put4byte(&pBt->pPage1->aData[28], nFin);
- sqlite3PagerTruncateImage(pBt->pPager, nFin);
+ pBt->bDoTruncate = 1;
pBt->nPage = nFin;
}
if( rc!=SQLITE_OK ){
@@ -51014,7 +52756,7 @@ static int autoVacuumCommit(BtShared *pBt){
}
}
- assert( nRef==sqlite3PagerRefcount(pPager) );
+ assert( nRef>=sqlite3PagerRefcount(pPager) );
return rc;
}
@@ -51061,6 +52803,9 @@ SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zMaster){
return rc;
}
}
+ if( pBt->bDoTruncate ){
+ sqlite3PagerTruncateImage(pBt->pPager, pBt->nPage);
+ }
#endif
rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zMaster, 0);
sqlite3BtreeLeave(p);
@@ -51076,7 +52821,9 @@ static void btreeEndTransaction(Btree *p){
BtShared *pBt = p->pBt;
assert( sqlite3BtreeHoldsMutex(p) );
- btreeClearHasContent(pBt);
+#ifndef SQLITE_OMIT_AUTOVACUUM
+ pBt->bDoTruncate = 0;
+#endif
if( p->inTrans>TRANS_NONE && p->db->activeVdbeCnt>1 ){
/* If there are other active statements that belong to this database
** handle, downgrade to a read-only transaction. The other statements
@@ -51151,6 +52898,7 @@ SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree *p, int bCleanup){
return rc;
}
pBt->inTransaction = TRANS_READ;
+ btreeClearHasContent(pBt);
}
btreeEndTransaction(p);
@@ -51172,27 +52920,6 @@ SQLITE_PRIVATE int sqlite3BtreeCommit(Btree *p){
return rc;
}
-#ifndef NDEBUG
-/*
-** Return the number of write-cursors open on this handle. This is for use
-** in assert() expressions, so it is only compiled if NDEBUG is not
-** defined.
-**
-** For the purposes of this routine, a write-cursor is any cursor that
-** is capable of writing to the databse. That means the cursor was
-** originally opened for writing and the cursor has not be disabled
-** by having its state changed to CURSOR_FAULT.
-*/
-static int countWriteCursors(BtShared *pBt){
- BtCursor *pCur;
- int r = 0;
- for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
- if( pCur->wrFlag && pCur->eState!=CURSOR_FAULT ) r++;
- }
- return r;
-}
-#endif
-
/*
** This routine sets the state to CURSOR_FAULT and the error
** code to errCode for every cursor on BtShared that pBtree
@@ -51264,7 +52991,7 @@ SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p, int tripCode){
/* The rollback may have destroyed the pPage1->aData value. So
** call btreeGetPage() on page 1 again to make
** sure pPage1->aData is set correctly. */
- if( btreeGetPage(pBt, 1, &pPage1, 0)==SQLITE_OK ){
+ if( btreeGetPage(pBt, 1, &pPage1, 0, 0)==SQLITE_OK ){
int nPage = get4byte(28+(u8*)pPage1->aData);
testcase( nPage==0 );
if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage);
@@ -51272,8 +52999,9 @@ SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p, int tripCode){
pBt->nPage = nPage;
releasePage(pPage1);
}
- assert( countWriteCursors(pBt)==0 );
+ assert( countValidCursors(pBt, 1)==0 );
pBt->inTransaction = TRANS_READ;
+ btreeClearHasContent(pBt);
}
btreeEndTransaction(p);
@@ -51698,7 +53426,7 @@ static int getOverflowPage(
assert( next==0 || rc==SQLITE_DONE );
if( rc==SQLITE_OK ){
- rc = btreeGetPage(pBt, ovfl, &pPage, 0);
+ rc = btreeGetPage(pBt, ovfl, &pPage, 0, (ppPage==0));
assert( rc==SQLITE_OK || pPage==0 );
if( rc==SQLITE_OK ){
next = get4byte(pPage->aData);
@@ -51919,7 +53647,9 @@ static int accessPayload(
{
DbPage *pDbPage;
- rc = sqlite3PagerGet(pBt->pPager, nextPage, &pDbPage);
+ rc = sqlite3PagerAcquire(pBt->pPager, nextPage, &pDbPage,
+ (eOp==0 ? PAGER_ACQUIRE_READONLY : 0)
+ );
if( rc==SQLITE_OK ){
aPayload = sqlite3PagerGetData(pDbPage);
nextPage = get4byte(aPayload);
@@ -52098,10 +53828,11 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
+ assert( pCur->iPage>=0 );
if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){
return SQLITE_CORRUPT_BKPT;
}
- rc = getAndInitPage(pBt, newPgno, &pNewPage);
+ rc = getAndInitPage(pBt, newPgno, &pNewPage, (pCur->wrFlag==0));
if( rc ) return rc;
pCur->apPage[i+1] = pNewPage;
pCur->aiIdx[i+1] = 0;
@@ -52218,7 +53949,7 @@ static int moveToRoot(BtCursor *pCur){
pCur->eState = CURSOR_INVALID;
return SQLITE_OK;
}else{
- rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->apPage[0]);
+ rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->apPage[0], pCur->wrFlag==0);
if( rc!=SQLITE_OK ){
pCur->eState = CURSOR_INVALID;
return rc;
@@ -52748,21 +54479,23 @@ SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
** an error. *ppPage and *pPgno are undefined in the event of an error.
** Do not invoke sqlite3PagerUnref() on *ppPage if an error is returned.
**
-** If the "nearby" parameter is not 0, then a (feeble) effort is made to
+** If the "nearby" parameter is not 0, then an effort is made to
** locate a page close to the page number "nearby". This can be used in an
** attempt to keep related pages close to each other in the database file,
** which in turn can make database access faster.
**
-** If the "exact" parameter is not 0, and the page-number nearby exists
-** anywhere on the free-list, then it is guarenteed to be returned. This
-** is only used by auto-vacuum databases when allocating a new table.
+** If the eMode parameter is BTALLOC_EXACT and the nearby page exists
+** anywhere on the free-list, then it is guaranteed to be returned. If
+** eMode is BTALLOC_LT then the page returned will be less than or equal
+** to nearby if any such page exists. If eMode is BTALLOC_ANY then there
+** are no restrictions on which page is returned.
*/
static int allocateBtreePage(
- BtShared *pBt,
- MemPage **ppPage,
- Pgno *pPgno,
- Pgno nearby,
- u8 exact
+ BtShared *pBt, /* The btree */
+ MemPage **ppPage, /* Store pointer to the allocated page here */
+ Pgno *pPgno, /* Store the page number here */
+ Pgno nearby, /* Search for a page near this one */
+ u8 eMode /* BTALLOC_EXACT, BTALLOC_LT, or BTALLOC_ANY */
){
MemPage *pPage1;
int rc;
@@ -52773,6 +54506,7 @@ static int allocateBtreePage(
Pgno mxPage; /* Total size of the database file */
assert( sqlite3_mutex_held(pBt->mutex) );
+ assert( eMode==BTALLOC_ANY || (nearby>0 && IfNotOmitAV(pBt->autoVacuum)) );
pPage1 = pBt->pPage1;
mxPage = btreePagecount(pBt);
n = get4byte(&pPage1->aData[36]);
@@ -52785,21 +54519,24 @@ static int allocateBtreePage(
Pgno iTrunk;
u8 searchList = 0; /* If the free-list must be searched for 'nearby' */
- /* If the 'exact' parameter was true and a query of the pointer-map
+ /* If eMode==BTALLOC_EXACT and a query of the pointer-map
** shows that the page 'nearby' is somewhere on the free-list, then
** the entire-list will be searched for that page.
*/
#ifndef SQLITE_OMIT_AUTOVACUUM
- if( exact && nearby<=mxPage ){
- u8 eType;
- assert( nearby>0 );
- assert( pBt->autoVacuum );
- rc = ptrmapGet(pBt, nearby, &eType, 0);
- if( rc ) return rc;
- if( eType==PTRMAP_FREEPAGE ){
- searchList = 1;
+ if( eMode==BTALLOC_EXACT ){
+ if( nearby<=mxPage ){
+ u8 eType;
+ assert( nearby>0 );
+ assert( pBt->autoVacuum );
+ rc = ptrmapGet(pBt, nearby, &eType, 0);
+ if( rc ) return rc;
+ if( eType==PTRMAP_FREEPAGE ){
+ searchList = 1;
+ }
}
- *pPgno = nearby;
+ }else if( eMode==BTALLOC_LE ){
+ searchList = 1;
}
#endif
@@ -52812,7 +54549,8 @@ static int allocateBtreePage(
/* The code within this loop is run only once if the 'searchList' variable
** is not true. Otherwise, it runs once for each trunk-page on the
- ** free-list until the page 'nearby' is located.
+ ** free-list until the page 'nearby' is located (eMode==BTALLOC_EXACT)
+ ** or until a page less than 'nearby' is located (eMode==BTALLOC_LT)
*/
do {
pPrevTrunk = pTrunk;
@@ -52825,7 +54563,7 @@ static int allocateBtreePage(
if( iTrunk>mxPage ){
rc = SQLITE_CORRUPT_BKPT;
}else{
- rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0);
+ rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0, 0);
}
if( rc ){
pTrunk = 0;
@@ -52854,11 +54592,13 @@ static int allocateBtreePage(
rc = SQLITE_CORRUPT_BKPT;
goto end_allocate_page;
#ifndef SQLITE_OMIT_AUTOVACUUM
- }else if( searchList && nearby==iTrunk ){
+ }else if( searchList
+ && (nearby==iTrunk || (iTrunk<nearby && eMode==BTALLOC_LE))
+ ){
/* The list is being searched and this trunk page is the page
** to allocate, regardless of whether it has leaves.
*/
- assert( *pPgno==iTrunk );
+ *pPgno = iTrunk;
*ppPage = pTrunk;
searchList = 0;
rc = sqlite3PagerWrite(pTrunk->pDbPage);
@@ -52887,7 +54627,7 @@ static int allocateBtreePage(
goto end_allocate_page;
}
testcase( iNewTrunk==mxPage );
- rc = btreeGetPage(pBt, iNewTrunk, &pNewTrunk, 0);
+ rc = btreeGetPage(pBt, iNewTrunk, &pNewTrunk, 0, 0);
if( rc!=SQLITE_OK ){
goto end_allocate_page;
}
@@ -52921,14 +54661,24 @@ static int allocateBtreePage(
unsigned char *aData = pTrunk->aData;
if( nearby>0 ){
u32 i;
- int dist;
closest = 0;
- dist = sqlite3AbsInt32(get4byte(&aData[8]) - nearby);
- for(i=1; i<k; i++){
- int d2 = sqlite3AbsInt32(get4byte(&aData[8+i*4]) - nearby);
- if( d2<dist ){
- closest = i;
- dist = d2;
+ if( eMode==BTALLOC_LE ){
+ for(i=0; i<k; i++){
+ iPage = get4byte(&aData[8+i*4]);
+ if( iPage<=nearby ){
+ closest = i;
+ break;
+ }
+ }
+ }else{
+ int dist;
+ dist = sqlite3AbsInt32(get4byte(&aData[8]) - nearby);
+ for(i=1; i<k; i++){
+ int d2 = sqlite3AbsInt32(get4byte(&aData[8+i*4]) - nearby);
+ if( d2<dist ){
+ closest = i;
+ dist = d2;
+ }
}
}
}else{
@@ -52942,7 +54692,9 @@ static int allocateBtreePage(
goto end_allocate_page;
}
testcase( iPage==mxPage );
- if( !searchList || iPage==nearby ){
+ if( !searchList
+ || (iPage==nearby || (iPage<nearby && eMode==BTALLOC_LE))
+ ){
int noContent;
*pPgno = iPage;
TRACE(("ALLOCATE: %d was leaf %d of %d on trunk %d"
@@ -52955,7 +54707,7 @@ static int allocateBtreePage(
}
put4byte(&aData[4], k-1);
noContent = !btreeGetHasContent(pBt, *pPgno);
- rc = btreeGetPage(pBt, *pPgno, ppPage, noContent);
+ rc = btreeGetPage(pBt, *pPgno, ppPage, noContent, 0);
if( rc==SQLITE_OK ){
rc = sqlite3PagerWrite((*ppPage)->pDbPage);
if( rc!=SQLITE_OK ){
@@ -52969,8 +54721,26 @@ static int allocateBtreePage(
pPrevTrunk = 0;
}while( searchList );
}else{
- /* There are no pages on the freelist, so create a new page at the
- ** end of the file */
+ /* There are no pages on the freelist, so append a new page to the
+ ** database image.
+ **
+ ** Normally, new pages allocated by this block can be requested from the
+ ** pager layer with the 'no-content' flag set. This prevents the pager
+ ** from trying to read the pages content from disk. However, if the
+ ** current transaction has already run one or more incremental-vacuum
+ ** steps, then the page we are about to allocate may contain content
+ ** that is required in the event of a rollback. In this case, do
+ ** not set the no-content flag. This causes the pager to load and journal
+ ** the current page content before overwriting it.
+ **
+ ** Note that the pager will not actually attempt to load or journal
+ ** content for any page that really does lie past the end of the database
+ ** file on disk. So the effects of disabling the no-content optimization
+ ** 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));
+
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
if( rc ) return rc;
pBt->nPage++;
@@ -52985,7 +54755,7 @@ static int allocateBtreePage(
MemPage *pPg = 0;
TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", pBt->nPage));
assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) );
- rc = btreeGetPage(pBt, pBt->nPage, &pPg, 1);
+ rc = btreeGetPage(pBt, pBt->nPage, &pPg, bNoContent, 0);
if( rc==SQLITE_OK ){
rc = sqlite3PagerWrite(pPg->pDbPage);
releasePage(pPg);
@@ -52999,7 +54769,7 @@ static int allocateBtreePage(
*pPgno = pBt->nPage;
assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
- rc = btreeGetPage(pBt, *pPgno, ppPage, 1);
+ rc = btreeGetPage(pBt, *pPgno, ppPage, bNoContent, 0);
if( rc ) return rc;
rc = sqlite3PagerWrite((*ppPage)->pDbPage);
if( rc!=SQLITE_OK ){
@@ -53067,7 +54837,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
/* If the secure_delete option is enabled, then
** always fully overwrite deleted information with zeros.
*/
- if( (!pPage && ((rc = btreeGetPage(pBt, iPage, &pPage, 0))!=0) )
+ if( (!pPage && ((rc = btreeGetPage(pBt, iPage, &pPage, 0, 0))!=0) )
|| ((rc = sqlite3PagerWrite(pPage->pDbPage))!=0)
){
goto freepage_out;
@@ -53094,7 +54864,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
u32 nLeaf; /* Initial number of leaf cells on trunk page */
iTrunk = get4byte(&pPage1->aData[32]);
- rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0);
+ rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0, 0);
if( rc!=SQLITE_OK ){
goto freepage_out;
}
@@ -53140,7 +54910,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
** first trunk in the free-list is full. Either way, the page being freed
** will become the new first trunk page in the free-list.
*/
- if( pPage==0 && SQLITE_OK!=(rc = btreeGetPage(pBt, iPage, &pPage, 0)) ){
+ if( pPage==0 && SQLITE_OK!=(rc = btreeGetPage(pBt, iPage, &pPage, 0, 0)) ){
goto freepage_out;
}
rc = sqlite3PagerWrite(pPage->pDbPage);
@@ -53183,7 +54953,7 @@ static int clearCell(MemPage *pPage, unsigned char *pCell){
return SQLITE_OK; /* No overflow pages. Return without doing anything */
}
if( pCell+info.iOverflow+3 > pPage->aData+pPage->maskPage ){
- return SQLITE_CORRUPT; /* Cell extends past end of page */
+ return SQLITE_CORRUPT_BKPT; /* Cell extends past end of page */
}
ovflPgno = get4byte(&pCell[info.iOverflow]);
assert( pBt->usableSize > 4 );
@@ -53327,7 +55097,7 @@ static int fillInCell(
** If this is the first overflow page, then write a partial entry
** to the pointer-map. If we write nothing to this pointer-map slot,
** then the optimistic overflow chain processing in clearCell()
- ** may misinterpret the uninitialised values and delete the
+ ** may misinterpret the uninitialized values and delete the
** wrong pages from the database.
*/
if( pBt->autoVacuum && rc==SQLITE_OK ){
@@ -53639,7 +55409,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( 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
@@ -53941,7 +55711,7 @@ static int balance_nonroot(
}
pgno = get4byte(pRight);
while( 1 ){
- rc = getAndInitPage(pBt, pgno, &apOld[i]);
+ rc = getAndInitPage(pBt, pgno, &apOld[i], 0);
if( rc ){
memset(apOld, 0, (i+1)*sizeof(MemPage*));
goto balance_cleanup;
@@ -54800,7 +56570,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
insertCell(pPage, idx, newCell, szNew, 0, 0, &rc);
assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 );
- /* If no error has occured and pPage has an overflow cell, call balance()
+ /* If no error has occurred and pPage has an overflow cell, call balance()
** to redistribute the cells within the tree. Since balance() may move
** the cursor, zero the BtCursor.info.nSize and BtCursor.validNKey
** variables.
@@ -55014,7 +56784,7 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
** be moved to the allocated page (unless the allocated page happens
** to reside at pgnoRoot).
*/
- rc = allocateBtreePage(pBt, &pPageMove, &pgnoMove, pgnoRoot, 1);
+ rc = allocateBtreePage(pBt, &pPageMove, &pgnoMove, pgnoRoot, BTALLOC_EXACT);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -55029,10 +56799,17 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
u8 eType = 0;
Pgno iPtrPage = 0;
+ /* Save the positions of any open cursors. This is required in
+ ** case they are holding a reference to an xFetch reference
+ ** corresponding to page pgnoRoot. */
+ rc = saveAllCursors(pBt, 0, 0);
releasePage(pPageMove);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
/* Move the page currently at pgnoRoot to pgnoMove. */
- rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0);
+ rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0, 0);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -55053,7 +56830,7 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
if( rc!=SQLITE_OK ){
return rc;
}
- rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0);
+ rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0, 0);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -55129,7 +56906,7 @@ static int clearDatabasePage(
return SQLITE_CORRUPT_BKPT;
}
- rc = getAndInitPage(pBt, pgno, &pPage);
+ rc = getAndInitPage(pBt, pgno, &pPage, 0);
if( rc ) return rc;
for(i=0; i<pPage->nCell; i++){
pCell = findCell(pPage, i);
@@ -55231,7 +57008,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
return SQLITE_LOCKED_SHAREDCACHE;
}
- rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0);
+ rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0, 0);
if( rc ) return rc;
rc = sqlite3BtreeClearTable(p, iTable, 0);
if( rc ){
@@ -55266,7 +57043,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
*/
MemPage *pMove;
releasePage(pPage);
- rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0);
+ rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0, 0);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -55276,7 +57053,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
return rc;
}
pMove = 0;
- rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0);
+ rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0, 0);
freePage(pMove, &rc);
releasePage(pMove);
if( rc!=SQLITE_OK ){
@@ -55688,7 +57465,7 @@ static int checkTreePage(
usableSize = pBt->usableSize;
if( iPage==0 ) return 0;
if( checkRef(pCheck, iPage, zParentContext) ) return 0;
- if( (rc = btreeGetPage(pBt, (Pgno)iPage, &pPage, 0))!=0 ){
+ if( (rc = btreeGetPage(pBt, (Pgno)iPage, &pPage, 0, 0))!=0 ){
checkAppendMsg(pCheck, zContext,
"unable to get the page. error code=%d", rc);
return 0;
@@ -55921,7 +57698,7 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
}
i = PENDING_BYTE_PAGE(pBt);
if( i<=sCheck.nPage ) setPageReferenced(&sCheck, i);
- sqlite3StrAccumInit(&sCheck.errMsg, zErr, sizeof(zErr), 20000);
+ sqlite3StrAccumInit(&sCheck.errMsg, zErr, sizeof(zErr), SQLITE_MAX_LENGTH);
sCheck.errMsg.useMalloc = 2;
/* Check the integrity of the freelist
@@ -56160,6 +57937,17 @@ SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void
return SQLITE_ABORT;
}
+ /* Save the positions of all other cursors open on this table. This is
+ ** 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()
+ ** and hence saveAllCursors() cannot fail on a BTREE_INTKEY table, hence
+ ** saveAllCursors can only return SQLITE_OK.
+ */
+ VVA_ONLY(rc =) saveAllCursors(pCsr->pBt, pCsr->pgnoRoot, pCsr);
+ assert( rc==SQLITE_OK );
+
/* Check some assumptions:
** (a) the cursor is open for writing,
** (b) there is a read/write transaction open,
@@ -56456,20 +58244,28 @@ static int isFatalError(int rc){
** page iSrcPg from the source database. Copy this data into the
** destination database.
*/
-static int backupOnePage(sqlite3_backup *p, Pgno iSrcPg, const u8 *zSrcData){
+static int backupOnePage(
+ sqlite3_backup *p, /* Backup handle */
+ Pgno iSrcPg, /* Source database page to backup */
+ const u8 *zSrcData, /* Source database page data */
+ int bUpdate /* True for an update, false otherwise */
+){
Pager * const pDestPager = sqlite3BtreePager(p->pDest);
const int nSrcPgsz = sqlite3BtreeGetPageSize(p->pSrc);
int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest);
const int nCopy = MIN(nSrcPgsz, nDestPgsz);
const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz;
#ifdef SQLITE_HAS_CODEC
- int nSrcReserve = sqlite3BtreeGetReserve(p->pSrc);
+ /* Use BtreeGetReserveNoMutex() for the source b-tree, as although it is
+ ** 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);
#endif
-
int rc = SQLITE_OK;
i64 iOff;
+ assert( sqlite3BtreeGetReserveNoMutex(p->pSrc)>=0 );
assert( p->bDestLocked );
assert( !isFatalError(p->rc) );
assert( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) );
@@ -56526,6 +58322,9 @@ static int backupOnePage(sqlite3_backup *p, Pgno iSrcPg, const u8 *zSrcData){
*/
memcpy(zOut, zIn, nCopy);
((u8 *)sqlite3PagerGetExtra(pDestPg))[0] = 0;
+ if( iOff==0 && bUpdate==0 ){
+ sqlite3Put4byte(&zOut[28], sqlite3BtreeLastPage(p->pSrc));
+ }
}
sqlite3PagerUnref(pDestPg);
}
@@ -56630,9 +58429,10 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
const Pgno iSrcPg = p->iNext; /* Source page number */
if( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ){
DbPage *pSrcPg; /* Source page object */
- rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg);
+ rc = sqlite3PagerAcquire(pSrcPager, iSrcPg, &pSrcPg,
+ PAGER_ACQUIRE_READONLY);
if( rc==SQLITE_OK ){
- rc = backupOnePage(p, iSrcPg, sqlite3PagerGetData(pSrcPg));
+ rc = backupOnePage(p, iSrcPg, sqlite3PagerGetData(pSrcPg), 0);
sqlite3PagerUnref(pSrcPg);
}
}
@@ -56654,7 +58454,13 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
** same schema version.
*/
if( rc==SQLITE_DONE ){
- rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1);
+ if( nSrcPage==0 ){
+ rc = sqlite3BtreeNewDb(p->pDest);
+ nSrcPage = 1;
+ }
+ if( rc==SQLITE_OK || rc==SQLITE_DONE ){
+ rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1);
+ }
if( rc==SQLITE_OK ){
if( p->pDestDb ){
sqlite3ResetAllSchemasOfConnection(p->pDestDb);
@@ -56688,7 +58494,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
}else{
nDestTruncate = nSrcPage * (pgszSrc/pgszDest);
}
- sqlite3PagerTruncateImage(pDestPager, nDestTruncate);
+ assert( nDestTruncate>0 );
if( pgszSrc<pgszDest ){
/* If the source page-size is smaller than the destination page-size,
@@ -56702,22 +58508,38 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
*/
const i64 iSize = (i64)pgszSrc * (i64)nSrcPage;
sqlite3_file * const pFile = sqlite3PagerFile(pDestPager);
+ Pgno iPg;
+ int nDstPage;
i64 iOff;
i64 iEnd;
assert( pFile );
- assert( (i64)nDestTruncate*(i64)pgszDest >= iSize || (
+ assert( nDestTruncate==0
+ || (i64)nDestTruncate*(i64)pgszDest >= iSize || (
nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1)
&& iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest
));
- /* This call ensures that all data required to recreate the original
+ /* This block ensures that all data required to recreate the original
** database has been stored in the journal for pDestPager and the
** journal synced to disk. So at this point we may safely modify
** the database file in any way, knowing that if a power failure
** occurs, the original database will be reconstructed from the
** journal file. */
- rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1);
+ sqlite3PagerPagecount(pDestPager, &nDstPage);
+ for(iPg=nDestTruncate; rc==SQLITE_OK && iPg<=(Pgno)nDstPage; iPg++){
+ if( iPg!=PENDING_BYTE_PAGE(p->pDest->pBt) ){
+ DbPage *pPg;
+ rc = sqlite3PagerGet(pDestPager, iPg, &pPg);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3PagerWrite(pPg);
+ sqlite3PagerUnref(pPg);
+ }
+ }
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1);
+ }
/* Write the extra pages and truncate the database file as required */
iEnd = MIN(PENDING_BYTE + pgszDest, iSize);
@@ -56744,6 +58566,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
rc = sqlite3PagerSync(pDestPager);
}
}else{
+ sqlite3PagerTruncateImage(pDestPager, nDestTruncate);
rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 0);
}
@@ -56872,7 +58695,7 @@ SQLITE_PRIVATE void sqlite3BackupUpdate(sqlite3_backup *pBackup, Pgno iPage, con
int rc;
assert( p->pDestDb );
sqlite3_mutex_enter(p->pDestDb->mutex);
- rc = backupOnePage(p, iPage, aData);
+ rc = backupOnePage(p, iPage, aData, 1);
sqlite3_mutex_leave(p->pDestDb->mutex);
assert( rc!=SQLITE_BUSY && rc!=SQLITE_LOCKED );
if( rc!=SQLITE_OK ){
@@ -56995,7 +58818,9 @@ copy_finished:
** between formats.
*/
SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
+#ifndef SQLITE_OMIT_UTF16
int rc;
+#endif
assert( (pMem->flags&MEM_RowSet)==0 );
assert( desiredEnc==SQLITE_UTF8 || desiredEnc==SQLITE_UTF16LE
|| desiredEnc==SQLITE_UTF16BE );
@@ -58140,18 +59965,6 @@ SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){
** But that file was getting too big so this subroutines were split out.
*/
-
-
-/*
-** When debugging the code generator in a symbolic debugger, one can
-** set the sqlite3VdbeAddopTrace to 1 and all opcodes will be printed
-** as they are added to the instruction stream.
-*/
-#ifdef SQLITE_DEBUG
-SQLITE_PRIVATE int sqlite3VdbeAddopTrace = 0;
-#endif
-
-
/*
** Create a new virtual database engine.
*/
@@ -58176,7 +59989,7 @@ SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(sqlite3 *db){
SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepareV2){
assert( isPrepareV2==1 || isPrepareV2==0 );
if( p==0 ) return;
-#ifdef SQLITE_OMIT_TRACE
+#if defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_ENABLE_SQLLOG)
if( !isPrepareV2 ) return;
#endif
assert( p->zSql==0 );
@@ -58281,7 +60094,9 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
pOp->p4type = P4_NOTUSED;
#ifdef SQLITE_DEBUG
pOp->zComment = 0;
- if( sqlite3VdbeAddopTrace ) sqlite3VdbePrintOp(0, i, &p->aOp[i]);
+ if( p->db->flags & SQLITE_VdbeAddopTrace ){
+ sqlite3VdbePrintOp(0, i, &p->aOp[i]);
+ }
#endif
#ifdef VDBE_PROFILE
pOp->cycles = 0;
@@ -58500,7 +60315,7 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
|| (opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1)
#endif
|| ((opcode==OP_Halt || opcode==OP_HaltIfNull)
- && (pOp->p1==SQLITE_CONSTRAINT && pOp->p2==OE_Abort))
+ && ((pOp->p1&0xff)==SQLITE_CONSTRAINT && pOp->p2==OE_Abort))
){
hasAbort = 1;
break;
@@ -58508,7 +60323,7 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
}
sqlite3DbFree(v->db, sIter.apSub);
- /* Return true if hasAbort==mayAbort. Or if a malloc failure occured.
+ /* Return true if hasAbort==mayAbort. Or if a malloc failure occurred.
** If malloc failed, then the while() loop above may not have iterated
** through all opcodes and hasAbort may be set incorrectly. Return
** true for this case to prevent the assert() in the callers frame
@@ -58635,7 +60450,7 @@ SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp)
pOut->p5 = 0;
#ifdef SQLITE_DEBUG
pOut->zComment = 0;
- if( sqlite3VdbeAddopTrace ){
+ if( p->db->flags & SQLITE_VdbeAddopTrace ){
sqlite3VdbePrintOp(0, i+addr, &p->aOp[i+addr]);
}
#endif
@@ -58846,6 +60661,7 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int
addr = p->nOp - 1;
}
pOp = &p->aOp[addr];
+ assert( pOp->p4type==P4_NOTUSED || pOp->p4type==P4_INT32 );
freeP4(db, pOp->p4type, pOp->p4.p);
pOp->p4.p = 0;
if( n==P4_INT32 ){
@@ -58868,10 +60684,9 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int
u8 *aSortOrder;
memcpy((char*)pKeyInfo, zP4, nByte - nField);
aSortOrder = pKeyInfo->aSortOrder;
- if( aSortOrder ){
- pKeyInfo->aSortOrder = (unsigned char*)&pKeyInfo->aColl[nField];
- memcpy(pKeyInfo->aSortOrder, aSortOrder, nField);
- }
+ assert( aSortOrder!=0 );
+ pKeyInfo->aSortOrder = (unsigned char*)&pKeyInfo->aColl[nField];
+ memcpy(pKeyInfo->aSortOrder, aSortOrder, nField);
pOp->p4type = P4_KEYINFO;
}else{
p->db->mallocFailed = 1;
@@ -58984,26 +60799,23 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
case P4_KEYINFO: {
int i, j;
KeyInfo *pKeyInfo = pOp->p4.pKeyInfo;
+ assert( pKeyInfo->aSortOrder!=0 );
sqlite3_snprintf(nTemp, zTemp, "keyinfo(%d", pKeyInfo->nField);
i = sqlite3Strlen30(zTemp);
for(j=0; j<pKeyInfo->nField; j++){
CollSeq *pColl = pKeyInfo->aColl[j];
- if( pColl ){
- int n = sqlite3Strlen30(pColl->zName);
- if( i+n>nTemp-6 ){
- memcpy(&zTemp[i],",...",4);
- break;
- }
- zTemp[i++] = ',';
- if( pKeyInfo->aSortOrder && pKeyInfo->aSortOrder[j] ){
- zTemp[i++] = '-';
- }
- memcpy(&zTemp[i], pColl->zName,n+1);
- i += n;
- }else if( i+4<nTemp-6 ){
- memcpy(&zTemp[i],",nil",4);
- i += 4;
+ const char *zColl = pColl ? pColl->zName : "nil";
+ int n = sqlite3Strlen30(zColl);
+ if( i+n>nTemp-6 ){
+ memcpy(&zTemp[i],",...",4);
+ break;
}
+ zTemp[i++] = ',';
+ if( pKeyInfo->aSortOrder[j] ){
+ zTemp[i++] = '-';
+ }
+ memcpy(&zTemp[i], zColl, n+1);
+ i += n;
}
zTemp[i++] = ')';
zTemp[i] = 0;
@@ -59664,7 +61476,7 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
zEnd = &zCsr[nByte];
}while( nByte && !db->mallocFailed );
- p->nCursor = (u16)nCursor;
+ p->nCursor = nCursor;
p->nOnceFlag = nOnce;
if( p->aVar ){
p->nVar = (ynVar)nVar;
@@ -59893,7 +61705,9 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
if( sqlite3BtreeIsInTrans(pBt) ){
needXcommit = 1;
if( i!=1 ) nTrans++;
+ sqlite3BtreeEnter(pBt);
rc = sqlite3PagerExclusiveLock(sqlite3BtreePager(pBt));
+ sqlite3BtreeLeave(pBt);
}
}
if( rc!=SQLITE_OK ){
@@ -59904,7 +61718,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
if( needXcommit && db->xCommitCallback ){
rc = db->xCommitCallback(db->pCommitArg);
if( rc ){
- return SQLITE_CONSTRAINT;
+ return SQLITE_CONSTRAINT_COMMITHOOK;
}
}
@@ -60141,7 +61955,7 @@ SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){
/* If p->iStatement is greater than zero, then this Vdbe opened a
** statement transaction that should be closed here. The only exception
- ** is that an IO error may have occured, causing an emergency rollback.
+ ** is that an IO error may have occurred, causing an emergency rollback.
** In this case (db->nStatement==0), and there is nothing to do.
*/
if( db->nStatement && p->iStatement ){
@@ -60196,14 +62010,14 @@ SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){
** violations, return SQLITE_ERROR. Otherwise, SQLITE_OK.
**
** If there are outstanding FK violations and this function returns
-** SQLITE_ERROR, set the result of the VM to SQLITE_CONSTRAINT and write
-** an error message to it. Then return SQLITE_ERROR.
+** SQLITE_ERROR, set the result of the VM to SQLITE_CONSTRAINT_FOREIGNKEY
+** and write an error message to it. Then return SQLITE_ERROR.
*/
#ifndef SQLITE_OMIT_FOREIGN_KEY
SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *p, int deferred){
sqlite3 *db = p->db;
if( (deferred && db->nDeferredCons>0) || (!deferred && p->nFkConstraint>0) ){
- p->rc = SQLITE_CONSTRAINT;
+ p->rc = SQLITE_CONSTRAINT_FOREIGNKEY;
p->errorAction = OE_Abort;
sqlite3SetString(&p->zErrMsg, db, "foreign key constraint failed");
return SQLITE_ERROR;
@@ -60277,7 +62091,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
**
** Even if the statement is read-only, it is important to perform
** a statement or transaction rollback operation. If the error
- ** occured while writing to the journal, sub-journal or database
+ ** occurred while writing to the journal, sub-journal or database
** file as part of an effort to free up cache space (see function
** pagerStress() in pager.c), the rollback is required to restore
** the pager to a consistent state.
@@ -60318,7 +62132,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
sqlite3VdbeLeave(p);
return SQLITE_ERROR;
}
- rc = SQLITE_CONSTRAINT;
+ rc = SQLITE_CONSTRAINT_FOREIGNKEY;
}else{
/* The auto-commit flag is true, the vdbe program was successful
** or hit an 'OR FAIL' constraint and there are no deferred foreign
@@ -60361,7 +62175,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
if( eStatementOp ){
rc = sqlite3VdbeCloseStatement(p, eStatementOp);
if( rc ){
- if( p->rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT ){
+ if( p->rc==SQLITE_OK || (p->rc&0xff)==SQLITE_CONSTRAINT ){
p->rc = rc;
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = 0;
@@ -60447,6 +62261,27 @@ SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p){
return rc;
}
+#ifdef SQLITE_ENABLE_SQLLOG
+/*
+** If an SQLITE_CONFIG_SQLLOG hook is registered and the VM has been run,
+** invoke it.
+*/
+static void vdbeInvokeSqllog(Vdbe *v){
+ if( sqlite3GlobalConfig.xSqllog && v->rc==SQLITE_OK && v->zSql && v->pc>=0 ){
+ char *zExpanded = sqlite3VdbeExpandSql(v, v->zSql);
+ assert( v->db->init.busy==0 );
+ if( zExpanded ){
+ sqlite3GlobalConfig.xSqllog(
+ sqlite3GlobalConfig.pSqllogArg, v->db, zExpanded, 1
+ );
+ sqlite3DbFree(v->db, zExpanded);
+ }
+ }
+}
+#else
+# define vdbeInvokeSqllog(x)
+#endif
+
/*
** Clean up a VDBE after execution but do not delete the VDBE just yet.
** Write any error messages into *pzErrMsg. Return the result code.
@@ -60474,6 +62309,7 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){
** instructions yet, leave the main database error information unchanged.
*/
if( p->pc>=0 ){
+ vdbeInvokeSqllog(p);
sqlite3VdbeTransferError(p);
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = 0;
@@ -60555,12 +62391,14 @@ SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(VdbeFunc *pVdbeFunc, int mask){
}
/*
-** Free all memory associated with the Vdbe passed as the second argument.
+** Free all memory associated with the Vdbe passed as the second argument,
+** except for object itself, which is preserved.
+**
** The difference between this function and sqlite3VdbeDelete() is that
** VdbeDelete() also unlinks the Vdbe from the list of VMs associated with
-** the database connection.
+** the database connection and frees the object itself.
*/
-SQLITE_PRIVATE void sqlite3VdbeDeleteObject(sqlite3 *db, Vdbe *p){
+SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
SubProgram *pSub, *pNext;
int i;
assert( p->db==0 || p->db==db );
@@ -60581,7 +62419,6 @@ SQLITE_PRIVATE void sqlite3VdbeDeleteObject(sqlite3 *db, Vdbe *p){
sqlite3DbFree(db, p->zExplain);
sqlite3DbFree(db, p->pExplain);
#endif
- sqlite3DbFree(db, p);
}
/*
@@ -60593,6 +62430,7 @@ SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe *p){
if( NEVER(p==0) ) return;
db = p->db;
assert( sqlite3_mutex_held(db->mutex) );
+ sqlite3VdbeClearObject(db, p);
if( p->pPrev ){
p->pPrev->pNext = p->pNext;
}else{
@@ -60604,7 +62442,7 @@ SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe *p){
}
p->magic = VDBE_MAGIC_DEAD;
p->db = 0;
- sqlite3VdbeDeleteObject(db, p);
+ sqlite3DbFree(db, p);
}
/*
@@ -60667,7 +62505,7 @@ SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor *p){
** the blob of data that it corresponds to. In a table record, all serial
** types are stored at the start of the record, and the blobs of data at
** the end. Hence these functions allow the caller to handle the
-** serial-type and data blob seperately.
+** serial-type and data blob separately.
**
** The following table describes the various storage classes for data:
**
@@ -60706,9 +62544,6 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
# define MAX_6BYTE ((((i64)0x00008000)<<32)-1)
i64 i = pMem->u.i;
u64 u;
- if( file_format>=4 && (i&1)==i ){
- return 8+(u32)i;
- }
if( i<0 ){
if( i<(-MAX_6BYTE) ) return 6;
/* Previous test prevents: u = -(-9223372036854775808) */
@@ -60716,7 +62551,9 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
}else{
u = i;
}
- if( u<=127 ) return 1;
+ if( u<=127 ){
+ return ((i&1)==i && file_format>=4) ? 8+(u32)u : 1;
+ }
if( u<=32767 ) return 2;
if( u<=8388607 ) return 3;
if( u<=2147483647 ) return 4;
@@ -61001,6 +62838,7 @@ SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(
}
p->aMem = (Mem*)&((char*)p)[ROUND8(sizeof(UnpackedRecord))];
+ assert( pKeyInfo->aSortOrder!=0 );
p->pKeyInfo = pKeyInfo;
p->nField = pKeyInfo->nField + 1;
return p;
@@ -61094,6 +62932,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare(
idx1 = getVarint32(aKey1, szHdr1);
d1 = szHdr1;
nField = pKeyInfo->nField;
+ assert( pKeyInfo->aSortOrder!=0 );
while( idx1<szHdr1 && i<pPKey2->nField ){
u32 serial_type1;
@@ -61113,7 +62952,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare(
assert( mem1.zMalloc==0 ); /* See comment below */
/* Invert the result if we are using DESC sort order. */
- if( pKeyInfo->aSortOrder && i<nField && pKeyInfo->aSortOrder[i] ){
+ if( i<nField && pKeyInfo->aSortOrder[i] ){
rc = -rc;
}
@@ -61806,7 +63645,7 @@ end_of_step:
assert( p->rc!=SQLITE_ROW && p->rc!=SQLITE_DONE );
if( p->isPrepareV2 && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
/* If this statement was prepared using sqlite3_prepare_v2(), and an
- ** error has occured, then return the error code in p->rc to the
+ ** error has occurred, then return the error code in p->rc to the
** caller. Set the error code in the database handle to the same value.
*/
rc = sqlite3VdbeTransferError(p);
@@ -61815,14 +63654,6 @@ end_of_step:
}
/*
-** 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 5
-#endif
-
-/*
** This is the top-level implementation of sqlite3_step(). Call
** sqlite3Step() to do most of the work. If a schema error occurs,
** call sqlite3Reprepare() and try again.
@@ -61839,10 +63670,12 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){
}
db = v->db;
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 ){
sqlite3_reset(pStmt);
+ v->doingRerun = 1;
assert( v->expired==0 );
}
if( rc2!=SQLITE_OK && ALWAYS(v->isPrepareV2) && ALWAYS(db->pErr) ){
@@ -62557,7 +64390,7 @@ SQLITE_PRIVATE int sqlite3VdbeParameterIndex(Vdbe *p, const char *zName, int nNa
if( zName ){
for(i=0; i<p->nzVar; i++){
const char *z = p->azVar[i];
- if( z && memcmp(z,zName,nName)==0 && z[nName]==0 ){
+ if( z && strncmp(z,zName,nName)==0 && z[nName]==0 ){
return i+1;
}
}
@@ -62723,6 +64556,11 @@ static int findNextHostParameter(const char *zSql, int *pnToken){
** then the returned string holds a copy of zRawSql with "-- " prepended
** to each line of text.
**
+** If the SQLITE_TRACE_SIZE_LIMIT macro is defined to an integer, then
+** then long strings and blobs are truncated to that many bytes. This
+** can be used to prevent unreasonably large trace strings when dealing
+** with large (multi-megabyte) strings and blobs.
+**
** The calling function is responsible for making sure the memory returned
** is eventually freed.
**
@@ -62793,30 +64631,49 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
}else if( pVar->flags & MEM_Real ){
sqlite3XPrintf(&out, "%!.15g", pVar->r);
}else if( pVar->flags & MEM_Str ){
+ int nOut; /* Number of bytes of the string text to include in output */
#ifndef SQLITE_OMIT_UTF16
u8 enc = ENC(db);
+ Mem utf8;
if( enc!=SQLITE_UTF8 ){
- Mem utf8;
memset(&utf8, 0, sizeof(utf8));
utf8.db = db;
sqlite3VdbeMemSetStr(&utf8, pVar->z, pVar->n, enc, SQLITE_STATIC);
sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8);
- sqlite3XPrintf(&out, "'%.*q'", utf8.n, utf8.z);
- sqlite3VdbeMemRelease(&utf8);
- }else
+ pVar = &utf8;
+ }
#endif
- {
- sqlite3XPrintf(&out, "'%.*q'", pVar->n, pVar->z);
+ nOut = pVar->n;
+#ifdef SQLITE_TRACE_SIZE_LIMIT
+ if( nOut>SQLITE_TRACE_SIZE_LIMIT ){
+ nOut = SQLITE_TRACE_SIZE_LIMIT;
+ while( nOut<pVar->n && (pVar->z[nOut]&0xc0)==0x80 ){ nOut++; }
}
+#endif
+ sqlite3XPrintf(&out, "'%.*q'", nOut, pVar->z);
+#ifdef SQLITE_TRACE_SIZE_LIMIT
+ if( nOut<pVar->n ) sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-nOut);
+#endif
+#ifndef SQLITE_OMIT_UTF16
+ if( enc!=SQLITE_UTF8 ) sqlite3VdbeMemRelease(&utf8);
+#endif
}else if( pVar->flags & MEM_Zero ){
sqlite3XPrintf(&out, "zeroblob(%d)", pVar->u.nZero);
}else{
+ int nOut; /* Number of bytes of the blob to include in output */
assert( pVar->flags & MEM_Blob );
sqlite3StrAccumAppend(&out, "x'", 2);
- for(i=0; i<pVar->n; i++){
+ nOut = pVar->n;
+#ifdef SQLITE_TRACE_SIZE_LIMIT
+ if( nOut>SQLITE_TRACE_SIZE_LIMIT ) nOut = SQLITE_TRACE_SIZE_LIMIT;
+#endif
+ for(i=0; i<nOut; i++){
sqlite3XPrintf(&out, "%02x", pVar->z[i]&0xff);
}
sqlite3StrAccumAppend(&out, "'", 1);
+#ifdef SQLITE_TRACE_SIZE_LIMIT
+ if( nOut<pVar->n ) sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-nOut);
+#endif
}
}
}
@@ -63094,11 +64951,7 @@ SQLITE_API int sqlite3_found_count = 0;
&& sqlite3VdbeMemMakeWriteable(P) ){ goto no_mem;}
/* Return true if the cursor was opened using the OP_OpenSorter opcode. */
-#ifdef SQLITE_OMIT_MERGE_SORT
-# define isSorter(x) 0
-#else
# define isSorter(x) ((x)->pSorter!=0)
-#endif
/*
** Argument pMem points at a register that will be passed to a
@@ -63364,7 +65217,9 @@ SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){
** Print the value of a register for tracing purposes:
*/
static void memTracePrint(FILE *out, Mem *p){
- if( p->flags & MEM_Null ){
+ if( p->flags & MEM_Invalid ){
+ fprintf(out, " undefined");
+ }else if( p->flags & MEM_Null ){
fprintf(out, " NULL");
}else if( (p->flags & (MEM_Int|MEM_Str))==(MEM_Int|MEM_Str) ){
fprintf(out, " si:%lld", p->u.i);
@@ -63615,6 +65470,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
} aa;
struct OP_Null_stack_vars {
int cnt;
+ u16 nullFlag;
} ab;
struct OP_Variable_stack_vars {
Mem *pVar; /* Value being transferred */
@@ -63625,39 +65481,43 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
int p1; /* Register to copy from */
int p2; /* Register to copy to */
} ad;
+ struct OP_Copy_stack_vars {
+ int n;
+ } ae;
struct OP_ResultRow_stack_vars {
Mem *pMem;
int i;
- } ae;
+ } af;
struct OP_Concat_stack_vars {
i64 nByte;
- } af;
+ } ag;
struct OP_Remainder_stack_vars {
+ char bIntint; /* Started out as two integer operands */
int flags; /* Combined MEM_* flags from both inputs */
i64 iA; /* Integer value of left operand */
i64 iB; /* Integer value of right operand */
double rA; /* Real value of left operand */
double rB; /* Real value of right operand */
- } ag;
+ } ah;
struct OP_Function_stack_vars {
int i;
Mem *pArg;
sqlite3_context ctx;
sqlite3_value **apVal;
int n;
- } ah;
+ } ai;
struct OP_ShiftRight_stack_vars {
i64 iA;
u64 uA;
i64 iB;
u8 op;
- } ai;
+ } aj;
struct OP_Ge_stack_vars {
int res; /* Result of the comparison of pIn1 against pIn3 */
char affinity; /* Affinity to use for comparison */
u16 flags1; /* Copy of initial value of pIn1->flags */
u16 flags3; /* Copy of initial value of pIn3->flags */
- } aj;
+ } ak;
struct OP_Compare_stack_vars {
int n;
int i;
@@ -63667,14 +65527,14 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
int idx;
CollSeq *pColl; /* Collating sequence to use on this term */
int bRev; /* True for DESCENDING sort order */
- } ak;
+ } al;
struct OP_Or_stack_vars {
int v1; /* Left operand: 0==FALSE, 1==TRUE, 2==UNKNOWN or NULL */
int v2; /* Right operand: 0==FALSE, 1==TRUE, 2==UNKNOWN or NULL */
- } al;
+ } am;
struct OP_IfNot_stack_vars {
int c;
- } am;
+ } an;
struct OP_Column_stack_vars {
u32 payloadSize; /* Number of bytes in the record */
i64 payloadSize64; /* Number of bytes in the record */
@@ -63699,11 +65559,11 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
int avail; /* Number of bytes of available data */
u32 t; /* A type code from the record header */
Mem *pReg; /* PseudoTable input register */
- } an;
+ } ao;
struct OP_Affinity_stack_vars {
const char *zAffinity; /* The affinity to be applied */
char cAff; /* A single character of affinity */
- } ao;
+ } ap;
struct OP_MakeRecord_stack_vars {
u8 *zNewRecord; /* A buffer to hold the data for the new record */
Mem *pRec; /* The new record */
@@ -63720,11 +65580,11 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
int file_format; /* File format to use for encoding */
int i; /* Space used in zNewRecord[] */
int len; /* Length of a field */
- } ap;
+ } aq;
struct OP_Count_stack_vars {
i64 nEntry;
BtCursor *pCrsr;
- } aq;
+ } ar;
struct OP_Savepoint_stack_vars {
int p1; /* Value of P1 operand */
char *zName; /* Name of savepoint */
@@ -63734,28 +65594,28 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
Savepoint *pTmp;
int iSavepoint;
int ii;
- } ar;
+ } as;
struct OP_AutoCommit_stack_vars {
int desiredAutoCommit;
int iRollback;
int turnOnAC;
- } as;
+ } at;
struct OP_Transaction_stack_vars {
Btree *pBt;
- } at;
+ } au;
struct OP_ReadCookie_stack_vars {
int iMeta;
int iDb;
int iCookie;
- } au;
+ } av;
struct OP_SetCookie_stack_vars {
Db *pDb;
- } av;
+ } aw;
struct OP_VerifyCookie_stack_vars {
int iMeta;
int iGen;
Btree *pBt;
- } aw;
+ } ax;
struct OP_OpenWrite_stack_vars {
int nField;
KeyInfo *pKeyInfo;
@@ -63765,16 +65625,16 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
Btree *pX;
VdbeCursor *pCur;
Db *pDb;
- } ax;
+ } ay;
struct OP_OpenEphemeral_stack_vars {
VdbeCursor *pCx;
- } ay;
+ } az;
struct OP_SorterOpen_stack_vars {
VdbeCursor *pCx;
- } az;
+ } ba;
struct OP_OpenPseudo_stack_vars {
VdbeCursor *pCx;
- } ba;
+ } bb;
struct OP_SeekGt_stack_vars {
int res;
int oc;
@@ -63782,10 +65642,10 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
UnpackedRecord r;
int nField;
i64 iKey; /* The rowid we are to seek to */
- } bb;
+ } bc;
struct OP_Seek_stack_vars {
VdbeCursor *pC;
- } bc;
+ } bd;
struct OP_Found_stack_vars {
int alreadyExists;
VdbeCursor *pC;
@@ -63794,7 +65654,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
UnpackedRecord *pIdxKey;
UnpackedRecord r;
char aTempRec[ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*3 + 7];
- } bd;
+ } be;
struct OP_IsUnique_stack_vars {
u16 ii;
VdbeCursor *pCx;
@@ -63803,13 +65663,13 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
Mem *aMx;
UnpackedRecord r; /* B-Tree index search key */
i64 R; /* Rowid stored in register P3 */
- } be;
+ } bf;
struct OP_NotExists_stack_vars {
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
u64 iKey;
- } bf;
+ } bg;
struct OP_NewRowid_stack_vars {
i64 v; /* The new rowid */
VdbeCursor *pC; /* Cursor of table to get the new rowid */
@@ -63817,7 +65677,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
int cnt; /* Counter to limit the number of searches */
Mem *pMem; /* Register holding largest rowid for AUTOINCREMENT */
VdbeFrame *pFrame; /* Root frame of VDBE */
- } bg;
+ } bh;
struct OP_InsertInt_stack_vars {
Mem *pData; /* MEM cell holding data for the record to be inserted */
Mem *pKey; /* MEM cell holding key for the record */
@@ -63828,89 +65688,89 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
const char *zDb; /* database name - used by the update hook */
const char *zTbl; /* Table name - used by the opdate hook */
int op; /* Opcode for update hook: SQLITE_UPDATE or SQLITE_INSERT */
- } bh;
+ } bi;
struct OP_Delete_stack_vars {
i64 iKey;
VdbeCursor *pC;
- } bi;
+ } bj;
struct OP_SorterCompare_stack_vars {
VdbeCursor *pC;
int res;
- } bj;
+ } bk;
struct OP_SorterData_stack_vars {
VdbeCursor *pC;
- } bk;
+ } bl;
struct OP_RowData_stack_vars {
VdbeCursor *pC;
BtCursor *pCrsr;
u32 n;
i64 n64;
- } bl;
+ } bm;
struct OP_Rowid_stack_vars {
VdbeCursor *pC;
i64 v;
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
- } bm;
+ } bn;
struct OP_NullRow_stack_vars {
VdbeCursor *pC;
- } bn;
+ } bo;
struct OP_Last_stack_vars {
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
- } bo;
+ } bp;
struct OP_Rewind_stack_vars {
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
- } bp;
+ } bq;
struct OP_Next_stack_vars {
VdbeCursor *pC;
int res;
- } bq;
+ } br;
struct OP_IdxInsert_stack_vars {
VdbeCursor *pC;
BtCursor *pCrsr;
int nKey;
const char *zKey;
- } br;
+ } bs;
struct OP_IdxDelete_stack_vars {
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
UnpackedRecord r;
- } bs;
+ } bt;
struct OP_IdxRowid_stack_vars {
BtCursor *pCrsr;
VdbeCursor *pC;
i64 rowid;
- } bt;
+ } bu;
struct OP_IdxGE_stack_vars {
VdbeCursor *pC;
int res;
UnpackedRecord r;
- } bu;
+ } bv;
struct OP_Destroy_stack_vars {
int iMoved;
int iCnt;
Vdbe *pVdbe;
int iDb;
- } bv;
+ } bw;
struct OP_Clear_stack_vars {
int nChange;
- } bw;
+ } bx;
struct OP_CreateTable_stack_vars {
int pgno;
int flags;
Db *pDb;
- } bx;
+ } by;
struct OP_ParseSchema_stack_vars {
int iDb;
const char *zMaster;
char *zSql;
InitData initData;
- } by;
+ } bz;
struct OP_IntegrityCk_stack_vars {
int nRoot; /* Number of tables to check. (Number of root pages.) */
int *aRoot; /* Array of rootpage numbers for tables to be checked */
@@ -63918,14 +65778,14 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
int nErr; /* Number of errors reported */
char *z; /* Text of the error report */
Mem *pnErr; /* Register keeping track of errors remaining */
- } bz;
+ } ca;
struct OP_RowSetRead_stack_vars {
i64 val;
- } ca;
+ } cb;
struct OP_RowSetTest_stack_vars {
int iSet;
int exists;
- } cb;
+ } cc;
struct OP_Program_stack_vars {
int nMem; /* Number of memory registers for sub-program */
int nByte; /* Bytes of runtime space required for sub-program */
@@ -63935,15 +65795,15 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
VdbeFrame *pFrame; /* New vdbe frame to execute in */
SubProgram *pProgram; /* Sub-program to execute */
void *t; /* Token identifying trigger */
- } cc;
+ } cd;
struct OP_Param_stack_vars {
VdbeFrame *pFrame;
Mem *pIn;
- } cd;
+ } ce;
struct OP_MemMax_stack_vars {
Mem *pIn1;
VdbeFrame *pFrame;
- } ce;
+ } cf;
struct OP_AggStep_stack_vars {
int n;
int i;
@@ -63951,34 +65811,36 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
Mem *pRec;
sqlite3_context ctx;
sqlite3_value **apVal;
- } cf;
+ } cg;
struct OP_AggFinal_stack_vars {
Mem *pMem;
- } cg;
+ } ch;
struct OP_Checkpoint_stack_vars {
int i; /* Loop counter */
int aRes[3]; /* Results */
Mem *pMem; /* Write results here */
- } ch;
+ } ci;
struct OP_JournalMode_stack_vars {
Btree *pBt; /* Btree to change journal mode of */
Pager *pPager; /* Pager associated with pBt */
int eNew; /* New journal mode */
int eOld; /* The old journal mode */
+#ifndef SQLITE_OMIT_WAL
const char *zFilename; /* Name of database file for pPager */
- } ci;
+#endif
+ } cj;
struct OP_IncrVacuum_stack_vars {
Btree *pBt;
- } cj;
+ } ck;
struct OP_VBegin_stack_vars {
VTable *pVTab;
- } ck;
+ } cl;
struct OP_VOpen_stack_vars {
VdbeCursor *pCur;
sqlite3_vtab_cursor *pVtabCursor;
sqlite3_vtab *pVtab;
sqlite3_module *pModule;
- } cl;
+ } cm;
struct OP_VFilter_stack_vars {
int nArg;
int iQuery;
@@ -63991,23 +65853,23 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
int res;
int i;
Mem **apArg;
- } cm;
+ } cn;
struct OP_VColumn_stack_vars {
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
Mem *pDest;
sqlite3_context sContext;
- } cn;
+ } co;
struct OP_VNext_stack_vars {
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
int res;
VdbeCursor *pCur;
- } co;
+ } cp;
struct OP_VRename_stack_vars {
sqlite3_vtab *pVtab;
Mem *pName;
- } cp;
+ } cq;
struct OP_VUpdate_stack_vars {
sqlite3_vtab *pVtab;
sqlite3_module *pModule;
@@ -64016,11 +65878,11 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
sqlite_int64 rowid;
Mem **apArg;
Mem *pX;
- } cq;
+ } cr;
struct OP_Trace_stack_vars {
char *zTrace;
char *z;
- } cr;
+ } cs;
} u;
/* End automatically generated code
********************************************************************/
@@ -64322,7 +66184,7 @@ case OP_Halt: {
if( rc==SQLITE_BUSY ){
p->rc = rc = SQLITE_BUSY;
}else{
- assert( rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT );
+ assert( rc==SQLITE_OK || (p->rc&0xff)==SQLITE_CONSTRAINT );
assert( rc==SQLITE_OK || db->nDeferredCons>0 );
rc = p->rc ? SQLITE_ERROR : SQLITE_DONE;
}
@@ -64411,25 +66273,30 @@ case OP_String: { /* out2-prerelease */
break;
}
-/* Opcode: Null * P2 P3 * *
+/* Opcode: Null P1 P2 P3 * *
**
** Write a NULL into registers P2. If P3 greater than P2, then also write
-** NULL into register P3 and ever register in between P2 and P3. If P3
+** NULL into register P3 and every register in between P2 and P3. If P3
** is less than P2 (typically P3 is zero) then only register P2 is
-** set to NULL
+** set to NULL.
+**
+** If the P1 value is non-zero, then also set the MEM_Cleared flag so that
+** NULL values will not compare equal even if SQLITE_NULLEQ is set on
+** OP_Ne or OP_Eq.
*/
case OP_Null: { /* out2-prerelease */
#if 0 /* local variables moved into u.ab */
int cnt;
+ u16 nullFlag;
#endif /* local variables moved into u.ab */
u.ab.cnt = pOp->p3-pOp->p2;
assert( pOp->p3<=p->nMem );
- pOut->flags = MEM_Null;
+ pOut->flags = u.ab.nullFlag = pOp->p1 ? (MEM_Null|MEM_Cleared) : MEM_Null;
while( u.ab.cnt>0 ){
pOut++;
memAboutToChange(p, pOut);
VdbeMemRelease(pOut);
- pOut->flags = MEM_Null;
+ pOut->flags = u.ab.nullFlag;
u.ab.cnt--;
}
break;
@@ -64474,10 +66341,10 @@ case OP_Variable: { /* out2-prerelease */
/* Opcode: Move P1 P2 P3 * *
**
-** Move the values in register P1..P1+P3-1 over into
-** registers P2..P2+P3-1. Registers P1..P1+P1-1 are
+** Move the values in register P1..P1+P3 over into
+** registers P2..P2+P3. Registers P1..P1+P3 are
** left holding a NULL. It is an error for register ranges
-** P1..P1+P3-1 and P2..P2+P3-1 to overlap.
+** P1..P1+P3 and P2..P2+P3 to overlap.
*/
case OP_Move: {
#if 0 /* local variables moved into u.ad */
@@ -64487,7 +66354,7 @@ case OP_Move: {
int p2; /* Register to copy to */
#endif /* local variables moved into u.ad */
- u.ad.n = pOp->p3;
+ u.ad.n = pOp->p3 + 1;
u.ad.p1 = pOp->p1;
u.ad.p2 = pOp->p2;
assert( u.ad.n>0 && u.ad.p1>0 && u.ad.p2>0 );
@@ -64516,20 +66383,33 @@ case OP_Move: {
break;
}
-/* Opcode: Copy P1 P2 * * *
+/* Opcode: Copy P1 P2 P3 * *
**
-** Make a copy of register P1 into register P2.
+** Make a copy of registers P1..P1+P3 into registers P2..P2+P3.
**
** This instruction makes a deep copy of the value. A duplicate
** is made of any string or blob constant. See also OP_SCopy.
*/
-case OP_Copy: { /* in1, out2 */
+case OP_Copy: {
+#if 0 /* local variables moved into u.ae */
+ int n;
+#endif /* local variables moved into u.ae */
+
+ u.ae.n = pOp->p3;
pIn1 = &aMem[pOp->p1];
pOut = &aMem[pOp->p2];
assert( pOut!=pIn1 );
- sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem);
- Deephemeralize(pOut);
- REGISTER_TRACE(pOp->p2, pOut);
+ while( 1 ){
+ sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem);
+ Deephemeralize(pOut);
+#ifdef SQLITE_DEBUG
+ pOut->pScopyFrom = 0;
+#endif
+ REGISTER_TRACE(pOp->p2+pOp->p3-u.ae.n, pOut);
+ if( (u.ae.n--)==0 ) break;
+ pOut++;
+ pIn1++;
+ }
break;
}
@@ -64566,10 +66446,10 @@ case OP_SCopy: { /* in1, out2 */
** row.
*/
case OP_ResultRow: {
-#if 0 /* local variables moved into u.ae */
+#if 0 /* local variables moved into u.af */
Mem *pMem;
int i;
-#endif /* local variables moved into u.ae */
+#endif /* local variables moved into u.af */
assert( p->nResColumn==pOp->p2 );
assert( pOp->p1>0 );
assert( pOp->p1+pOp->p2<=p->nMem+1 );
@@ -64611,15 +66491,15 @@ case OP_ResultRow: {
** and have an assigned type. The results are de-ephemeralized as
** a side effect.
*/
- u.ae.pMem = p->pResultSet = &aMem[pOp->p1];
- for(u.ae.i=0; u.ae.i<pOp->p2; u.ae.i++){
- assert( memIsValid(&u.ae.pMem[u.ae.i]) );
- Deephemeralize(&u.ae.pMem[u.ae.i]);
- assert( (u.ae.pMem[u.ae.i].flags & MEM_Ephem)==0
- || (u.ae.pMem[u.ae.i].flags & (MEM_Str|MEM_Blob))==0 );
- sqlite3VdbeMemNulTerminate(&u.ae.pMem[u.ae.i]);
- sqlite3VdbeMemStoreType(&u.ae.pMem[u.ae.i]);
- REGISTER_TRACE(pOp->p1+u.ae.i, &u.ae.pMem[u.ae.i]);
+ u.af.pMem = p->pResultSet = &aMem[pOp->p1];
+ for(u.af.i=0; u.af.i<pOp->p2; u.af.i++){
+ assert( memIsValid(&u.af.pMem[u.af.i]) );
+ Deephemeralize(&u.af.pMem[u.af.i]);
+ assert( (u.af.pMem[u.af.i].flags & MEM_Ephem)==0
+ || (u.af.pMem[u.af.i].flags & (MEM_Str|MEM_Blob))==0 );
+ sqlite3VdbeMemNulTerminate(&u.af.pMem[u.af.i]);
+ sqlite3VdbeMemStoreType(&u.af.pMem[u.af.i]);
+ REGISTER_TRACE(pOp->p1+u.af.i, &u.af.pMem[u.af.i]);
}
if( db->mallocFailed ) goto no_mem;
@@ -64643,9 +66523,9 @@ case OP_ResultRow: {
** to avoid a memcpy().
*/
case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */
-#if 0 /* local variables moved into u.af */
+#if 0 /* local variables moved into u.ag */
i64 nByte;
-#endif /* local variables moved into u.af */
+#endif /* local variables moved into u.ag */
pIn1 = &aMem[pOp->p1];
pIn2 = &aMem[pOp->p2];
@@ -64658,22 +66538,22 @@ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */
if( ExpandBlob(pIn1) || ExpandBlob(pIn2) ) goto no_mem;
Stringify(pIn1, encoding);
Stringify(pIn2, encoding);
- u.af.nByte = pIn1->n + pIn2->n;
- if( u.af.nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){
+ u.ag.nByte = pIn1->n + pIn2->n;
+ if( u.ag.nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){
goto too_big;
}
MemSetTypeFlag(pOut, MEM_Str);
- if( sqlite3VdbeMemGrow(pOut, (int)u.af.nByte+2, pOut==pIn2) ){
+ if( sqlite3VdbeMemGrow(pOut, (int)u.ag.nByte+2, pOut==pIn2) ){
goto no_mem;
}
if( pOut!=pIn2 ){
memcpy(pOut->z, pIn2->z, pIn2->n);
}
memcpy(&pOut->z[pIn2->n], pIn1->z, pIn1->n);
- pOut->z[u.af.nByte] = 0;
- pOut->z[u.af.nByte+1] = 0;
+ pOut->z[u.ag.nByte] = 0;
+ pOut->z[u.ag.nByte+1] = 0;
pOut->flags |= MEM_Term;
- pOut->n = (int)u.af.nByte;
+ pOut->n = (int)u.ag.nByte;
pOut->enc = encoding;
UPDATE_MAX_BLOBSIZE(pOut);
break;
@@ -64717,76 +66597,79 @@ case OP_Subtract: /* same as TK_MINUS, in1, in2, out3 */
case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */
case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */
case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
-#if 0 /* local variables moved into u.ag */
+#if 0 /* local variables moved into u.ah */
+ char bIntint; /* Started out as two integer operands */
int flags; /* Combined MEM_* flags from both inputs */
i64 iA; /* Integer value of left operand */
i64 iB; /* Integer value of right operand */
double rA; /* Real value of left operand */
double rB; /* Real value of right operand */
-#endif /* local variables moved into u.ag */
+#endif /* local variables moved into u.ah */
pIn1 = &aMem[pOp->p1];
applyNumericAffinity(pIn1);
pIn2 = &aMem[pOp->p2];
applyNumericAffinity(pIn2);
pOut = &aMem[pOp->p3];
- u.ag.flags = pIn1->flags | pIn2->flags;
- if( (u.ag.flags & MEM_Null)!=0 ) goto arithmetic_result_is_null;
+ u.ah.flags = pIn1->flags | pIn2->flags;
+ if( (u.ah.flags & MEM_Null)!=0 ) goto arithmetic_result_is_null;
if( (pIn1->flags & pIn2->flags & MEM_Int)==MEM_Int ){
- u.ag.iA = pIn1->u.i;
- u.ag.iB = pIn2->u.i;
+ u.ah.iA = pIn1->u.i;
+ u.ah.iB = pIn2->u.i;
+ u.ah.bIntint = 1;
switch( pOp->opcode ){
- case OP_Add: if( sqlite3AddInt64(&u.ag.iB,u.ag.iA) ) goto fp_math; break;
- case OP_Subtract: if( sqlite3SubInt64(&u.ag.iB,u.ag.iA) ) goto fp_math; break;
- case OP_Multiply: if( sqlite3MulInt64(&u.ag.iB,u.ag.iA) ) goto fp_math; break;
+ case OP_Add: if( sqlite3AddInt64(&u.ah.iB,u.ah.iA) ) goto fp_math; break;
+ case OP_Subtract: if( sqlite3SubInt64(&u.ah.iB,u.ah.iA) ) goto fp_math; break;
+ case OP_Multiply: if( sqlite3MulInt64(&u.ah.iB,u.ah.iA) ) goto fp_math; break;
case OP_Divide: {
- if( u.ag.iA==0 ) goto arithmetic_result_is_null;
- if( u.ag.iA==-1 && u.ag.iB==SMALLEST_INT64 ) goto fp_math;
- u.ag.iB /= u.ag.iA;
+ if( u.ah.iA==0 ) goto arithmetic_result_is_null;
+ if( u.ah.iA==-1 && u.ah.iB==SMALLEST_INT64 ) goto fp_math;
+ u.ah.iB /= u.ah.iA;
break;
}
default: {
- if( u.ag.iA==0 ) goto arithmetic_result_is_null;
- if( u.ag.iA==-1 ) u.ag.iA = 1;
- u.ag.iB %= u.ag.iA;
+ if( u.ah.iA==0 ) goto arithmetic_result_is_null;
+ if( u.ah.iA==-1 ) u.ah.iA = 1;
+ u.ah.iB %= u.ah.iA;
break;
}
}
- pOut->u.i = u.ag.iB;
+ pOut->u.i = u.ah.iB;
MemSetTypeFlag(pOut, MEM_Int);
}else{
+ u.ah.bIntint = 0;
fp_math:
- u.ag.rA = sqlite3VdbeRealValue(pIn1);
- u.ag.rB = sqlite3VdbeRealValue(pIn2);
+ u.ah.rA = sqlite3VdbeRealValue(pIn1);
+ u.ah.rB = sqlite3VdbeRealValue(pIn2);
switch( pOp->opcode ){
- case OP_Add: u.ag.rB += u.ag.rA; break;
- case OP_Subtract: u.ag.rB -= u.ag.rA; break;
- case OP_Multiply: u.ag.rB *= u.ag.rA; break;
+ case OP_Add: u.ah.rB += u.ah.rA; break;
+ case OP_Subtract: u.ah.rB -= u.ah.rA; break;
+ case OP_Multiply: u.ah.rB *= u.ah.rA; break;
case OP_Divide: {
/* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
- if( u.ag.rA==(double)0 ) goto arithmetic_result_is_null;
- u.ag.rB /= u.ag.rA;
+ if( u.ah.rA==(double)0 ) goto arithmetic_result_is_null;
+ u.ah.rB /= u.ah.rA;
break;
}
default: {
- u.ag.iA = (i64)u.ag.rA;
- u.ag.iB = (i64)u.ag.rB;
- if( u.ag.iA==0 ) goto arithmetic_result_is_null;
- if( u.ag.iA==-1 ) u.ag.iA = 1;
- u.ag.rB = (double)(u.ag.iB % u.ag.iA);
+ u.ah.iA = (i64)u.ah.rA;
+ u.ah.iB = (i64)u.ah.rB;
+ if( u.ah.iA==0 ) goto arithmetic_result_is_null;
+ if( u.ah.iA==-1 ) u.ah.iA = 1;
+ u.ah.rB = (double)(u.ah.iB % u.ah.iA);
break;
}
}
#ifdef SQLITE_OMIT_FLOATING_POINT
- pOut->u.i = u.ag.rB;
+ pOut->u.i = u.ah.rB;
MemSetTypeFlag(pOut, MEM_Int);
#else
- if( sqlite3IsNaN(u.ag.rB) ){
+ if( sqlite3IsNaN(u.ah.rB) ){
goto arithmetic_result_is_null;
}
- pOut->r = u.ag.rB;
+ pOut->r = u.ah.rB;
MemSetTypeFlag(pOut, MEM_Real);
- if( (u.ag.flags & MEM_Real)==0 ){
+ if( (u.ah.flags & MEM_Real)==0 && !u.ah.bIntint ){
sqlite3VdbeIntegerAffinity(pOut);
}
#endif
@@ -64838,70 +66721,70 @@ case OP_CollSeq: {
** See also: AggStep and AggFinal
*/
case OP_Function: {
-#if 0 /* local variables moved into u.ah */
+#if 0 /* local variables moved into u.ai */
int i;
Mem *pArg;
sqlite3_context ctx;
sqlite3_value **apVal;
int n;
-#endif /* local variables moved into u.ah */
+#endif /* local variables moved into u.ai */
- u.ah.n = pOp->p5;
- u.ah.apVal = p->apArg;
- assert( u.ah.apVal || u.ah.n==0 );
+ u.ai.n = pOp->p5;
+ u.ai.apVal = p->apArg;
+ assert( u.ai.apVal || u.ai.n==0 );
assert( pOp->p3>0 && pOp->p3<=p->nMem );
pOut = &aMem[pOp->p3];
memAboutToChange(p, pOut);
- assert( u.ah.n==0 || (pOp->p2>0 && pOp->p2+u.ah.n<=p->nMem+1) );
- assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+u.ah.n );
- u.ah.pArg = &aMem[pOp->p2];
- for(u.ah.i=0; u.ah.i<u.ah.n; u.ah.i++, u.ah.pArg++){
- assert( memIsValid(u.ah.pArg) );
- u.ah.apVal[u.ah.i] = u.ah.pArg;
- Deephemeralize(u.ah.pArg);
- sqlite3VdbeMemStoreType(u.ah.pArg);
- REGISTER_TRACE(pOp->p2+u.ah.i, u.ah.pArg);
+ assert( u.ai.n==0 || (pOp->p2>0 && pOp->p2+u.ai.n<=p->nMem+1) );
+ assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+u.ai.n );
+ u.ai.pArg = &aMem[pOp->p2];
+ for(u.ai.i=0; u.ai.i<u.ai.n; u.ai.i++, u.ai.pArg++){
+ assert( memIsValid(u.ai.pArg) );
+ u.ai.apVal[u.ai.i] = u.ai.pArg;
+ Deephemeralize(u.ai.pArg);
+ sqlite3VdbeMemStoreType(u.ai.pArg);
+ REGISTER_TRACE(pOp->p2+u.ai.i, u.ai.pArg);
}
assert( pOp->p4type==P4_FUNCDEF || pOp->p4type==P4_VDBEFUNC );
if( pOp->p4type==P4_FUNCDEF ){
- u.ah.ctx.pFunc = pOp->p4.pFunc;
- u.ah.ctx.pVdbeFunc = 0;
+ u.ai.ctx.pFunc = pOp->p4.pFunc;
+ u.ai.ctx.pVdbeFunc = 0;
}else{
- u.ah.ctx.pVdbeFunc = (VdbeFunc*)pOp->p4.pVdbeFunc;
- u.ah.ctx.pFunc = u.ah.ctx.pVdbeFunc->pFunc;
+ u.ai.ctx.pVdbeFunc = (VdbeFunc*)pOp->p4.pVdbeFunc;
+ u.ai.ctx.pFunc = u.ai.ctx.pVdbeFunc->pFunc;
}
- u.ah.ctx.s.flags = MEM_Null;
- u.ah.ctx.s.db = db;
- u.ah.ctx.s.xDel = 0;
- u.ah.ctx.s.zMalloc = 0;
+ u.ai.ctx.s.flags = MEM_Null;
+ u.ai.ctx.s.db = db;
+ u.ai.ctx.s.xDel = 0;
+ u.ai.ctx.s.zMalloc = 0;
/* The output cell may already have a buffer allocated. Move
- ** the pointer to u.ah.ctx.s so in case the user-function can use
+ ** the pointer to u.ai.ctx.s so in case the user-function can use
** the already allocated buffer instead of allocating a new one.
*/
- sqlite3VdbeMemMove(&u.ah.ctx.s, pOut);
- MemSetTypeFlag(&u.ah.ctx.s, MEM_Null);
+ sqlite3VdbeMemMove(&u.ai.ctx.s, pOut);
+ MemSetTypeFlag(&u.ai.ctx.s, MEM_Null);
- u.ah.ctx.isError = 0;
- if( u.ah.ctx.pFunc->flags & SQLITE_FUNC_NEEDCOLL ){
+ u.ai.ctx.isError = 0;
+ if( u.ai.ctx.pFunc->flags & SQLITE_FUNC_NEEDCOLL ){
assert( pOp>aOp );
assert( pOp[-1].p4type==P4_COLLSEQ );
assert( pOp[-1].opcode==OP_CollSeq );
- u.ah.ctx.pColl = pOp[-1].p4.pColl;
+ u.ai.ctx.pColl = pOp[-1].p4.pColl;
}
db->lastRowid = lastRowid;
- (*u.ah.ctx.pFunc->xFunc)(&u.ah.ctx, u.ah.n, u.ah.apVal); /* IMP: R-24505-23230 */
+ (*u.ai.ctx.pFunc->xFunc)(&u.ai.ctx, u.ai.n, u.ai.apVal); /* IMP: R-24505-23230 */
lastRowid = db->lastRowid;
/* If any auxiliary data functions have been called by this user function,
** immediately call the destructor for any non-static values.
*/
- if( u.ah.ctx.pVdbeFunc ){
- sqlite3VdbeDeleteAuxData(u.ah.ctx.pVdbeFunc, pOp->p1);
- pOp->p4.pVdbeFunc = u.ah.ctx.pVdbeFunc;
+ if( u.ai.ctx.pVdbeFunc ){
+ sqlite3VdbeDeleteAuxData(u.ai.ctx.pVdbeFunc, pOp->p1);
+ pOp->p4.pVdbeFunc = u.ai.ctx.pVdbeFunc;
pOp->p4type = P4_VDBEFUNC;
}
@@ -64911,19 +66794,19 @@ case OP_Function: {
** to return a value. The following call releases any resources
** associated with such a value.
*/
- sqlite3VdbeMemRelease(&u.ah.ctx.s);
+ sqlite3VdbeMemRelease(&u.ai.ctx.s);
goto no_mem;
}
/* If the function returned an error, throw an exception */
- if( u.ah.ctx.isError ){
- sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&u.ah.ctx.s));
- rc = u.ah.ctx.isError;
+ if( u.ai.ctx.isError ){
+ sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&u.ai.ctx.s));
+ rc = u.ai.ctx.isError;
}
/* Copy the result of the function into register P3 */
- sqlite3VdbeChangeEncoding(&u.ah.ctx.s, encoding);
- sqlite3VdbeMemMove(pOut, &u.ah.ctx.s);
+ sqlite3VdbeChangeEncoding(&u.ai.ctx.s, encoding);
+ sqlite3VdbeMemMove(pOut, &u.ai.ctx.s);
if( sqlite3VdbeMemTooBig(pOut) ){
goto too_big;
}
@@ -64971,12 +66854,12 @@ case OP_BitAnd: /* same as TK_BITAND, in1, in2, out3 */
case OP_BitOr: /* same as TK_BITOR, in1, in2, out3 */
case OP_ShiftLeft: /* same as TK_LSHIFT, in1, in2, out3 */
case OP_ShiftRight: { /* same as TK_RSHIFT, in1, in2, out3 */
-#if 0 /* local variables moved into u.ai */
+#if 0 /* local variables moved into u.aj */
i64 iA;
u64 uA;
i64 iB;
u8 op;
-#endif /* local variables moved into u.ai */
+#endif /* local variables moved into u.aj */
pIn1 = &aMem[pOp->p1];
pIn2 = &aMem[pOp->p2];
@@ -64985,38 +66868,38 @@ case OP_ShiftRight: { /* same as TK_RSHIFT, in1, in2, out3 */
sqlite3VdbeMemSetNull(pOut);
break;
}
- u.ai.iA = sqlite3VdbeIntValue(pIn2);
- u.ai.iB = sqlite3VdbeIntValue(pIn1);
- u.ai.op = pOp->opcode;
- if( u.ai.op==OP_BitAnd ){
- u.ai.iA &= u.ai.iB;
- }else if( u.ai.op==OP_BitOr ){
- u.ai.iA |= u.ai.iB;
- }else if( u.ai.iB!=0 ){
- assert( u.ai.op==OP_ShiftRight || u.ai.op==OP_ShiftLeft );
+ u.aj.iA = sqlite3VdbeIntValue(pIn2);
+ u.aj.iB = sqlite3VdbeIntValue(pIn1);
+ u.aj.op = pOp->opcode;
+ if( u.aj.op==OP_BitAnd ){
+ u.aj.iA &= u.aj.iB;
+ }else if( u.aj.op==OP_BitOr ){
+ u.aj.iA |= u.aj.iB;
+ }else if( u.aj.iB!=0 ){
+ assert( u.aj.op==OP_ShiftRight || u.aj.op==OP_ShiftLeft );
/* If shifting by a negative amount, shift in the other direction */
- if( u.ai.iB<0 ){
+ if( u.aj.iB<0 ){
assert( OP_ShiftRight==OP_ShiftLeft+1 );
- u.ai.op = 2*OP_ShiftLeft + 1 - u.ai.op;
- u.ai.iB = u.ai.iB>(-64) ? -u.ai.iB : 64;
+ u.aj.op = 2*OP_ShiftLeft + 1 - u.aj.op;
+ u.aj.iB = u.aj.iB>(-64) ? -u.aj.iB : 64;
}
- if( u.ai.iB>=64 ){
- u.ai.iA = (u.ai.iA>=0 || u.ai.op==OP_ShiftLeft) ? 0 : -1;
+ if( u.aj.iB>=64 ){
+ u.aj.iA = (u.aj.iA>=0 || u.aj.op==OP_ShiftLeft) ? 0 : -1;
}else{
- memcpy(&u.ai.uA, &u.ai.iA, sizeof(u.ai.uA));
- if( u.ai.op==OP_ShiftLeft ){
- u.ai.uA <<= u.ai.iB;
+ memcpy(&u.aj.uA, &u.aj.iA, sizeof(u.aj.uA));
+ if( u.aj.op==OP_ShiftLeft ){
+ u.aj.uA <<= u.aj.iB;
}else{
- u.ai.uA >>= u.ai.iB;
+ u.aj.uA >>= u.aj.iB;
/* Sign-extend on a right shift of a negative number */
- if( u.ai.iA<0 ) u.ai.uA |= ((((u64)0xffffffff)<<32)|0xffffffff) << (64-u.ai.iB);
+ if( u.aj.iA<0 ) u.aj.uA |= ((((u64)0xffffffff)<<32)|0xffffffff) << (64-u.aj.iB);
}
- memcpy(&u.ai.iA, &u.ai.uA, sizeof(u.ai.iA));
+ memcpy(&u.aj.iA, &u.aj.uA, sizeof(u.aj.iA));
}
}
- pOut->u.i = u.ai.iA;
+ pOut->u.i = u.aj.iA;
MemSetTypeFlag(pOut, MEM_Int);
break;
}
@@ -65208,6 +67091,10 @@ case OP_ToReal: { /* same as TK_TO_REAL, in1 */
**
** If the SQLITE_STOREP2 bit of P5 is set, then do not jump. Instead,
** store a boolean result (either 0, or 1, or NULL) in register P2.
+**
+** If the SQLITE_NULLEQ bit is set in P5, then NULL values are considered
+** equal to one another, provided that they do not have their MEM_Cleared
+** bit set.
*/
/* Opcode: Ne P1 P2 P3 P4 P5
**
@@ -65257,18 +67144,18 @@ case OP_Lt: /* same as TK_LT, jump, in1, in3 */
case OP_Le: /* same as TK_LE, jump, in1, in3 */
case OP_Gt: /* same as TK_GT, jump, in1, in3 */
case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
-#if 0 /* local variables moved into u.aj */
+#if 0 /* local variables moved into u.ak */
int res; /* Result of the comparison of pIn1 against pIn3 */
char affinity; /* Affinity to use for comparison */
u16 flags1; /* Copy of initial value of pIn1->flags */
u16 flags3; /* Copy of initial value of pIn3->flags */
-#endif /* local variables moved into u.aj */
+#endif /* local variables moved into u.ak */
pIn1 = &aMem[pOp->p1];
pIn3 = &aMem[pOp->p3];
- u.aj.flags1 = pIn1->flags;
- u.aj.flags3 = pIn3->flags;
- if( (u.aj.flags1 | u.aj.flags3)&MEM_Null ){
+ u.ak.flags1 = pIn1->flags;
+ u.ak.flags3 = pIn3->flags;
+ if( (u.ak.flags1 | u.ak.flags3)&MEM_Null ){
/* One or both operands are NULL */
if( pOp->p5 & SQLITE_NULLEQ ){
/* If SQLITE_NULLEQ is set (which will only happen if the operator is
@@ -65276,7 +67163,15 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
** or not both operands are null.
*/
assert( pOp->opcode==OP_Eq || pOp->opcode==OP_Ne );
- u.aj.res = (u.aj.flags1 & u.aj.flags3 & MEM_Null)==0;
+ assert( (u.ak.flags1 & MEM_Cleared)==0 );
+ if( (u.ak.flags1&MEM_Null)!=0
+ && (u.ak.flags3&MEM_Null)!=0
+ && (u.ak.flags3&MEM_Cleared)==0
+ ){
+ u.ak.res = 0; /* Results are equal */
+ }else{
+ u.ak.res = 1; /* Results are not equal */
+ }
}else{
/* SQLITE_NULLEQ is clear and at least one operand is NULL,
** then the result is always NULL.
@@ -65293,40 +67188,40 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
}
}else{
/* Neither operand is NULL. Do a comparison. */
- u.aj.affinity = pOp->p5 & SQLITE_AFF_MASK;
- if( u.aj.affinity ){
- applyAffinity(pIn1, u.aj.affinity, encoding);
- applyAffinity(pIn3, u.aj.affinity, encoding);
+ u.ak.affinity = pOp->p5 & SQLITE_AFF_MASK;
+ if( u.ak.affinity ){
+ applyAffinity(pIn1, u.ak.affinity, encoding);
+ applyAffinity(pIn3, u.ak.affinity, encoding);
if( db->mallocFailed ) goto no_mem;
}
assert( pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0 );
ExpandBlob(pIn1);
ExpandBlob(pIn3);
- u.aj.res = sqlite3MemCompare(pIn3, pIn1, pOp->p4.pColl);
+ u.ak.res = sqlite3MemCompare(pIn3, pIn1, pOp->p4.pColl);
}
switch( pOp->opcode ){
- case OP_Eq: u.aj.res = u.aj.res==0; break;
- case OP_Ne: u.aj.res = u.aj.res!=0; break;
- case OP_Lt: u.aj.res = u.aj.res<0; break;
- case OP_Le: u.aj.res = u.aj.res<=0; break;
- case OP_Gt: u.aj.res = u.aj.res>0; break;
- default: u.aj.res = u.aj.res>=0; break;
+ case OP_Eq: u.ak.res = u.ak.res==0; break;
+ case OP_Ne: u.ak.res = u.ak.res!=0; break;
+ case OP_Lt: u.ak.res = u.ak.res<0; break;
+ case OP_Le: u.ak.res = u.ak.res<=0; break;
+ case OP_Gt: u.ak.res = u.ak.res>0; break;
+ default: u.ak.res = u.ak.res>=0; break;
}
if( pOp->p5 & SQLITE_STOREP2 ){
pOut = &aMem[pOp->p2];
memAboutToChange(p, pOut);
MemSetTypeFlag(pOut, MEM_Int);
- pOut->u.i = u.aj.res;
+ pOut->u.i = u.ak.res;
REGISTER_TRACE(pOp->p2, pOut);
- }else if( u.aj.res ){
+ }else if( u.ak.res ){
pc = pOp->p2-1;
}
/* Undo any changes made by applyAffinity() to the input registers. */
- pIn1->flags = (pIn1->flags&~MEM_TypeMask) | (u.aj.flags1&MEM_TypeMask);
- pIn3->flags = (pIn3->flags&~MEM_TypeMask) | (u.aj.flags3&MEM_TypeMask);
+ pIn1->flags = (pIn1->flags&~MEM_TypeMask) | (u.ak.flags1&MEM_TypeMask);
+ pIn3->flags = (pIn3->flags&~MEM_TypeMask) | (u.ak.flags3&MEM_TypeMask);
break;
}
@@ -65335,9 +67230,9 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
** Set the permutation used by the OP_Compare operator to be the array
** of integers in P4.
**
-** The permutation is only valid until the next OP_Permutation, OP_Compare,
-** OP_Halt, or OP_ResultRow. Typically the OP_Permutation should occur
-** immediately prior to the OP_Compare.
+** The permutation is only valid until the next OP_Compare that has
+** the OPFLAG_PERMUTE bit set in P5. Typically the OP_Permutation should
+** occur immediately prior to the OP_Compare.
*/
case OP_Permutation: {
assert( pOp->p4type==P4_INTARRAY );
@@ -65346,12 +67241,17 @@ case OP_Permutation: {
break;
}
-/* Opcode: Compare P1 P2 P3 P4 *
+/* Opcode: Compare P1 P2 P3 P4 P5
**
** Compare two vectors of registers in reg(P1)..reg(P1+P3-1) (call this
** vector "A") and in reg(P2)..reg(P2+P3-1) ("B"). Save the result of
** the comparison for use by the next OP_Jump instruct.
**
+** If P5 has the OPFLAG_PERMUTE bit set, then the order of comparison is
+** determined by the most recent OP_Permutation operator. If the
+** OPFLAG_PERMUTE bit is clear, then register are compared in sequential
+** order.
+**
** P4 is a KeyInfo structure that defines collating sequences and sort
** orders for the comparison. The permutation applies to registers
** only. The KeyInfo elements are used sequentially.
@@ -65361,7 +67261,7 @@ case OP_Permutation: {
** and strings are less than blobs.
*/
case OP_Compare: {
-#if 0 /* local variables moved into u.ak */
+#if 0 /* local variables moved into u.al */
int n;
int i;
int p1;
@@ -65370,37 +67270,38 @@ case OP_Compare: {
int idx;
CollSeq *pColl; /* Collating sequence to use on this term */
int bRev; /* True for DESCENDING sort order */
-#endif /* local variables moved into u.ak */
+#endif /* local variables moved into u.al */
- u.ak.n = pOp->p3;
- u.ak.pKeyInfo = pOp->p4.pKeyInfo;
- assert( u.ak.n>0 );
- assert( u.ak.pKeyInfo!=0 );
- u.ak.p1 = pOp->p1;
- u.ak.p2 = pOp->p2;
+ if( (pOp->p5 & OPFLAG_PERMUTE)==0 ) aPermute = 0;
+ u.al.n = pOp->p3;
+ u.al.pKeyInfo = pOp->p4.pKeyInfo;
+ assert( u.al.n>0 );
+ assert( u.al.pKeyInfo!=0 );
+ u.al.p1 = pOp->p1;
+ u.al.p2 = pOp->p2;
#if SQLITE_DEBUG
if( aPermute ){
int k, mx = 0;
- for(k=0; k<u.ak.n; k++) if( aPermute[k]>mx ) mx = aPermute[k];
- assert( u.ak.p1>0 && u.ak.p1+mx<=p->nMem+1 );
- assert( u.ak.p2>0 && u.ak.p2+mx<=p->nMem+1 );
+ for(k=0; k<u.al.n; k++) if( aPermute[k]>mx ) mx = aPermute[k];
+ assert( u.al.p1>0 && u.al.p1+mx<=p->nMem+1 );
+ assert( u.al.p2>0 && u.al.p2+mx<=p->nMem+1 );
}else{
- assert( u.ak.p1>0 && u.ak.p1+u.ak.n<=p->nMem+1 );
- assert( u.ak.p2>0 && u.ak.p2+u.ak.n<=p->nMem+1 );
+ assert( u.al.p1>0 && u.al.p1+u.al.n<=p->nMem+1 );
+ assert( u.al.p2>0 && u.al.p2+u.al.n<=p->nMem+1 );
}
#endif /* SQLITE_DEBUG */
- for(u.ak.i=0; u.ak.i<u.ak.n; u.ak.i++){
- u.ak.idx = aPermute ? aPermute[u.ak.i] : u.ak.i;
- assert( memIsValid(&aMem[u.ak.p1+u.ak.idx]) );
- assert( memIsValid(&aMem[u.ak.p2+u.ak.idx]) );
- REGISTER_TRACE(u.ak.p1+u.ak.idx, &aMem[u.ak.p1+u.ak.idx]);
- REGISTER_TRACE(u.ak.p2+u.ak.idx, &aMem[u.ak.p2+u.ak.idx]);
- assert( u.ak.i<u.ak.pKeyInfo->nField );
- u.ak.pColl = u.ak.pKeyInfo->aColl[u.ak.i];
- u.ak.bRev = u.ak.pKeyInfo->aSortOrder[u.ak.i];
- iCompare = sqlite3MemCompare(&aMem[u.ak.p1+u.ak.idx], &aMem[u.ak.p2+u.ak.idx], u.ak.pColl);
+ for(u.al.i=0; u.al.i<u.al.n; u.al.i++){
+ u.al.idx = aPermute ? aPermute[u.al.i] : u.al.i;
+ assert( memIsValid(&aMem[u.al.p1+u.al.idx]) );
+ assert( memIsValid(&aMem[u.al.p2+u.al.idx]) );
+ REGISTER_TRACE(u.al.p1+u.al.idx, &aMem[u.al.p1+u.al.idx]);
+ REGISTER_TRACE(u.al.p2+u.al.idx, &aMem[u.al.p2+u.al.idx]);
+ assert( u.al.i<u.al.pKeyInfo->nField );
+ u.al.pColl = u.al.pKeyInfo->aColl[u.al.i];
+ u.al.bRev = u.al.pKeyInfo->aSortOrder[u.al.i];
+ iCompare = sqlite3MemCompare(&aMem[u.al.p1+u.al.idx], &aMem[u.al.p2+u.al.idx], u.al.pColl);
if( iCompare ){
- if( u.ak.bRev ) iCompare = -iCompare;
+ if( u.al.bRev ) iCompare = -iCompare;
break;
}
}
@@ -65445,35 +67346,35 @@ case OP_Jump: { /* jump */
*/
case OP_And: /* same as TK_AND, in1, in2, out3 */
case OP_Or: { /* same as TK_OR, in1, in2, out3 */
-#if 0 /* local variables moved into u.al */
+#if 0 /* local variables moved into u.am */
int v1; /* Left operand: 0==FALSE, 1==TRUE, 2==UNKNOWN or NULL */
int v2; /* Right operand: 0==FALSE, 1==TRUE, 2==UNKNOWN or NULL */
-#endif /* local variables moved into u.al */
+#endif /* local variables moved into u.am */
pIn1 = &aMem[pOp->p1];
if( pIn1->flags & MEM_Null ){
- u.al.v1 = 2;
+ u.am.v1 = 2;
}else{
- u.al.v1 = sqlite3VdbeIntValue(pIn1)!=0;
+ u.am.v1 = sqlite3VdbeIntValue(pIn1)!=0;
}
pIn2 = &aMem[pOp->p2];
if( pIn2->flags & MEM_Null ){
- u.al.v2 = 2;
+ u.am.v2 = 2;
}else{
- u.al.v2 = sqlite3VdbeIntValue(pIn2)!=0;
+ u.am.v2 = sqlite3VdbeIntValue(pIn2)!=0;
}
if( pOp->opcode==OP_And ){
static const unsigned char and_logic[] = { 0, 0, 0, 0, 1, 2, 0, 2, 2 };
- u.al.v1 = and_logic[u.al.v1*3+u.al.v2];
+ u.am.v1 = and_logic[u.am.v1*3+u.am.v2];
}else{
static const unsigned char or_logic[] = { 0, 1, 2, 1, 1, 1, 2, 1, 2 };
- u.al.v1 = or_logic[u.al.v1*3+u.al.v2];
+ u.am.v1 = or_logic[u.am.v1*3+u.am.v2];
}
pOut = &aMem[pOp->p3];
- if( u.al.v1==2 ){
+ if( u.am.v1==2 ){
MemSetTypeFlag(pOut, MEM_Null);
}else{
- pOut->u.i = u.al.v1;
+ pOut->u.i = u.am.v1;
MemSetTypeFlag(pOut, MEM_Int);
}
break;
@@ -65517,8 +67418,6 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */
**
** Check if OP_Once flag P1 is set. If so, jump to instruction P2. Otherwise,
** set the flag and fall through to the next instruction.
-**
-** See also: JumpOnce
*/
case OP_Once: { /* jump */
assert( pOp->p1<p->nOnceFlag );
@@ -65544,21 +67443,21 @@ case OP_Once: { /* jump */
*/
case OP_If: /* jump, in1 */
case OP_IfNot: { /* jump, in1 */
-#if 0 /* local variables moved into u.am */
+#if 0 /* local variables moved into u.an */
int c;
-#endif /* local variables moved into u.am */
+#endif /* local variables moved into u.an */
pIn1 = &aMem[pOp->p1];
if( pIn1->flags & MEM_Null ){
- u.am.c = pOp->p3;
+ u.an.c = pOp->p3;
}else{
#ifdef SQLITE_OMIT_FLOATING_POINT
- u.am.c = sqlite3VdbeIntValue(pIn1)!=0;
+ u.an.c = sqlite3VdbeIntValue(pIn1)!=0;
#else
- u.am.c = sqlite3VdbeRealValue(pIn1)!=0.0;
+ u.an.c = sqlite3VdbeRealValue(pIn1)!=0.0;
#endif
- if( pOp->opcode==OP_IfNot ) u.am.c = !u.am.c;
+ if( pOp->opcode==OP_IfNot ) u.an.c = !u.an.c;
}
- if( u.am.c ){
+ if( u.an.c ){
pc = pOp->p2-1;
}
break;
@@ -65613,7 +67512,7 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */
** skipped for length() and all content loading can be skipped for typeof().
*/
case OP_Column: {
-#if 0 /* local variables moved into u.an */
+#if 0 /* local variables moved into u.ao */
u32 payloadSize; /* Number of bytes in the record */
i64 payloadSize64; /* Number of bytes in the record */
int p1; /* P1 value of the opcode */
@@ -65637,126 +67536,131 @@ case OP_Column: {
int avail; /* Number of bytes of available data */
u32 t; /* A type code from the record header */
Mem *pReg; /* PseudoTable input register */
-#endif /* local variables moved into u.an */
+#endif /* local variables moved into u.ao */
- u.an.p1 = pOp->p1;
- u.an.p2 = pOp->p2;
- u.an.pC = 0;
- memset(&u.an.sMem, 0, sizeof(u.an.sMem));
- assert( u.an.p1<p->nCursor );
+ u.ao.p1 = pOp->p1;
+ u.ao.p2 = pOp->p2;
+ u.ao.pC = 0;
+ memset(&u.ao.sMem, 0, sizeof(u.ao.sMem));
+ assert( u.ao.p1<p->nCursor );
assert( pOp->p3>0 && pOp->p3<=p->nMem );
- u.an.pDest = &aMem[pOp->p3];
- memAboutToChange(p, u.an.pDest);
- u.an.zRec = 0;
+ u.ao.pDest = &aMem[pOp->p3];
+ memAboutToChange(p, u.ao.pDest);
+ u.ao.zRec = 0;
- /* This block sets the variable u.an.payloadSize to be the total number of
+ /* This block sets the variable u.ao.payloadSize to be the total number of
** bytes in the record.
**
- ** u.an.zRec is set to be the complete text of the record if it is available.
+ ** u.ao.zRec is set to be the complete text of the record if it is available.
** The complete record text is always available for pseudo-tables
** If the record is stored in a cursor, the complete record text
- ** might be available in the u.an.pC->aRow cache. Or it might not be.
- ** If the data is unavailable, u.an.zRec is set to NULL.
+ ** might be available in the u.ao.pC->aRow cache. Or it might not be.
+ ** If the data is unavailable, u.ao.zRec is set to NULL.
**
** We also compute the number of columns in the record. For cursors,
** the number of columns is stored in the VdbeCursor.nField element.
*/
- u.an.pC = p->apCsr[u.an.p1];
- assert( u.an.pC!=0 );
+ u.ao.pC = p->apCsr[u.ao.p1];
+ assert( u.ao.pC!=0 );
#ifndef SQLITE_OMIT_VIRTUALTABLE
- assert( u.an.pC->pVtabCursor==0 );
+ assert( u.ao.pC->pVtabCursor==0 );
#endif
- u.an.pCrsr = u.an.pC->pCursor;
- if( u.an.pCrsr!=0 ){
+ u.ao.pCrsr = u.ao.pC->pCursor;
+ if( u.ao.pCrsr!=0 ){
/* The record is stored in a B-Tree */
- rc = sqlite3VdbeCursorMoveto(u.an.pC);
+ rc = sqlite3VdbeCursorMoveto(u.ao.pC);
if( rc ) goto abort_due_to_error;
- if( u.an.pC->nullRow ){
- u.an.payloadSize = 0;
- }else if( u.an.pC->cacheStatus==p->cacheCtr ){
- u.an.payloadSize = u.an.pC->payloadSize;
- u.an.zRec = (char*)u.an.pC->aRow;
- }else if( u.an.pC->isIndex ){
- assert( sqlite3BtreeCursorIsValid(u.an.pCrsr) );
- VVA_ONLY(rc =) sqlite3BtreeKeySize(u.an.pCrsr, &u.an.payloadSize64);
+ if( u.ao.pC->nullRow ){
+ u.ao.payloadSize = 0;
+ }else if( u.ao.pC->cacheStatus==p->cacheCtr ){
+ u.ao.payloadSize = u.ao.pC->payloadSize;
+ u.ao.zRec = (char*)u.ao.pC->aRow;
+ }else if( u.ao.pC->isIndex ){
+ assert( sqlite3BtreeCursorIsValid(u.ao.pCrsr) );
+ VVA_ONLY(rc =) sqlite3BtreeKeySize(u.ao.pCrsr, &u.ao.payloadSize64);
assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */
/* sqlite3BtreeParseCellPtr() uses getVarint32() to extract the
- ** payload size, so it is impossible for u.an.payloadSize64 to be
+ ** payload size, so it is impossible for u.ao.payloadSize64 to be
** larger than 32 bits. */
- assert( (u.an.payloadSize64 & SQLITE_MAX_U32)==(u64)u.an.payloadSize64 );
- u.an.payloadSize = (u32)u.an.payloadSize64;
+ assert( (u.ao.payloadSize64 & SQLITE_MAX_U32)==(u64)u.ao.payloadSize64 );
+ u.ao.payloadSize = (u32)u.ao.payloadSize64;
}else{
- assert( sqlite3BtreeCursorIsValid(u.an.pCrsr) );
- VVA_ONLY(rc =) sqlite3BtreeDataSize(u.an.pCrsr, &u.an.payloadSize);
+ assert( sqlite3BtreeCursorIsValid(u.ao.pCrsr) );
+ VVA_ONLY(rc =) sqlite3BtreeDataSize(u.ao.pCrsr, &u.ao.payloadSize);
assert( rc==SQLITE_OK ); /* DataSize() cannot fail */
}
- }else if( ALWAYS(u.an.pC->pseudoTableReg>0) ){
- u.an.pReg = &aMem[u.an.pC->pseudoTableReg];
- assert( u.an.pReg->flags & MEM_Blob );
- assert( memIsValid(u.an.pReg) );
- u.an.payloadSize = u.an.pReg->n;
- u.an.zRec = u.an.pReg->z;
- u.an.pC->cacheStatus = (pOp->p5&OPFLAG_CLEARCACHE) ? CACHE_STALE : p->cacheCtr;
- assert( u.an.payloadSize==0 || u.an.zRec!=0 );
+ }else if( ALWAYS(u.ao.pC->pseudoTableReg>0) ){
+ u.ao.pReg = &aMem[u.ao.pC->pseudoTableReg];
+ if( u.ao.pC->multiPseudo ){
+ sqlite3VdbeMemShallowCopy(u.ao.pDest, u.ao.pReg+u.ao.p2, MEM_Ephem);
+ Deephemeralize(u.ao.pDest);
+ goto op_column_out;
+ }
+ assert( u.ao.pReg->flags & MEM_Blob );
+ assert( memIsValid(u.ao.pReg) );
+ u.ao.payloadSize = u.ao.pReg->n;
+ u.ao.zRec = u.ao.pReg->z;
+ u.ao.pC->cacheStatus = (pOp->p5&OPFLAG_CLEARCACHE) ? CACHE_STALE : p->cacheCtr;
+ assert( u.ao.payloadSize==0 || u.ao.zRec!=0 );
}else{
/* Consider the row to be NULL */
- u.an.payloadSize = 0;
+ u.ao.payloadSize = 0;
}
- /* If u.an.payloadSize is 0, then just store a NULL. This can happen because of
+ /* If u.ao.payloadSize is 0, then just store a NULL. This can happen because of
** nullRow or because of a corrupt database. */
- if( u.an.payloadSize==0 ){
- MemSetTypeFlag(u.an.pDest, MEM_Null);
+ if( u.ao.payloadSize==0 ){
+ MemSetTypeFlag(u.ao.pDest, MEM_Null);
goto op_column_out;
}
assert( db->aLimit[SQLITE_LIMIT_LENGTH]>=0 );
- if( u.an.payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
+ if( u.ao.payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
goto too_big;
}
- u.an.nField = u.an.pC->nField;
- assert( u.an.p2<u.an.nField );
+ u.ao.nField = u.ao.pC->nField;
+ assert( u.ao.p2<u.ao.nField );
/* Read and parse the table header. Store the results of the parse
** into the record header cache fields of the cursor.
*/
- u.an.aType = u.an.pC->aType;
- if( u.an.pC->cacheStatus==p->cacheCtr ){
- u.an.aOffset = u.an.pC->aOffset;
+ u.ao.aType = u.ao.pC->aType;
+ if( u.ao.pC->cacheStatus==p->cacheCtr ){
+ u.ao.aOffset = u.ao.pC->aOffset;
}else{
- assert(u.an.aType);
- u.an.avail = 0;
- u.an.pC->aOffset = u.an.aOffset = &u.an.aType[u.an.nField];
- u.an.pC->payloadSize = u.an.payloadSize;
- u.an.pC->cacheStatus = p->cacheCtr;
+ assert(u.ao.aType);
+ u.ao.avail = 0;
+ u.ao.pC->aOffset = u.ao.aOffset = &u.ao.aType[u.ao.nField];
+ u.ao.pC->payloadSize = u.ao.payloadSize;
+ u.ao.pC->cacheStatus = p->cacheCtr;
/* Figure out how many bytes are in the header */
- if( u.an.zRec ){
- u.an.zData = u.an.zRec;
+ if( u.ao.zRec ){
+ u.ao.zData = u.ao.zRec;
}else{
- if( u.an.pC->isIndex ){
- u.an.zData = (char*)sqlite3BtreeKeyFetch(u.an.pCrsr, &u.an.avail);
+ if( u.ao.pC->isIndex ){
+ u.ao.zData = (char*)sqlite3BtreeKeyFetch(u.ao.pCrsr, &u.ao.avail);
}else{
- u.an.zData = (char*)sqlite3BtreeDataFetch(u.an.pCrsr, &u.an.avail);
+ u.ao.zData = (char*)sqlite3BtreeDataFetch(u.ao.pCrsr, &u.ao.avail);
}
/* If KeyFetch()/DataFetch() managed to get the entire payload,
- ** save the payload in the u.an.pC->aRow cache. That will save us from
+ ** save the payload in the u.ao.pC->aRow cache. That will save us from
** having to make additional calls to fetch the content portion of
** the record.
*/
- assert( u.an.avail>=0 );
- if( u.an.payloadSize <= (u32)u.an.avail ){
- u.an.zRec = u.an.zData;
- u.an.pC->aRow = (u8*)u.an.zData;
+ assert( u.ao.avail>=0 );
+ if( u.ao.payloadSize <= (u32)u.ao.avail ){
+ u.ao.zRec = u.ao.zData;
+ u.ao.pC->aRow = (u8*)u.ao.zData;
}else{
- u.an.pC->aRow = 0;
+ u.ao.pC->aRow = 0;
}
}
/* The following assert is true in all cases except when
** the database file has been corrupted externally.
- ** assert( u.an.zRec!=0 || u.an.avail>=u.an.payloadSize || u.an.avail>=9 ); */
- u.an.szHdr = getVarint32((u8*)u.an.zData, u.an.offset);
+ ** assert( u.ao.zRec!=0 || u.ao.avail>=u.ao.payloadSize || u.ao.avail>=9 ); */
+ u.ao.szHdr = getVarint32((u8*)u.ao.zData, u.ao.offset);
/* Make sure a corrupt database has not given us an oversize header.
** Do this now to avoid an oversize memory allocation.
@@ -65767,26 +67671,26 @@ case OP_Column: {
** 3-byte type for each of the maximum of 32768 columns plus three
** extra bytes for the header length itself. 32768*3 + 3 = 98307.
*/
- if( u.an.offset > 98307 ){
+ if( u.ao.offset > 98307 ){
rc = SQLITE_CORRUPT_BKPT;
goto op_column_out;
}
- /* Compute in u.an.len the number of bytes of data we need to read in order
- ** to get u.an.nField type values. u.an.offset is an upper bound on this. But
- ** u.an.nField might be significantly less than the true number of columns
- ** in the table, and in that case, 5*u.an.nField+3 might be smaller than u.an.offset.
- ** We want to minimize u.an.len in order to limit the size of the memory
- ** allocation, especially if a corrupt database file has caused u.an.offset
+ /* Compute in u.ao.len the number of bytes of data we need to read in order
+ ** to get u.ao.nField type values. u.ao.offset is an upper bound on this. But
+ ** u.ao.nField might be significantly less than the true number of columns
+ ** in the table, and in that case, 5*u.ao.nField+3 might be smaller than u.ao.offset.
+ ** We want to minimize u.ao.len in order to limit the size of the memory
+ ** allocation, especially if a corrupt database file has caused u.ao.offset
** to be oversized. Offset is limited to 98307 above. But 98307 might
** still exceed Robson memory allocation limits on some configurations.
- ** On systems that cannot tolerate large memory allocations, u.an.nField*5+3
- ** will likely be much smaller since u.an.nField will likely be less than
+ ** On systems that cannot tolerate large memory allocations, u.ao.nField*5+3
+ ** will likely be much smaller since u.ao.nField will likely be less than
** 20 or so. This insures that Robson memory allocation limits are
** not exceeded even for corrupt database files.
*/
- u.an.len = u.an.nField*5 + 3;
- if( u.an.len > (int)u.an.offset ) u.an.len = (int)u.an.offset;
+ u.ao.len = u.ao.nField*5 + 3;
+ if( u.ao.len > (int)u.ao.offset ) u.ao.len = (int)u.ao.offset;
/* The KeyFetch() or DataFetch() above are fast and will get the entire
** record header in most cases. But they will fail to get the complete
@@ -65794,51 +67698,51 @@ case OP_Column: {
** in the B-Tree. When that happens, use sqlite3VdbeMemFromBtree() to
** acquire the complete header text.
*/
- if( !u.an.zRec && u.an.avail<u.an.len ){
- u.an.sMem.flags = 0;
- u.an.sMem.db = 0;
- rc = sqlite3VdbeMemFromBtree(u.an.pCrsr, 0, u.an.len, u.an.pC->isIndex, &u.an.sMem);
+ if( !u.ao.zRec && u.ao.avail<u.ao.len ){
+ u.ao.sMem.flags = 0;
+ u.ao.sMem.db = 0;
+ rc = sqlite3VdbeMemFromBtree(u.ao.pCrsr, 0, u.ao.len, u.ao.pC->isIndex, &u.ao.sMem);
if( rc!=SQLITE_OK ){
goto op_column_out;
}
- u.an.zData = u.an.sMem.z;
+ u.ao.zData = u.ao.sMem.z;
}
- u.an.zEndHdr = (u8 *)&u.an.zData[u.an.len];
- u.an.zIdx = (u8 *)&u.an.zData[u.an.szHdr];
+ u.ao.zEndHdr = (u8 *)&u.ao.zData[u.ao.len];
+ u.ao.zIdx = (u8 *)&u.ao.zData[u.ao.szHdr];
- /* Scan the header and use it to fill in the u.an.aType[] and u.an.aOffset[]
- ** arrays. u.an.aType[u.an.i] will contain the type integer for the u.an.i-th
- ** column and u.an.aOffset[u.an.i] will contain the u.an.offset from the beginning
- ** of the record to the start of the data for the u.an.i-th column
+ /* Scan the header and use it to fill in the u.ao.aType[] and u.ao.aOffset[]
+ ** arrays. u.ao.aType[u.ao.i] will contain the type integer for the u.ao.i-th
+ ** column and u.ao.aOffset[u.ao.i] will contain the u.ao.offset from the beginning
+ ** of the record to the start of the data for the u.ao.i-th column
*/
- for(u.an.i=0; u.an.i<u.an.nField; u.an.i++){
- if( u.an.zIdx<u.an.zEndHdr ){
- u.an.aOffset[u.an.i] = u.an.offset;
- if( u.an.zIdx[0]<0x80 ){
- u.an.t = u.an.zIdx[0];
- u.an.zIdx++;
+ for(u.ao.i=0; u.ao.i<u.ao.nField; u.ao.i++){
+ if( u.ao.zIdx<u.ao.zEndHdr ){
+ u.ao.aOffset[u.ao.i] = u.ao.offset;
+ if( u.ao.zIdx[0]<0x80 ){
+ u.ao.t = u.ao.zIdx[0];
+ u.ao.zIdx++;
}else{
- u.an.zIdx += sqlite3GetVarint32(u.an.zIdx, &u.an.t);
+ u.ao.zIdx += sqlite3GetVarint32(u.ao.zIdx, &u.ao.t);
}
- u.an.aType[u.an.i] = u.an.t;
- u.an.szField = sqlite3VdbeSerialTypeLen(u.an.t);
- u.an.offset += u.an.szField;
- if( u.an.offset<u.an.szField ){ /* True if u.an.offset overflows */
- u.an.zIdx = &u.an.zEndHdr[1]; /* Forces SQLITE_CORRUPT return below */
+ u.ao.aType[u.ao.i] = u.ao.t;
+ u.ao.szField = sqlite3VdbeSerialTypeLen(u.ao.t);
+ u.ao.offset += u.ao.szField;
+ if( u.ao.offset<u.ao.szField ){ /* True if u.ao.offset overflows */
+ u.ao.zIdx = &u.ao.zEndHdr[1]; /* Forces SQLITE_CORRUPT return below */
break;
}
}else{
- /* If u.an.i is less that u.an.nField, then there are fewer fields in this
+ /* If u.ao.i is less that u.ao.nField, then there are fewer fields in this
** record than SetNumColumns indicated there are columns in the
- ** table. Set the u.an.offset for any extra columns not present in
+ ** table. Set the u.ao.offset for any extra columns not present in
** the record to 0. This tells code below to store the default value
** for the column instead of deserializing a value from the record.
*/
- u.an.aOffset[u.an.i] = 0;
+ u.ao.aOffset[u.ao.i] = 0;
}
}
- sqlite3VdbeMemRelease(&u.an.sMem);
- u.an.sMem.flags = MEM_Null;
+ sqlite3VdbeMemRelease(&u.ao.sMem);
+ u.ao.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
@@ -65846,78 +67750,78 @@ case OP_Column: {
** of the record (when all fields present), then we must be dealing
** with a corrupt database.
*/
- if( (u.an.zIdx > u.an.zEndHdr) || (u.an.offset > u.an.payloadSize)
- || (u.an.zIdx==u.an.zEndHdr && u.an.offset!=u.an.payloadSize) ){
+ if( (u.ao.zIdx > u.ao.zEndHdr) || (u.ao.offset > u.ao.payloadSize)
+ || (u.ao.zIdx==u.ao.zEndHdr && u.ao.offset!=u.ao.payloadSize) ){
rc = SQLITE_CORRUPT_BKPT;
goto op_column_out;
}
}
- /* Get the column information. If u.an.aOffset[u.an.p2] is non-zero, then
- ** deserialize the value from the record. If u.an.aOffset[u.an.p2] is zero,
+ /* Get the column information. If u.ao.aOffset[u.ao.p2] is non-zero, then
+ ** deserialize the value from the record. If u.ao.aOffset[u.ao.p2] is zero,
** then there are not enough fields in the record to satisfy the
** request. In this case, set the value NULL or to P4 if P4 is
** a pointer to a Mem object.
*/
- if( u.an.aOffset[u.an.p2] ){
+ if( u.ao.aOffset[u.ao.p2] ){
assert( rc==SQLITE_OK );
- if( u.an.zRec ){
+ if( u.ao.zRec ){
/* This is the common case where the whole row fits on a single page */
- VdbeMemRelease(u.an.pDest);
- sqlite3VdbeSerialGet((u8 *)&u.an.zRec[u.an.aOffset[u.an.p2]], u.an.aType[u.an.p2], u.an.pDest);
+ VdbeMemRelease(u.ao.pDest);
+ sqlite3VdbeSerialGet((u8 *)&u.ao.zRec[u.ao.aOffset[u.ao.p2]], u.ao.aType[u.ao.p2], u.ao.pDest);
}else{
/* This branch happens only when the row overflows onto multiple pages */
- u.an.t = u.an.aType[u.an.p2];
+ u.ao.t = u.ao.aType[u.ao.p2];
if( (pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
- && ((u.an.t>=12 && (u.an.t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0)
+ && ((u.ao.t>=12 && (u.ao.t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=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 u.an.payloadSize64 variable
+ ** for text and blob and whatever is in the u.ao.payloadSize64 variable
** will work for everything else. */
- u.an.zData = u.an.t<12 ? (char*)&u.an.payloadSize64 : 0;
+ u.ao.zData = u.ao.t<12 ? (char*)&u.ao.payloadSize64 : 0;
}else{
- u.an.len = sqlite3VdbeSerialTypeLen(u.an.t);
- sqlite3VdbeMemMove(&u.an.sMem, u.an.pDest);
- rc = sqlite3VdbeMemFromBtree(u.an.pCrsr, u.an.aOffset[u.an.p2], u.an.len, u.an.pC->isIndex,
- &u.an.sMem);
+ u.ao.len = sqlite3VdbeSerialTypeLen(u.ao.t);
+ sqlite3VdbeMemMove(&u.ao.sMem, u.ao.pDest);
+ rc = sqlite3VdbeMemFromBtree(u.ao.pCrsr, u.ao.aOffset[u.ao.p2], u.ao.len, u.ao.pC->isIndex,
+ &u.ao.sMem);
if( rc!=SQLITE_OK ){
goto op_column_out;
}
- u.an.zData = u.an.sMem.z;
+ u.ao.zData = u.ao.sMem.z;
}
- sqlite3VdbeSerialGet((u8*)u.an.zData, u.an.t, u.an.pDest);
+ sqlite3VdbeSerialGet((u8*)u.ao.zData, u.ao.t, u.ao.pDest);
}
- u.an.pDest->enc = encoding;
+ u.ao.pDest->enc = encoding;
}else{
if( pOp->p4type==P4_MEM ){
- sqlite3VdbeMemShallowCopy(u.an.pDest, pOp->p4.pMem, MEM_Static);
+ sqlite3VdbeMemShallowCopy(u.ao.pDest, pOp->p4.pMem, MEM_Static);
}else{
- MemSetTypeFlag(u.an.pDest, MEM_Null);
+ MemSetTypeFlag(u.ao.pDest, MEM_Null);
}
}
/* 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 u.an.pDest structure.
+ ** dynamically allocated space over to the u.ao.pDest structure.
** This prevents a memory copy.
*/
- if( u.an.sMem.zMalloc ){
- assert( u.an.sMem.z==u.an.sMem.zMalloc );
- assert( !(u.an.pDest->flags & MEM_Dyn) );
- assert( !(u.an.pDest->flags & (MEM_Blob|MEM_Str)) || u.an.pDest->z==u.an.sMem.z );
- u.an.pDest->flags &= ~(MEM_Ephem|MEM_Static);
- u.an.pDest->flags |= MEM_Term;
- u.an.pDest->z = u.an.sMem.z;
- u.an.pDest->zMalloc = u.an.sMem.zMalloc;
+ if( u.ao.sMem.zMalloc ){
+ assert( u.ao.sMem.z==u.ao.sMem.zMalloc );
+ assert( !(u.ao.pDest->flags & MEM_Dyn) );
+ assert( !(u.ao.pDest->flags & (MEM_Blob|MEM_Str)) || u.ao.pDest->z==u.ao.sMem.z );
+ u.ao.pDest->flags &= ~(MEM_Ephem|MEM_Static);
+ u.ao.pDest->flags |= MEM_Term;
+ u.ao.pDest->z = u.ao.sMem.z;
+ u.ao.pDest->zMalloc = u.ao.sMem.zMalloc;
}
- rc = sqlite3VdbeMemMakeWriteable(u.an.pDest);
+ rc = sqlite3VdbeMemMakeWriteable(u.ao.pDest);
op_column_out:
- UPDATE_MAX_BLOBSIZE(u.an.pDest);
- REGISTER_TRACE(pOp->p3, u.an.pDest);
+ UPDATE_MAX_BLOBSIZE(u.ao.pDest);
+ REGISTER_TRACE(pOp->p3, u.ao.pDest);
break;
}
@@ -65930,20 +67834,20 @@ op_column_out:
** memory cell in the range.
*/
case OP_Affinity: {
-#if 0 /* local variables moved into u.ao */
+#if 0 /* local variables moved into u.ap */
const char *zAffinity; /* The affinity to be applied */
char cAff; /* A single character of affinity */
-#endif /* local variables moved into u.ao */
+#endif /* local variables moved into u.ap */
- u.ao.zAffinity = pOp->p4.z;
- assert( u.ao.zAffinity!=0 );
- assert( u.ao.zAffinity[pOp->p2]==0 );
+ u.ap.zAffinity = pOp->p4.z;
+ assert( u.ap.zAffinity!=0 );
+ assert( u.ap.zAffinity[pOp->p2]==0 );
pIn1 = &aMem[pOp->p1];
- while( (u.ao.cAff = *(u.ao.zAffinity++))!=0 ){
+ while( (u.ap.cAff = *(u.ap.zAffinity++))!=0 ){
assert( pIn1 <= &p->aMem[p->nMem] );
assert( memIsValid(pIn1) );
ExpandBlob(pIn1);
- applyAffinity(pIn1, u.ao.cAff, encoding);
+ applyAffinity(pIn1, u.ap.cAff, encoding);
pIn1++;
}
break;
@@ -65965,7 +67869,7 @@ case OP_Affinity: {
** If P4 is NULL then all index fields have the affinity NONE.
*/
case OP_MakeRecord: {
-#if 0 /* local variables moved into u.ap */
+#if 0 /* local variables moved into u.aq */
u8 *zNewRecord; /* A buffer to hold the data for the new record */
Mem *pRec; /* The new record */
u64 nData; /* Number of bytes of data space */
@@ -65981,7 +67885,7 @@ case OP_MakeRecord: {
int file_format; /* File format to use for encoding */
int i; /* Space used in zNewRecord[] */
int len; /* Length of a field */
-#endif /* local variables moved into u.ap */
+#endif /* local variables moved into u.aq */
/* Assuming the record contains N fields, the record format looks
** like this:
@@ -65998,16 +67902,16 @@ case OP_MakeRecord: {
** hdr-size field is also a varint which is the offset from the beginning
** of the record to data0.
*/
- u.ap.nData = 0; /* Number of bytes of data space */
- u.ap.nHdr = 0; /* Number of bytes of header space */
- u.ap.nZero = 0; /* Number of zero bytes at the end of the record */
- u.ap.nField = pOp->p1;
- u.ap.zAffinity = pOp->p4.z;
- assert( u.ap.nField>0 && pOp->p2>0 && pOp->p2+u.ap.nField<=p->nMem+1 );
- u.ap.pData0 = &aMem[u.ap.nField];
- u.ap.nField = pOp->p2;
- u.ap.pLast = &u.ap.pData0[u.ap.nField-1];
- u.ap.file_format = p->minWriteFileFormat;
+ u.aq.nData = 0; /* Number of bytes of data space */
+ u.aq.nHdr = 0; /* Number of bytes of header space */
+ u.aq.nZero = 0; /* Number of zero bytes at the end of the record */
+ u.aq.nField = pOp->p1;
+ u.aq.zAffinity = pOp->p4.z;
+ assert( u.aq.nField>0 && pOp->p2>0 && pOp->p2+u.aq.nField<=p->nMem+1 );
+ u.aq.pData0 = &aMem[u.aq.nField];
+ u.aq.nField = pOp->p2;
+ u.aq.pLast = &u.aq.pData0[u.aq.nField-1];
+ u.aq.file_format = p->minWriteFileFormat;
/* Identify the output register */
assert( pOp->p3<pOp->p1 || pOp->p3>=pOp->p1+pOp->p2 );
@@ -66017,34 +67921,34 @@ case OP_MakeRecord: {
/* Loop through the elements that will make up the record to figure
** out how much space is required for the new record.
*/
- for(u.ap.pRec=u.ap.pData0; u.ap.pRec<=u.ap.pLast; u.ap.pRec++){
- assert( memIsValid(u.ap.pRec) );
- if( u.ap.zAffinity ){
- applyAffinity(u.ap.pRec, u.ap.zAffinity[u.ap.pRec-u.ap.pData0], encoding);
+ for(u.aq.pRec=u.aq.pData0; u.aq.pRec<=u.aq.pLast; u.aq.pRec++){
+ assert( memIsValid(u.aq.pRec) );
+ if( u.aq.zAffinity ){
+ applyAffinity(u.aq.pRec, u.aq.zAffinity[u.aq.pRec-u.aq.pData0], encoding);
}
- if( u.ap.pRec->flags&MEM_Zero && u.ap.pRec->n>0 ){
- sqlite3VdbeMemExpandBlob(u.ap.pRec);
+ if( u.aq.pRec->flags&MEM_Zero && u.aq.pRec->n>0 ){
+ sqlite3VdbeMemExpandBlob(u.aq.pRec);
}
- u.ap.serial_type = sqlite3VdbeSerialType(u.ap.pRec, u.ap.file_format);
- u.ap.len = sqlite3VdbeSerialTypeLen(u.ap.serial_type);
- u.ap.nData += u.ap.len;
- u.ap.nHdr += sqlite3VarintLen(u.ap.serial_type);
- if( u.ap.pRec->flags & MEM_Zero ){
+ u.aq.serial_type = sqlite3VdbeSerialType(u.aq.pRec, u.aq.file_format);
+ u.aq.len = sqlite3VdbeSerialTypeLen(u.aq.serial_type);
+ u.aq.nData += u.aq.len;
+ u.aq.nHdr += sqlite3VarintLen(u.aq.serial_type);
+ if( u.aq.pRec->flags & MEM_Zero ){
/* Only pure zero-filled BLOBs can be input to this Opcode.
** We do not allow blobs with a prefix and a zero-filled tail. */
- u.ap.nZero += u.ap.pRec->u.nZero;
- }else if( u.ap.len ){
- u.ap.nZero = 0;
+ u.aq.nZero += u.aq.pRec->u.nZero;
+ }else if( u.aq.len ){
+ u.aq.nZero = 0;
}
}
/* Add the initial header varint and total the size */
- u.ap.nHdr += u.ap.nVarint = sqlite3VarintLen(u.ap.nHdr);
- if( u.ap.nVarint<sqlite3VarintLen(u.ap.nHdr) ){
- u.ap.nHdr++;
+ u.aq.nHdr += u.aq.nVarint = sqlite3VarintLen(u.aq.nHdr);
+ if( u.aq.nVarint<sqlite3VarintLen(u.aq.nHdr) ){
+ u.aq.nHdr++;
}
- u.ap.nByte = u.ap.nHdr+u.ap.nData-u.ap.nZero;
- if( u.ap.nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){
+ u.aq.nByte = u.aq.nHdr+u.aq.nData-u.aq.nZero;
+ if( u.aq.nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){
goto too_big;
}
@@ -66053,28 +67957,28 @@ case OP_MakeRecord: {
** be one of the input registers (because the following call to
** sqlite3VdbeMemGrow() could clobber the value before it is used).
*/
- if( sqlite3VdbeMemGrow(pOut, (int)u.ap.nByte, 0) ){
+ if( sqlite3VdbeMemGrow(pOut, (int)u.aq.nByte, 0) ){
goto no_mem;
}
- u.ap.zNewRecord = (u8 *)pOut->z;
+ u.aq.zNewRecord = (u8 *)pOut->z;
/* Write the record */
- u.ap.i = putVarint32(u.ap.zNewRecord, u.ap.nHdr);
- for(u.ap.pRec=u.ap.pData0; u.ap.pRec<=u.ap.pLast; u.ap.pRec++){
- u.ap.serial_type = sqlite3VdbeSerialType(u.ap.pRec, u.ap.file_format);
- u.ap.i += putVarint32(&u.ap.zNewRecord[u.ap.i], u.ap.serial_type); /* serial type */
+ u.aq.i = putVarint32(u.aq.zNewRecord, u.aq.nHdr);
+ for(u.aq.pRec=u.aq.pData0; u.aq.pRec<=u.aq.pLast; u.aq.pRec++){
+ u.aq.serial_type = sqlite3VdbeSerialType(u.aq.pRec, u.aq.file_format);
+ u.aq.i += putVarint32(&u.aq.zNewRecord[u.aq.i], u.aq.serial_type); /* serial type */
}
- for(u.ap.pRec=u.ap.pData0; u.ap.pRec<=u.ap.pLast; u.ap.pRec++){ /* serial data */
- u.ap.i += sqlite3VdbeSerialPut(&u.ap.zNewRecord[u.ap.i], (int)(u.ap.nByte-u.ap.i),
u.ap.pRec,u.ap.file_format);
+ for(u.aq.pRec=u.aq.pData0; u.aq.pRec<=u.aq.pLast; u.aq.pRec++){ /* serial data */
+ u.aq.i += sqlite3VdbeSerialPut(&u.aq.zNewRecord[u.aq.i], (int)(u.aq.nByte-u.aq.i),
u.aq.pRec,u.aq.file_format);
}
- assert( u.ap.i==u.ap.nByte );
+ assert( u.aq.i==u.aq.nByte );
assert( pOp->p3>0 && pOp->p3<=p->nMem );
- pOut->n = (int)u.ap.nByte;
+ pOut->n = (int)u.aq.nByte;
pOut->flags = MEM_Blob | MEM_Dyn;
pOut->xDel = 0;
- if( u.ap.nZero ){
- pOut->u.nZero = u.ap.nZero;
+ if( u.aq.nZero ){
+ pOut->u.nZero = u.aq.nZero;
pOut->flags |= MEM_Zero;
}
pOut->enc = SQLITE_UTF8; /* In case the blob is ever converted to text */
@@ -66090,18 +67994,18 @@ case OP_MakeRecord: {
*/
#ifndef SQLITE_OMIT_BTREECOUNT
case OP_Count: { /* out2-prerelease */
-#if 0 /* local variables moved into u.aq */
+#if 0 /* local variables moved into u.ar */
i64 nEntry;
BtCursor *pCrsr;
-#endif /* local variables moved into u.aq */
+#endif /* local variables moved into u.ar */
- u.aq.pCrsr = p->apCsr[pOp->p1]->pCursor;
- if( ALWAYS(u.aq.pCrsr) ){
- rc = sqlite3BtreeCount(u.aq.pCrsr, &u.aq.nEntry);
+ u.ar.pCrsr = p->apCsr[pOp->p1]->pCursor;
+ if( ALWAYS(u.ar.pCrsr) ){
+ rc = sqlite3BtreeCount(u.ar.pCrsr, &u.ar.nEntry);
}else{
- u.aq.nEntry = 0;
+ u.ar.nEntry = 0;
}
- pOut->u.i = u.aq.nEntry;
+ pOut->u.i = u.ar.nEntry;
break;
}
#endif
@@ -66113,7 +68017,7 @@ case OP_Count: { /* out2-prerelease */
** existing savepoint, P1==1, or to rollback an existing savepoint P1==2.
*/
case OP_Savepoint: {
-#if 0 /* local variables moved into u.ar */
+#if 0 /* local variables moved into u.as */
int p1; /* Value of P1 operand */
char *zName; /* Name of savepoint */
int nName;
@@ -66122,20 +68026,20 @@ case OP_Savepoint: {
Savepoint *pTmp;
int iSavepoint;
int ii;
-#endif /* local variables moved into u.ar */
+#endif /* local variables moved into u.as */
- u.ar.p1 = pOp->p1;
- u.ar.zName = pOp->p4.z;
+ u.as.p1 = pOp->p1;
+ u.as.zName = pOp->p4.z;
- /* Assert that the u.ar.p1 parameter is valid. Also that if there is no open
+ /* Assert that the u.as.p1 parameter is valid. Also that if there is no open
** transaction, then there cannot be any savepoints.
*/
assert( db->pSavepoint==0 || db->autoCommit==0 );
- assert( u.ar.p1==SAVEPOINT_BEGIN||u.ar.p1==SAVEPOINT_RELEASE||u.ar.p1==SAVEPOINT_ROLLBACK );
+ assert( u.as.p1==SAVEPOINT_BEGIN||u.as.p1==SAVEPOINT_RELEASE||u.as.p1==SAVEPOINT_ROLLBACK );
assert( db->pSavepoint || db->isTransactionSavepoint==0 );
assert( checkSavepointCount(db) );
- if( u.ar.p1==SAVEPOINT_BEGIN ){
+ if( u.as.p1==SAVEPOINT_BEGIN ){
if( db->writeVdbeCnt>0 ){
/* A new savepoint cannot be created if there are active write
** statements (i.e. open read/write incremental blob handles).
@@ -66144,7 +68048,7 @@ case OP_Savepoint: {
"SQL statements in progress");
rc = SQLITE_BUSY;
}else{
- u.ar.nName = sqlite3Strlen30(u.ar.zName);
+ u.as.nName = sqlite3Strlen30(u.as.zName);
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* This call is Ok even if this savepoint is actually a transaction
@@ -66158,10 +68062,10 @@ case OP_Savepoint: {
#endif
/* Create a new savepoint structure. */
- u.ar.pNew = sqlite3DbMallocRaw(db, sizeof(Savepoint)+u.ar.nName+1);
- if( u.ar.pNew ){
- u.ar.pNew->zName = (char *)&u.ar.pNew[1];
- memcpy(u.ar.pNew->zName, u.ar.zName, u.ar.nName+1);
+ u.as.pNew = sqlite3DbMallocRaw(db, sizeof(Savepoint)+u.as.nName+1);
+ if( u.as.pNew ){
+ u.as.pNew->zName = (char *)&u.as.pNew[1];
+ memcpy(u.as.pNew->zName, u.as.zName, u.as.nName+1);
/* If there is no open transaction, then mark this as a special
** "transaction savepoint". */
@@ -66173,27 +68077,27 @@ case OP_Savepoint: {
}
/* Link the new savepoint into the database handle's list. */
- u.ar.pNew->pNext = db->pSavepoint;
- db->pSavepoint = u.ar.pNew;
- u.ar.pNew->nDeferredCons = db->nDeferredCons;
+ u.as.pNew->pNext = db->pSavepoint;
+ db->pSavepoint = u.as.pNew;
+ u.as.pNew->nDeferredCons = db->nDeferredCons;
}
}
}else{
- u.ar.iSavepoint = 0;
+ u.as.iSavepoint = 0;
/* Find the named savepoint. If there is no such savepoint, then an
** an error is returned to the user. */
for(
- u.ar.pSavepoint = db->pSavepoint;
- u.ar.pSavepoint && sqlite3StrICmp(u.ar.pSavepoint->zName, u.ar.zName);
- u.ar.pSavepoint = u.ar.pSavepoint->pNext
+ u.as.pSavepoint = db->pSavepoint;
+ u.as.pSavepoint && sqlite3StrICmp(u.as.pSavepoint->zName, u.as.zName);
+ u.as.pSavepoint = u.as.pSavepoint->pNext
){
- u.ar.iSavepoint++;
+ u.as.iSavepoint++;
}
- if( !u.ar.pSavepoint ){
- sqlite3SetString(&p->zErrMsg, db, "no such savepoint: %s", u.ar.zName);
+ if( !u.as.pSavepoint ){
+ sqlite3SetString(&p->zErrMsg, db, "no such savepoint: %s", u.as.zName);
rc = SQLITE_ERROR;
- }else if( db->writeVdbeCnt>0 && u.ar.p1==SAVEPOINT_RELEASE ){
+ }else if( db->writeVdbeCnt>0 && u.as.p1==SAVEPOINT_RELEASE ){
/* It is not possible to release (commit) a savepoint if there are
** active write statements.
*/
@@ -66207,8 +68111,8 @@ case OP_Savepoint: {
** and this is a RELEASE command, then the current transaction
** is committed.
*/
- int isTransaction = u.ar.pSavepoint->pNext==0 && db->isTransactionSavepoint;
- if( isTransaction && u.ar.p1==SAVEPOINT_RELEASE ){
+ int isTransaction = u.as.pSavepoint->pNext==0 && db->isTransactionSavepoint;
+ if( isTransaction && u.as.p1==SAVEPOINT_RELEASE ){
if( (rc = sqlite3VdbeCheckFk(p, 1))!=SQLITE_OK ){
goto vdbe_return;
}
@@ -66222,19 +68126,19 @@ case OP_Savepoint: {
db->isTransactionSavepoint = 0;
rc = p->rc;
}else{
- u.ar.iSavepoint = db->nSavepoint - u.ar.iSavepoint - 1;
- if( u.ar.p1==SAVEPOINT_ROLLBACK ){
- for(u.ar.ii=0; u.ar.ii<db->nDb; u.ar.ii++){
- sqlite3BtreeTripAllCursors(db->aDb[u.ar.ii].pBt, SQLITE_ABORT);
+ u.as.iSavepoint = db->nSavepoint - u.as.iSavepoint - 1;
+ if( u.as.p1==SAVEPOINT_ROLLBACK ){
+ for(u.as.ii=0; u.as.ii<db->nDb; u.as.ii++){
+ sqlite3BtreeTripAllCursors(db->aDb[u.as.ii].pBt, SQLITE_ABORT);
}
}
- for(u.ar.ii=0; u.ar.ii<db->nDb; u.ar.ii++){
- rc = sqlite3BtreeSavepoint(db->aDb[u.ar.ii].pBt, u.ar.p1, u.ar.iSavepoint);
+ for(u.as.ii=0; u.as.ii<db->nDb; u.as.ii++){
+ rc = sqlite3BtreeSavepoint(db->aDb[u.as.ii].pBt, u.as.p1, u.as.iSavepoint);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
}
- if( u.ar.p1==SAVEPOINT_ROLLBACK && (db->flags&SQLITE_InternChanges)!=0 ){
+ if( u.as.p1==SAVEPOINT_ROLLBACK && (db->flags&SQLITE_InternChanges)!=0 ){
sqlite3ExpirePreparedStatements(db);
sqlite3ResetAllSchemasOfConnection(db);
db->flags = (db->flags | SQLITE_InternChanges);
@@ -66243,10 +68147,10 @@ case OP_Savepoint: {
/* Regardless of whether this is a RELEASE or ROLLBACK, destroy all
** savepoints nested inside of the savepoint being operated on. */
- while( db->pSavepoint!=u.ar.pSavepoint ){
- u.ar.pTmp = db->pSavepoint;
- db->pSavepoint = u.ar.pTmp->pNext;
- sqlite3DbFree(db, u.ar.pTmp);
+ while( db->pSavepoint!=u.as.pSavepoint ){
+ u.as.pTmp = db->pSavepoint;
+ db->pSavepoint = u.as.pTmp->pNext;
+ sqlite3DbFree(db, u.as.pTmp);
db->nSavepoint--;
}
@@ -66254,19 +68158,19 @@ case OP_Savepoint: {
** too. If it is a ROLLBACK TO, then set the number of deferred
** constraint violations present in the database to the value stored
** when the savepoint was created. */
- if( u.ar.p1==SAVEPOINT_RELEASE ){
- assert( u.ar.pSavepoint==db->pSavepoint );
- db->pSavepoint = u.ar.pSavepoint->pNext;
- sqlite3DbFree(db, u.ar.pSavepoint);
+ if( u.as.p1==SAVEPOINT_RELEASE ){
+ assert( u.as.pSavepoint==db->pSavepoint );
+ db->pSavepoint = u.as.pSavepoint->pNext;
+ sqlite3DbFree(db, u.as.pSavepoint);
if( !isTransaction ){
db->nSavepoint--;
}
}else{
- db->nDeferredCons = u.ar.pSavepoint->nDeferredCons;
+ db->nDeferredCons = u.as.pSavepoint->nDeferredCons;
}
if( !isTransaction ){
- rc = sqlite3VtabSavepoint(db, u.ar.p1, u.ar.iSavepoint);
+ rc = sqlite3VtabSavepoint(db, u.as.p1, u.as.iSavepoint);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
}
}
@@ -66285,21 +68189,21 @@ case OP_Savepoint: {
** This instruction causes the VM to halt.
*/
case OP_AutoCommit: {
-#if 0 /* local variables moved into u.as */
+#if 0 /* local variables moved into u.at */
int desiredAutoCommit;
int iRollback;
int turnOnAC;
-#endif /* local variables moved into u.as */
+#endif /* local variables moved into u.at */
- u.as.desiredAutoCommit = pOp->p1;
- u.as.iRollback = pOp->p2;
- u.as.turnOnAC = u.as.desiredAutoCommit && !db->autoCommit;
- assert( u.as.desiredAutoCommit==1 || u.as.desiredAutoCommit==0 );
- assert( u.as.desiredAutoCommit==1 || u.as.iRollback==0 );
+ u.at.desiredAutoCommit = pOp->p1;
+ u.at.iRollback = pOp->p2;
+ u.at.turnOnAC = u.at.desiredAutoCommit && !db->autoCommit;
+ assert( u.at.desiredAutoCommit==1 || u.at.desiredAutoCommit==0 );
+ assert( u.at.desiredAutoCommit==1 || u.at.iRollback==0 );
assert( db->activeVdbeCnt>0 ); /* At least this one VM is active */
#if 0
- if( u.as.turnOnAC && u.as.iRollback && db->activeVdbeCnt>1 ){
+ if( u.at.turnOnAC && u.at.iRollback && db->activeVdbeCnt>1 ){
/* If this instruction implements a ROLLBACK and other VMs are
** still running, and a transaction is active, return an error indicating
** that the other VMs must complete first.
@@ -66309,25 +68213,25 @@ case OP_AutoCommit: {
rc = SQLITE_BUSY;
}else
#endif
- if( u.as.turnOnAC && !u.as.iRollback && db->writeVdbeCnt>0 ){
+ if( u.at.turnOnAC && !u.at.iRollback && db->writeVdbeCnt>0 ){
/* If this instruction implements a COMMIT and other VMs are writing
** return an error indicating that the other VMs must complete first.
*/
sqlite3SetString(&p->zErrMsg, db, "cannot commit transaction - "
"SQL statements in progress");
rc = SQLITE_BUSY;
- }else if( u.as.desiredAutoCommit!=db->autoCommit ){
- if( u.as.iRollback ){
- assert( u.as.desiredAutoCommit==1 );
+ }else if( u.at.desiredAutoCommit!=db->autoCommit ){
+ if( u.at.iRollback ){
+ assert( u.at.desiredAutoCommit==1 );
sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
db->autoCommit = 1;
}else if( (rc = sqlite3VdbeCheckFk(p, 1))!=SQLITE_OK ){
goto vdbe_return;
}else{
- db->autoCommit = (u8)u.as.desiredAutoCommit;
+ db->autoCommit = (u8)u.at.desiredAutoCommit;
if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){
p->pc = pc;
- db->autoCommit = (u8)(1-u.as.desiredAutoCommit);
+ db->autoCommit = (u8)(1-u.at.desiredAutoCommit);
p->rc = rc = SQLITE_BUSY;
goto vdbe_return;
}
@@ -66342,8 +68246,8 @@ case OP_AutoCommit: {
goto vdbe_return;
}else{
sqlite3SetString(&p->zErrMsg, db,
- (!u.as.desiredAutoCommit)?"cannot start a transaction within a transaction":(
- (u.as.iRollback)?"cannot rollback - no transaction is active":
+ (!u.at.desiredAutoCommit)?"cannot start a transaction within a transaction":(
+ (u.at.iRollback)?"cannot rollback - no transaction is active":
"cannot commit - no transaction is active"));
rc = SQLITE_ERROR;
@@ -66383,16 +68287,16 @@ case OP_AutoCommit: {
** If P2 is zero, then a read-lock is obtained on the database file.
*/
case OP_Transaction: {
-#if 0 /* local variables moved into u.at */
+#if 0 /* local variables moved into u.au */
Btree *pBt;
-#endif /* local variables moved into u.at */
+#endif /* local variables moved into u.au */
assert( pOp->p1>=0 && pOp->p1<db->nDb );
assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
- u.at.pBt = db->aDb[pOp->p1].pBt;
+ u.au.pBt = db->aDb[pOp->p1].pBt;
- if( u.at.pBt ){
- rc = sqlite3BtreeBeginTrans(u.at.pBt, pOp->p2);
+ if( u.au.pBt ){
+ rc = sqlite3BtreeBeginTrans(u.au.pBt, pOp->p2);
if( rc==SQLITE_BUSY ){
p->pc = pc;
p->rc = rc = SQLITE_BUSY;
@@ -66405,7 +68309,7 @@ case OP_Transaction: {
if( pOp->p2 && p->usesStmtJournal
&& (db->autoCommit==0 || db->activeVdbeCnt>1)
){
- assert( sqlite3BtreeIsInTrans(u.at.pBt) );
+ assert( sqlite3BtreeIsInTrans(u.au.pBt) );
if( p->iStatement==0 ){
assert( db->nStatement>=0 && db->nSavepoint>=0 );
db->nStatement++;
@@ -66414,7 +68318,7 @@ case OP_Transaction: {
rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN, p->iStatement-1);
if( rc==SQLITE_OK ){
- rc = sqlite3BtreeBeginStmt(u.at.pBt, p->iStatement);
+ rc = sqlite3BtreeBeginStmt(u.au.pBt, p->iStatement);
}
/* Store the current value of the database handles deferred constraint
@@ -66439,21 +68343,21 @@ case OP_Transaction: {
** executing this instruction.
*/
case OP_ReadCookie: { /* out2-prerelease */
-#if 0 /* local variables moved into u.au */
+#if 0 /* local variables moved into u.av */
int iMeta;
int iDb;
int iCookie;
-#endif /* local variables moved into u.au */
+#endif /* local variables moved into u.av */
- u.au.iDb = pOp->p1;
- u.au.iCookie = pOp->p3;
+ u.av.iDb = pOp->p1;
+ u.av.iCookie = pOp->p3;
assert( pOp->p3<SQLITE_N_BTREE_META );
- assert( u.au.iDb>=0 && u.au.iDb<db->nDb );
- assert( db->aDb[u.au.iDb].pBt!=0 );
- assert( (p->btreeMask & (((yDbMask)1)<<u.au.iDb))!=0 );
+ assert( u.av.iDb>=0 && u.av.iDb<db->nDb );
+ assert( db->aDb[u.av.iDb].pBt!=0 );
+ assert( (p->btreeMask & (((yDbMask)1)<<u.av.iDb))!=0 );
- sqlite3BtreeGetMeta(db->aDb[u.au.iDb].pBt, u.au.iCookie, (u32 *)&u.au.iMeta);
- pOut->u.i = u.au.iMeta;
+ sqlite3BtreeGetMeta(db->aDb[u.av.iDb].pBt, u.av.iCookie, (u32 *)&u.av.iMeta);
+ pOut->u.i = u.av.iMeta;
break;
}
@@ -66468,26 +68372,26 @@ case OP_ReadCookie: { /* out2-prerelease */
** A transaction must be started before executing this opcode.
*/
case OP_SetCookie: { /* in3 */
-#if 0 /* local variables moved into u.av */
+#if 0 /* local variables moved into u.aw */
Db *pDb;
-#endif /* local variables moved into u.av */
+#endif /* local variables moved into u.aw */
assert( pOp->p2<SQLITE_N_BTREE_META );
assert( pOp->p1>=0 && pOp->p1<db->nDb );
assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
- u.av.pDb = &db->aDb[pOp->p1];
- assert( u.av.pDb->pBt!=0 );
+ u.aw.pDb = &db->aDb[pOp->p1];
+ assert( u.aw.pDb->pBt!=0 );
assert( sqlite3SchemaMutexHeld(db, pOp->p1, 0) );
pIn3 = &aMem[pOp->p3];
sqlite3VdbeMemIntegerify(pIn3);
/* See note about index shifting on OP_ReadCookie */
- rc = sqlite3BtreeUpdateMeta(u.av.pDb->pBt, pOp->p2, (int)pIn3->u.i);
+ rc = sqlite3BtreeUpdateMeta(u.aw.pDb->pBt, pOp->p2, (int)pIn3->u.i);
if( pOp->p2==BTREE_SCHEMA_VERSION ){
/* When the schema cookie changes, record the new cookie internally */
- u.av.pDb->pSchema->schema_cookie = (int)pIn3->u.i;
+ u.aw.pDb->pSchema->schema_cookie = (int)pIn3->u.i;
db->flags |= SQLITE_InternChanges;
}else if( pOp->p2==BTREE_FILE_FORMAT ){
/* Record changes in the file format */
- u.av.pDb->pSchema->file_format = (u8)pIn3->u.i;
+ u.aw.pDb->pSchema->file_format = (u8)pIn3->u.i;
}
if( pOp->p1==1 ){
/* Invalidate all prepared statements whenever the TEMP database
@@ -66517,23 +68421,23 @@ case OP_SetCookie: { /* in3 */
** invoked.
*/
case OP_VerifyCookie: {
-#if 0 /* local variables moved into u.aw */
+#if 0 /* local variables moved into u.ax */
int iMeta;
int iGen;
Btree *pBt;
-#endif /* local variables moved into u.aw */
+#endif /* local variables moved into u.ax */
assert( pOp->p1>=0 && pOp->p1<db->nDb );
assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
assert( sqlite3SchemaMutexHeld(db, pOp->p1, 0) );
- u.aw.pBt = db->aDb[pOp->p1].pBt;
- if( u.aw.pBt ){
- sqlite3BtreeGetMeta(u.aw.pBt, BTREE_SCHEMA_VERSION, (u32 *)&u.aw.iMeta);
- u.aw.iGen = db->aDb[pOp->p1].pSchema->iGeneration;
+ u.ax.pBt = db->aDb[pOp->p1].pBt;
+ if( u.ax.pBt ){
+ sqlite3BtreeGetMeta(u.ax.pBt, BTREE_SCHEMA_VERSION, (u32 *)&u.ax.iMeta);
+ u.ax.iGen = db->aDb[pOp->p1].pSchema->iGeneration;
}else{
- u.aw.iGen = u.aw.iMeta = 0;
+ u.ax.iGen = u.ax.iMeta = 0;
}
- if( u.aw.iMeta!=pOp->p2 || u.aw.iGen!=pOp->p3 ){
+ if( u.ax.iMeta!=pOp->p2 || u.ax.iGen!=pOp->p3 ){
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed");
/* If the schema-cookie from the database file matches the cookie
@@ -66549,7 +68453,7 @@ case OP_VerifyCookie: {
** to be invalidated whenever sqlite3_step() is called from within
** a v-table method.
*/
- if( db->aDb[pOp->p1].pSchema->schema_cookie!=u.aw.iMeta ){
+ if( db->aDb[pOp->p1].pSchema->schema_cookie!=u.ax.iMeta ){
sqlite3ResetOneSchema(db, pOp->p1);
}
@@ -66610,7 +68514,7 @@ case OP_VerifyCookie: {
*/
case OP_OpenRead:
case OP_OpenWrite: {
-#if 0 /* local variables moved into u.ax */
+#if 0 /* local variables moved into u.ay */
int nField;
KeyInfo *pKeyInfo;
int p2;
@@ -66619,7 +68523,7 @@ case OP_OpenWrite: {
Btree *pX;
VdbeCursor *pCur;
Db *pDb;
-#endif /* local variables moved into u.ax */
+#endif /* local variables moved into u.ay */
assert( (pOp->p5&(OPFLAG_P2ISREG|OPFLAG_BULKCSR))==pOp->p5 );
assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 );
@@ -66629,57 +68533,57 @@ case OP_OpenWrite: {
break;
}
- u.ax.nField = 0;
- u.ax.pKeyInfo = 0;
- u.ax.p2 = pOp->p2;
- u.ax.iDb = pOp->p3;
- assert( u.ax.iDb>=0 && u.ax.iDb<db->nDb );
- assert( (p->btreeMask & (((yDbMask)1)<<u.ax.iDb))!=0 );
- u.ax.pDb = &db->aDb[u.ax.iDb];
- u.ax.pX = u.ax.pDb->pBt;
- assert( u.ax.pX!=0 );
+ u.ay.nField = 0;
+ u.ay.pKeyInfo = 0;
+ u.ay.p2 = pOp->p2;
+ u.ay.iDb = pOp->p3;
+ assert( u.ay.iDb>=0 && u.ay.iDb<db->nDb );
+ assert( (p->btreeMask & (((yDbMask)1)<<u.ay.iDb))!=0 );
+ u.ay.pDb = &db->aDb[u.ay.iDb];
+ u.ay.pX = u.ay.pDb->pBt;
+ assert( u.ay.pX!=0 );
if( pOp->opcode==OP_OpenWrite ){
- u.ax.wrFlag = 1;
- assert( sqlite3SchemaMutexHeld(db, u.ax.iDb, 0) );
- if( u.ax.pDb->pSchema->file_format < p->minWriteFileFormat ){
- p->minWriteFileFormat = u.ax.pDb->pSchema->file_format;
+ u.ay.wrFlag = 1;
+ assert( sqlite3SchemaMutexHeld(db, u.ay.iDb, 0) );
+ if( u.ay.pDb->pSchema->file_format < p->minWriteFileFormat ){
+ p->minWriteFileFormat = u.ay.pDb->pSchema->file_format;
}
}else{
- u.ax.wrFlag = 0;
+ u.ay.wrFlag = 0;
}
if( pOp->p5 & OPFLAG_P2ISREG ){
- assert( u.ax.p2>0 );
- assert( u.ax.p2<=p->nMem );
- pIn2 = &aMem[u.ax.p2];
+ assert( u.ay.p2>0 );
+ assert( u.ay.p2<=p->nMem );
+ pIn2 = &aMem[u.ay.p2];
assert( memIsValid(pIn2) );
assert( (pIn2->flags & MEM_Int)!=0 );
sqlite3VdbeMemIntegerify(pIn2);
- u.ax.p2 = (int)pIn2->u.i;
- /* The u.ax.p2 value always comes from a prior OP_CreateTable opcode and
- ** that opcode will always set the u.ax.p2 value to 2 or more or else fail.
+ u.ay.p2 = (int)pIn2->u.i;
+ /* The u.ay.p2 value always comes from a prior OP_CreateTable opcode and
+ ** that opcode will always set the u.ay.p2 value to 2 or more or else fail.
** If there were a failure, the prepared statement would have halted
** before reaching this instruction. */
- if( NEVER(u.ax.p2<2) ) {
+ if( NEVER(u.ay.p2<2) ) {
rc = SQLITE_CORRUPT_BKPT;
goto abort_due_to_error;
}
}
if( pOp->p4type==P4_KEYINFO ){
- u.ax.pKeyInfo = pOp->p4.pKeyInfo;
- u.ax.pKeyInfo->enc = ENC(p->db);
- u.ax.nField = u.ax.pKeyInfo->nField+1;
+ u.ay.pKeyInfo = pOp->p4.pKeyInfo;
+ u.ay.pKeyInfo->enc = ENC(p->db);
+ u.ay.nField = u.ay.pKeyInfo->nField+1;
}else if( pOp->p4type==P4_INT32 ){
- u.ax.nField = pOp->p4.i;
+ u.ay.nField = pOp->p4.i;
}
assert( pOp->p1>=0 );
- u.ax.pCur = allocateCursor(p, pOp->p1, u.ax.nField, u.ax.iDb, 1);
- if( u.ax.pCur==0 ) goto no_mem;
- u.ax.pCur->nullRow = 1;
- u.ax.pCur->isOrdered = 1;
- rc = sqlite3BtreeCursor(u.ax.pX, u.ax.p2, u.ax.wrFlag, u.ax.pKeyInfo, u.ax.pCur->pCursor);
- u.ax.pCur->pKeyInfo = u.ax.pKeyInfo;
+ u.ay.pCur = allocateCursor(p, pOp->p1, u.ay.nField, u.ay.iDb, 1);
+ if( u.ay.pCur==0 ) goto no_mem;
+ u.ay.pCur->nullRow = 1;
+ u.ay.pCur->isOrdered = 1;
+ rc = sqlite3BtreeCursor(u.ay.pX, u.ay.p2, u.ay.wrFlag, u.ay.pKeyInfo, u.ay.pCur->pCursor);
+ u.ay.pCur->pKeyInfo = u.ay.pKeyInfo;
assert( OPFLAG_BULKCSR==BTREE_BULKLOAD );
- sqlite3BtreeCursorHints(u.ax.pCur->pCursor, (pOp->p5 & OPFLAG_BULKCSR));
+ sqlite3BtreeCursorHints(u.ay.pCur->pCursor, (pOp->p5 & OPFLAG_BULKCSR));
/* Since it performs no memory allocation or IO, the only value that
** sqlite3BtreeCursor() may return is SQLITE_OK. */
@@ -66689,8 +68593,8 @@ case OP_OpenWrite: {
** 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. */
- u.ax.pCur->isTable = pOp->p4type!=P4_KEYINFO;
- u.ax.pCur->isIndex = !u.ax.pCur->isTable;
+ u.ay.pCur->isTable = pOp->p4type!=P4_KEYINFO;
+ u.ay.pCur->isIndex = !u.ay.pCur->isTable;
break;
}
@@ -66726,9 +68630,9 @@ case OP_OpenWrite: {
*/
case OP_OpenAutoindex:
case OP_OpenEphemeral: {
-#if 0 /* local variables moved into u.ay */
+#if 0 /* local variables moved into u.az */
VdbeCursor *pCx;
-#endif /* local variables moved into u.ay */
+#endif /* local variables moved into u.az */
static const int vfsFlags =
SQLITE_OPEN_READWRITE |
SQLITE_OPEN_CREATE |
@@ -66737,13 +68641,13 @@ case OP_OpenEphemeral: {
SQLITE_OPEN_TRANSIENT_DB;
assert( pOp->p1>=0 );
- u.ay.pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
- if( u.ay.pCx==0 ) goto no_mem;
- u.ay.pCx->nullRow = 1;
- rc = sqlite3BtreeOpen(db->pVfs, 0, db, &u.ay.pCx->pBt,
+ u.az.pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
+ if( u.az.pCx==0 ) goto no_mem;
+ u.az.pCx->nullRow = 1;
+ rc = sqlite3BtreeOpen(db->pVfs, 0, db, &u.az.pCx->pBt,
BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags);
if( rc==SQLITE_OK ){
- rc = sqlite3BtreeBeginTrans(u.ay.pCx->pBt, 1);
+ rc = sqlite3BtreeBeginTrans(u.az.pCx->pBt, 1);
}
if( rc==SQLITE_OK ){
/* If a transient index is required, create it by calling
@@ -66754,55 +68658,52 @@ case OP_OpenEphemeral: {
if( pOp->p4.pKeyInfo ){
int pgno;
assert( pOp->p4type==P4_KEYINFO );
- rc = sqlite3BtreeCreateTable(u.ay.pCx->pBt, &pgno, BTREE_BLOBKEY | pOp->p5);
+ rc = sqlite3BtreeCreateTable(u.az.pCx->pBt, &pgno, BTREE_BLOBKEY | pOp->p5);
if( rc==SQLITE_OK ){
assert( pgno==MASTER_ROOT+1 );
- rc = sqlite3BtreeCursor(u.ay.pCx->pBt, pgno, 1,
- (KeyInfo*)pOp->p4.z, u.ay.pCx->pCursor);
- u.ay.pCx->pKeyInfo = pOp->p4.pKeyInfo;
- u.ay.pCx->pKeyInfo->enc = ENC(p->db);
+ rc = sqlite3BtreeCursor(u.az.pCx->pBt, pgno, 1,
+ (KeyInfo*)pOp->p4.z, u.az.pCx->pCursor);
+ u.az.pCx->pKeyInfo = pOp->p4.pKeyInfo;
+ u.az.pCx->pKeyInfo->enc = ENC(p->db);
}
- u.ay.pCx->isTable = 0;
+ u.az.pCx->isTable = 0;
}else{
- rc = sqlite3BtreeCursor(u.ay.pCx->pBt, MASTER_ROOT, 1, 0, u.ay.pCx->pCursor);
- u.ay.pCx->isTable = 1;
+ rc = sqlite3BtreeCursor(u.az.pCx->pBt, MASTER_ROOT, 1, 0, u.az.pCx->pCursor);
+ u.az.pCx->isTable = 1;
}
}
- u.ay.pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
- u.ay.pCx->isIndex = !u.ay.pCx->isTable;
+ u.az.pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
+ u.az.pCx->isIndex = !u.az.pCx->isTable;
break;
}
-/* Opcode: OpenSorter P1 P2 * P4 *
+/* Opcode: SorterOpen P1 P2 * 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.
*/
case OP_SorterOpen: {
-#if 0 /* local variables moved into u.az */
+#if 0 /* local variables moved into u.ba */
VdbeCursor *pCx;
-#endif /* local variables moved into u.az */
-#ifndef SQLITE_OMIT_MERGE_SORT
- u.az.pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
- if( u.az.pCx==0 ) goto no_mem;
- u.az.pCx->pKeyInfo = pOp->p4.pKeyInfo;
- u.az.pCx->pKeyInfo->enc = ENC(p->db);
- u.az.pCx->isSorter = 1;
- rc = sqlite3VdbeSorterInit(db, u.az.pCx);
-#else
- pOp->opcode = OP_OpenEphemeral;
- pc--;
-#endif
+#endif /* local variables moved into u.ba */
+
+ u.ba.pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
+ if( u.ba.pCx==0 ) goto no_mem;
+ u.ba.pCx->pKeyInfo = pOp->p4.pKeyInfo;
+ u.ba.pCx->pKeyInfo->enc = ENC(p->db);
+ u.ba.pCx->isSorter = 1;
+ rc = sqlite3VdbeSorterInit(db, u.ba.pCx);
break;
}
-/* Opcode: OpenPseudo P1 P2 P3 * *
+/* Opcode: OpenPseudo P1 P2 P3 * P5
**
** Open a new cursor that points to a fake table that contains a single
** row of data. The content of that one row in the content of memory
-** register P2. In other words, cursor P1 becomes an alias for the
-** MEM_Blob content contained in register P2.
+** register P2 when P5==0. In other words, cursor P1 becomes an alias for the
+** MEM_Blob content contained in register P2. When P5==1, then the
+** row is represented by P3 consecutive registers beginning with P2.
**
** A pseudo-table created by this opcode is used to hold a single
** row output from the sorter so that the row can be decomposed into
@@ -66813,17 +68714,18 @@ case OP_SorterOpen: {
** the pseudo-table.
*/
case OP_OpenPseudo: {
-#if 0 /* local variables moved into u.ba */
+#if 0 /* local variables moved into u.bb */
VdbeCursor *pCx;
-#endif /* local variables moved into u.ba */
+#endif /* local variables moved into u.bb */
assert( pOp->p1>=0 );
- u.ba.pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, 0);
- if( u.ba.pCx==0 ) goto no_mem;
- u.ba.pCx->nullRow = 1;
- u.ba.pCx->pseudoTableReg = pOp->p2;
- u.ba.pCx->isTable = 1;
- u.ba.pCx->isIndex = 0;
+ u.bb.pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, 0);
+ if( u.bb.pCx==0 ) goto no_mem;
+ u.bb.pCx->nullRow = 1;
+ u.bb.pCx->pseudoTableReg = pOp->p2;
+ u.bb.pCx->isTable = 1;
+ u.bb.pCx->isIndex = 0;
+ u.bb.pCx->multiPseudo = pOp->p5;
break;
}
@@ -66895,35 +68797,35 @@ case OP_SeekLt: /* jump, in3 */
case OP_SeekLe: /* jump, in3 */
case OP_SeekGe: /* jump, in3 */
case OP_SeekGt: { /* jump, in3 */
-#if 0 /* local variables moved into u.bb */
+#if 0 /* local variables moved into u.bc */
int res;
int oc;
VdbeCursor *pC;
UnpackedRecord r;
int nField;
i64 iKey; /* The rowid we are to seek to */
-#endif /* local variables moved into u.bb */
+#endif /* local variables moved into u.bc */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( pOp->p2!=0 );
- u.bb.pC = p->apCsr[pOp->p1];
- assert( u.bb.pC!=0 );
- assert( u.bb.pC->pseudoTableReg==0 );
+ u.bc.pC = p->apCsr[pOp->p1];
+ assert( u.bc.pC!=0 );
+ assert( u.bc.pC->pseudoTableReg==0 );
assert( OP_SeekLe == OP_SeekLt+1 );
assert( OP_SeekGe == OP_SeekLt+2 );
assert( OP_SeekGt == OP_SeekLt+3 );
- assert( u.bb.pC->isOrdered );
- if( ALWAYS(u.bb.pC->pCursor!=0) ){
- u.bb.oc = pOp->opcode;
- u.bb.pC->nullRow = 0;
- if( u.bb.pC->isTable ){
+ assert( u.bc.pC->isOrdered );
+ if( ALWAYS(u.bc.pC->pCursor!=0) ){
+ u.bc.oc = pOp->opcode;
+ u.bc.pC->nullRow = 0;
+ if( u.bc.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. */
pIn3 = &aMem[pOp->p3];
applyNumericAffinity(pIn3);
- u.bb.iKey = sqlite3VdbeIntValue(pIn3);
- u.bb.pC->rowidIsValid = 0;
+ u.bc.iKey = sqlite3VdbeIntValue(pIn3);
+ u.bc.pC->rowidIsValid = 0;
/* If the P3 value could not be converted into an integer without
** loss of information, then special processing is required... */
@@ -66938,101 +68840,101 @@ case OP_SeekGt: { /* jump, in3 */
** point number. */
assert( (pIn3->flags & MEM_Real)!=0 );
- if( u.bb.iKey==SMALLEST_INT64 && (pIn3->r<(double)u.bb.iKey || pIn3->r>0) ){
+ if( u.bc.iKey==SMALLEST_INT64 && (pIn3->r<(double)u.bc.iKey || pIn3->r>0) ){
/* The P3 value is too large in magnitude to be expressed as an
** integer. */
- u.bb.res = 1;
+ u.bc.res = 1;
if( pIn3->r<0 ){
- if( u.bb.oc>=OP_SeekGe ){ assert( u.bb.oc==OP_SeekGe || u.bb.oc==OP_SeekGt );
- rc = sqlite3BtreeFirst(u.bb.pC->pCursor, &u.bb.res);
+ if( u.bc.oc>=OP_SeekGe ){ assert( u.bc.oc==OP_SeekGe || u.bc.oc==OP_SeekGt );
+ rc = sqlite3BtreeFirst(u.bc.pC->pCursor, &u.bc.res);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
}
}else{
- if( u.bb.oc<=OP_SeekLe ){ assert( u.bb.oc==OP_SeekLt || u.bb.oc==OP_SeekLe );
- rc = sqlite3BtreeLast(u.bb.pC->pCursor, &u.bb.res);
+ if( u.bc.oc<=OP_SeekLe ){ assert( u.bc.oc==OP_SeekLt || u.bc.oc==OP_SeekLe );
+ rc = sqlite3BtreeLast(u.bc.pC->pCursor, &u.bc.res);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
}
}
- if( u.bb.res ){
+ if( u.bc.res ){
pc = pOp->p2 - 1;
}
break;
- }else if( u.bb.oc==OP_SeekLt || u.bb.oc==OP_SeekGe ){
+ }else if( u.bc.oc==OP_SeekLt || u.bc.oc==OP_SeekGe ){
/* Use the ceiling() function to convert real->int */
- if( pIn3->r > (double)u.bb.iKey ) u.bb.iKey++;
+ if( pIn3->r > (double)u.bc.iKey ) u.bc.iKey++;
}else{
/* Use the floor() function to convert real->int */
- assert( u.bb.oc==OP_SeekLe || u.bb.oc==OP_SeekGt );
- if( pIn3->r < (double)u.bb.iKey ) u.bb.iKey--;
+ assert( u.bc.oc==OP_SeekLe || u.bc.oc==OP_SeekGt );
+ if( pIn3->r < (double)u.bc.iKey ) u.bc.iKey--;
}
}
- rc = sqlite3BtreeMovetoUnpacked(u.bb.pC->pCursor, 0, (u64)u.bb.iKey, 0, &u.bb.res);
+ rc = sqlite3BtreeMovetoUnpacked(u.bc.pC->pCursor, 0, (u64)u.bc.iKey, 0, &u.bc.res);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
- if( u.bb.res==0 ){
- u.bb.pC->rowidIsValid = 1;
- u.bb.pC->lastRowid = u.bb.iKey;
+ if( u.bc.res==0 ){
+ u.bc.pC->rowidIsValid = 1;
+ u.bc.pC->lastRowid = u.bc.iKey;
}
}else{
- u.bb.nField = pOp->p4.i;
+ u.bc.nField = pOp->p4.i;
assert( pOp->p4type==P4_INT32 );
- assert( u.bb.nField>0 );
- u.bb.r.pKeyInfo = u.bb.pC->pKeyInfo;
- u.bb.r.nField = (u16)u.bb.nField;
+ assert( u.bc.nField>0 );
+ u.bc.r.pKeyInfo = u.bc.pC->pKeyInfo;
+ u.bc.r.nField = (u16)u.bc.nField;
/* The next line of code computes as follows, only faster:
- ** if( u.bb.oc==OP_SeekGt || u.bb.oc==OP_SeekLe ){
- ** u.bb.r.flags = UNPACKED_INCRKEY;
+ ** if( u.bc.oc==OP_SeekGt || u.bc.oc==OP_SeekLe ){
+ ** u.bc.r.flags = UNPACKED_INCRKEY;
** }else{
- ** u.bb.r.flags = 0;
+ ** u.bc.r.flags = 0;
** }
*/
- u.bb.r.flags = (u16)(UNPACKED_INCRKEY * (1 & (u.bb.oc - OP_SeekLt)));
- assert( u.bb.oc!=OP_SeekGt || u.bb.r.flags==UNPACKED_INCRKEY );
- assert( u.bb.oc!=OP_SeekLe || u.bb.r.flags==UNPACKED_INCRKEY );
- assert( u.bb.oc!=OP_SeekGe || u.bb.r.flags==0 );
- assert( u.bb.oc!=OP_SeekLt || u.bb.r.flags==0 );
+ u.bc.r.flags = (u8)(UNPACKED_INCRKEY * (1 & (u.bc.oc - OP_SeekLt)));
+ assert( u.bc.oc!=OP_SeekGt || u.bc.r.flags==UNPACKED_INCRKEY );
+ assert( u.bc.oc!=OP_SeekLe || u.bc.r.flags==UNPACKED_INCRKEY );
+ assert( u.bc.oc!=OP_SeekGe || u.bc.r.flags==0 );
+ assert( u.bc.oc!=OP_SeekLt || u.bc.r.flags==0 );
- u.bb.r.aMem = &aMem[pOp->p3];
+ u.bc.r.aMem = &aMem[pOp->p3];
#ifdef SQLITE_DEBUG
- { int i; for(i=0; i<u.bb.r.nField; i++) assert( memIsValid(&u.bb.r.aMem[i]) ); }
+ { int i; for(i=0; i<u.bc.r.nField; i++) assert( memIsValid(&u.bc.r.aMem[i]) ); }
#endif
- ExpandBlob(u.bb.r.aMem);
- rc = sqlite3BtreeMovetoUnpacked(u.bb.pC->pCursor, &u.bb.r, 0, 0, &u.bb.res);
+ ExpandBlob(u.bc.r.aMem);
+ rc = sqlite3BtreeMovetoUnpacked(u.bc.pC->pCursor, &u.bc.r, 0, 0, &u.bc.res);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
- u.bb.pC->rowidIsValid = 0;
+ u.bc.pC->rowidIsValid = 0;
}
- u.bb.pC->deferredMoveto = 0;
- u.bb.pC->cacheStatus = CACHE_STALE;
+ u.bc.pC->deferredMoveto = 0;
+ u.bc.pC->cacheStatus = CACHE_STALE;
#ifdef SQLITE_TEST
sqlite3_search_count++;
#endif
- if( u.bb.oc>=OP_SeekGe ){ assert( u.bb.oc==OP_SeekGe || u.bb.oc==OP_SeekGt );
- if( u.bb.res<0 || (u.bb.res==0 && u.bb.oc==OP_SeekGt) ){
- rc = sqlite3BtreeNext(u.bb.pC->pCursor, &u.bb.res);
+ if( u.bc.oc>=OP_SeekGe ){ assert( u.bc.oc==OP_SeekGe || u.bc.oc==OP_SeekGt );
+ if( u.bc.res<0 || (u.bc.res==0 && u.bc.oc==OP_SeekGt) ){
+ rc = sqlite3BtreeNext(u.bc.pC->pCursor, &u.bc.res);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
- u.bb.pC->rowidIsValid = 0;
+ u.bc.pC->rowidIsValid = 0;
}else{
- u.bb.res = 0;
+ u.bc.res = 0;
}
}else{
- assert( u.bb.oc==OP_SeekLt || u.bb.oc==OP_SeekLe );
- if( u.bb.res>0 || (u.bb.res==0 && u.bb.oc==OP_SeekLt) ){
- rc = sqlite3BtreePrevious(u.bb.pC->pCursor, &u.bb.res);
+ assert( u.bc.oc==OP_SeekLt || u.bc.oc==OP_SeekLe );
+ if( u.bc.res>0 || (u.bc.res==0 && u.bc.oc==OP_SeekLt) ){
+ rc = sqlite3BtreePrevious(u.bc.pC->pCursor, &u.bc.res);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
- u.bb.pC->rowidIsValid = 0;
+ u.bc.pC->rowidIsValid = 0;
}else{
- /* u.bb.res might be negative because the table is empty. Check to
+ /* u.bc.res might be negative because the table is empty. Check to
** see if this is the case.
*/
- u.bb.res = sqlite3BtreeEof(u.bb.pC->pCursor);
+ u.bc.res = sqlite3BtreeEof(u.bc.pC->pCursor);
}
}
assert( pOp->p2>0 );
- if( u.bb.res ){
+ if( u.bc.res ){
pc = pOp->p2 - 1;
}
}else{
@@ -67055,20 +68957,20 @@ case OP_SeekGt: { /* jump, in3 */
** occur, no unnecessary I/O happens.
*/
case OP_Seek: { /* in2 */
-#if 0 /* local variables moved into u.bc */
+#if 0 /* local variables moved into u.bd */
VdbeCursor *pC;
-#endif /* local variables moved into u.bc */
+#endif /* local variables moved into u.bd */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- u.bc.pC = p->apCsr[pOp->p1];
- assert( u.bc.pC!=0 );
- if( ALWAYS(u.bc.pC->pCursor!=0) ){
- assert( u.bc.pC->isTable );
- u.bc.pC->nullRow = 0;
+ u.bd.pC = p->apCsr[pOp->p1];
+ assert( u.bd.pC!=0 );
+ if( ALWAYS(u.bd.pC->pCursor!=0) ){
+ assert( u.bd.pC->isTable );
+ u.bd.pC->nullRow = 0;
pIn2 = &aMem[pOp->p2];
- u.bc.pC->movetoTarget = sqlite3VdbeIntValue(pIn2);
- u.bc.pC->rowidIsValid = 0;
- u.bc.pC->deferredMoveto = 1;
+ u.bd.pC->movetoTarget = sqlite3VdbeIntValue(pIn2);
+ u.bd.pC->rowidIsValid = 0;
+ u.bd.pC->deferredMoveto = 1;
}
break;
}
@@ -67100,7 +69002,7 @@ case OP_Seek: { /* in2 */
*/
case OP_NotFound: /* jump, in3 */
case OP_Found: { /* jump, in3 */
-#if 0 /* local variables moved into u.bd */
+#if 0 /* local variables moved into u.be */
int alreadyExists;
VdbeCursor *pC;
int res;
@@ -67108,55 +69010,55 @@ case OP_Found: { /* jump, in3 */
UnpackedRecord *pIdxKey;
UnpackedRecord r;
char aTempRec[ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*3 + 7];
-#endif /* local variables moved into u.bd */
+#endif /* local variables moved into u.be */
#ifdef SQLITE_TEST
sqlite3_found_count++;
#endif
- u.bd.alreadyExists = 0;
+ u.be.alreadyExists = 0;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( pOp->p4type==P4_INT32 );
- u.bd.pC = p->apCsr[pOp->p1];
- assert( u.bd.pC!=0 );
+ u.be.pC = p->apCsr[pOp->p1];
+ assert( u.be.pC!=0 );
pIn3 = &aMem[pOp->p3];
- if( ALWAYS(u.bd.pC->pCursor!=0) ){
+ if( ALWAYS(u.be.pC->pCursor!=0) ){
- assert( u.bd.pC->isTable==0 );
+ assert( u.be.pC->isTable==0 );
if( pOp->p4.i>0 ){
- u.bd.r.pKeyInfo = u.bd.pC->pKeyInfo;
- u.bd.r.nField = (u16)pOp->p4.i;
- u.bd.r.aMem = pIn3;
+ u.be.r.pKeyInfo = u.be.pC->pKeyInfo;
+ u.be.r.nField = (u16)pOp->p4.i;
+ u.be.r.aMem = pIn3;
#ifdef SQLITE_DEBUG
- { int i; for(i=0; i<u.bd.r.nField; i++) assert( memIsValid(&u.bd.r.aMem[i]) ); }
+ { int i; for(i=0; i<u.be.r.nField; i++) assert( memIsValid(&u.be.r.aMem[i]) ); }
#endif
- u.bd.r.flags = UNPACKED_PREFIX_MATCH;
- u.bd.pIdxKey = &u.bd.r;
+ u.be.r.flags = UNPACKED_PREFIX_MATCH;
+ u.be.pIdxKey = &u.be.r;
}else{
- u.bd.pIdxKey = sqlite3VdbeAllocUnpackedRecord(
- u.bd.pC->pKeyInfo, u.bd.aTempRec, sizeof(u.bd.aTempRec), &u.bd.pFree
+ u.be.pIdxKey = sqlite3VdbeAllocUnpackedRecord(
+ u.be.pC->pKeyInfo, u.be.aTempRec, sizeof(u.be.aTempRec), &u.be.pFree
);
- if( u.bd.pIdxKey==0 ) goto no_mem;
+ if( u.be.pIdxKey==0 ) goto no_mem;
assert( pIn3->flags & MEM_Blob );
assert( (pIn3->flags & MEM_Zero)==0 ); /* zeroblobs already expanded */
- sqlite3VdbeRecordUnpack(u.bd.pC->pKeyInfo, pIn3->n, pIn3->z, u.bd.pIdxKey);
- u.bd.pIdxKey->flags |= UNPACKED_PREFIX_MATCH;
+ sqlite3VdbeRecordUnpack(u.be.pC->pKeyInfo, pIn3->n, pIn3->z, u.be.pIdxKey);
+ u.be.pIdxKey->flags |= UNPACKED_PREFIX_MATCH;
}
- rc = sqlite3BtreeMovetoUnpacked(u.bd.pC->pCursor, u.bd.pIdxKey, 0, 0, &u.bd.res);
+ rc = sqlite3BtreeMovetoUnpacked(u.be.pC->pCursor, u.be.pIdxKey, 0, 0, &u.be.res);
if( pOp->p4.i==0 ){
- sqlite3DbFree(db, u.bd.pFree);
+ sqlite3DbFree(db, u.be.pFree);
}
if( rc!=SQLITE_OK ){
break;
}
- u.bd.alreadyExists = (u.bd.res==0);
- u.bd.pC->deferredMoveto = 0;
- u.bd.pC->cacheStatus = CACHE_STALE;
+ u.be.alreadyExists = (u.be.res==0);
+ u.be.pC->deferredMoveto = 0;
+ u.be.pC->cacheStatus = CACHE_STALE;
}
if( pOp->opcode==OP_Found ){
- if( u.bd.alreadyExists ) pc = pOp->p2 - 1;
+ if( u.be.alreadyExists ) pc = pOp->p2 - 1;
}else{
- if( !u.bd.alreadyExists ) pc = pOp->p2 - 1;
+ if( !u.be.alreadyExists ) pc = pOp->p2 - 1;
}
break;
}
@@ -67188,7 +69090,7 @@ case OP_Found: { /* jump, in3 */
** See also: NotFound, NotExists, Found
*/
case OP_IsUnique: { /* jump, in3 */
-#if 0 /* local variables moved into u.be */
+#if 0 /* local variables moved into u.bf */
u16 ii;
VdbeCursor *pCx;
BtCursor *pCrsr;
@@ -67196,55 +69098,55 @@ case OP_IsUnique: { /* jump, in3 */
Mem *aMx;
UnpackedRecord r; /* B-Tree index search key */
i64 R; /* Rowid stored in register P3 */
-#endif /* local variables moved into u.be */
+#endif /* local variables moved into u.bf */
pIn3 = &aMem[pOp->p3];
- u.be.aMx = &aMem[pOp->p4.i];
+ u.bf.aMx = &aMem[pOp->p4.i];
/* Assert that the values of parameters P1 and P4 are in range. */
assert( pOp->p4type==P4_INT32 );
assert( pOp->p4.i>0 && pOp->p4.i<=p->nMem );
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
/* Find the index cursor. */
- u.be.pCx = p->apCsr[pOp->p1];
- assert( u.be.pCx->deferredMoveto==0 );
- u.be.pCx->seekResult = 0;
- u.be.pCx->cacheStatus = CACHE_STALE;
- u.be.pCrsr = u.be.pCx->pCursor;
+ u.bf.pCx = p->apCsr[pOp->p1];
+ assert( u.bf.pCx->deferredMoveto==0 );
+ u.bf.pCx->seekResult = 0;
+ u.bf.pCx->cacheStatus = CACHE_STALE;
+ u.bf.pCrsr = u.bf.pCx->pCursor;
/* If any of the values are NULL, take the jump. */
- u.be.nField = u.be.pCx->pKeyInfo->nField;
- for(u.be.ii=0; u.be.ii<u.be.nField; u.be.ii++){
- if( u.be.aMx[u.be.ii].flags & MEM_Null ){
+ u.bf.nField = u.bf.pCx->pKeyInfo->nField;
+ for(u.bf.ii=0; u.bf.ii<u.bf.nField; u.bf.ii++){
+ if( u.bf.aMx[u.bf.ii].flags & MEM_Null ){
pc = pOp->p2 - 1;
- u.be.pCrsr = 0;
+ u.bf.pCrsr = 0;
break;
}
}
- assert( (u.be.aMx[u.be.nField].flags & MEM_Null)==0 );
+ assert( (u.bf.aMx[u.bf.nField].flags & MEM_Null)==0 );
- if( u.be.pCrsr!=0 ){
+ if( u.bf.pCrsr!=0 ){
/* Populate the index search key. */
- u.be.r.pKeyInfo = u.be.pCx->pKeyInfo;
- u.be.r.nField = u.be.nField + 1;
- u.be.r.flags = UNPACKED_PREFIX_SEARCH;
- u.be.r.aMem = u.be.aMx;
+ u.bf.r.pKeyInfo = u.bf.pCx->pKeyInfo;
+ u.bf.r.nField = u.bf.nField + 1;
+ u.bf.r.flags = UNPACKED_PREFIX_SEARCH;
+ u.bf.r.aMem = u.bf.aMx;
#ifdef SQLITE_DEBUG
- { int i; for(i=0; i<u.be.r.nField; i++) assert( memIsValid(&u.be.r.aMem[i]) ); }
+ { int i; for(i=0; i<u.bf.r.nField; i++) assert( memIsValid(&u.bf.r.aMem[i]) ); }
#endif
- /* Extract the value of u.be.R from register P3. */
+ /* Extract the value of u.bf.R from register P3. */
sqlite3VdbeMemIntegerify(pIn3);
- u.be.R = pIn3->u.i;
+ u.bf.R = pIn3->u.i;
/* Search the B-Tree index. If no conflicting record is found, jump
** to P2. Otherwise, copy the rowid of the conflicting record to
** register P3 and fall through to the next instruction. */
- rc = sqlite3BtreeMovetoUnpacked(u.be.pCrsr, &u.be.r, 0, 0, &u.be.pCx->seekResult);
- if( (u.be.r.flags & UNPACKED_PREFIX_SEARCH) || u.be.r.rowid==u.be.R ){
+ rc = sqlite3BtreeMovetoUnpacked(u.bf.pCrsr, &u.bf.r, 0, 0, &u.bf.pCx->seekResult);
+ if( (u.bf.r.flags & UNPACKED_PREFIX_SEARCH) || u.bf.r.rowid==u.bf.R ){
pc = pOp->p2 - 1;
}else{
- pIn3->u.i = u.be.r.rowid;
+ pIn3->u.i = u.bf.r.rowid;
}
}
break;
@@ -67265,42 +69167,42 @@ case OP_IsUnique: { /* jump, in3 */
** See also: Found, NotFound, IsUnique
*/
case OP_NotExists: { /* jump, in3 */
-#if 0 /* local variables moved into u.bf */
+#if 0 /* local variables moved into u.bg */
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
u64 iKey;
-#endif /* local variables moved into u.bf */
+#endif /* local variables moved into u.bg */
pIn3 = &aMem[pOp->p3];
assert( pIn3->flags & MEM_Int );
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- u.bf.pC = p->apCsr[pOp->p1];
- assert( u.bf.pC!=0 );
- assert( u.bf.pC->isTable );
- assert( u.bf.pC->pseudoTableReg==0 );
- u.bf.pCrsr = u.bf.pC->pCursor;
- if( ALWAYS(u.bf.pCrsr!=0) ){
- u.bf.res = 0;
- u.bf.iKey = pIn3->u.i;
- rc = sqlite3BtreeMovetoUnpacked(u.bf.pCrsr, 0, u.bf.iKey, 0, &u.bf.res);
- u.bf.pC->lastRowid = pIn3->u.i;
- u.bf.pC->rowidIsValid = u.bf.res==0 ?1:0;
- u.bf.pC->nullRow = 0;
- u.bf.pC->cacheStatus = CACHE_STALE;
- u.bf.pC->deferredMoveto = 0;
- if( u.bf.res!=0 ){
+ u.bg.pC = p->apCsr[pOp->p1];
+ assert( u.bg.pC!=0 );
+ assert( u.bg.pC->isTable );
+ assert( u.bg.pC->pseudoTableReg==0 );
+ u.bg.pCrsr = u.bg.pC->pCursor;
+ if( ALWAYS(u.bg.pCrsr!=0) ){
+ u.bg.res = 0;
+ u.bg.iKey = pIn3->u.i;
+ rc = sqlite3BtreeMovetoUnpacked(u.bg.pCrsr, 0, u.bg.iKey, 0, &u.bg.res);
+ u.bg.pC->lastRowid = pIn3->u.i;
+ u.bg.pC->rowidIsValid = u.bg.res==0 ?1:0;
+ u.bg.pC->nullRow = 0;
+ u.bg.pC->cacheStatus = CACHE_STALE;
+ u.bg.pC->deferredMoveto = 0;
+ if( u.bg.res!=0 ){
pc = pOp->p2 - 1;
- assert( u.bf.pC->rowidIsValid==0 );
+ assert( u.bg.pC->rowidIsValid==0 );
}
- u.bf.pC->seekResult = u.bf.res;
+ u.bg.pC->seekResult = u.bg.res;
}else{
/* This happens when an attempt to open a read cursor on the
** sqlite_master table returns SQLITE_EMPTY.
*/
pc = pOp->p2 - 1;
- assert( u.bf.pC->rowidIsValid==0 );
- u.bf.pC->seekResult = 0;
+ assert( u.bg.pC->rowidIsValid==0 );
+ u.bg.pC->seekResult = 0;
}
break;
}
@@ -67335,21 +69237,21 @@ case OP_Sequence: { /* out2-prerelease */
** AUTOINCREMENT feature.
*/
case OP_NewRowid: { /* out2-prerelease */
-#if 0 /* local variables moved into u.bg */
+#if 0 /* local variables moved into u.bh */
i64 v; /* The new rowid */
VdbeCursor *pC; /* Cursor of table to get the new rowid */
int res; /* Result of an sqlite3BtreeLast() */
int cnt; /* Counter to limit the number of searches */
Mem *pMem; /* Register holding largest rowid for AUTOINCREMENT */
VdbeFrame *pFrame; /* Root frame of VDBE */
-#endif /* local variables moved into u.bg */
+#endif /* local variables moved into u.bh */
- u.bg.v = 0;
- u.bg.res = 0;
+ u.bh.v = 0;
+ u.bh.res = 0;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- u.bg.pC = p->apCsr[pOp->p1];
- assert( u.bg.pC!=0 );
- if( NEVER(u.bg.pC->pCursor==0) ){
+ u.bh.pC = p->apCsr[pOp->p1];
+ assert( u.bh.pC!=0 );
+ if( NEVER(u.bh.pC->pCursor==0) ){
/* The zero initialization above is all that is needed */
}else{
/* The next rowid or record number (different terms for the same
@@ -67365,7 +69267,7 @@ case OP_NewRowid: { /* out2-prerelease */
** succeeded. If the random rowid does exist, we select a new one
** and try again, up to 100 times.
*/
- assert( u.bg.pC->isTable );
+ assert( u.bh.pC->isTable );
#ifdef SQLITE_32BIT_ROWID
# define MAX_ROWID 0x7fffffff
@@ -67377,23 +69279,23 @@ case OP_NewRowid: { /* out2-prerelease */
# define MAX_ROWID (i64)( (((u64)0x7fffffff)<<32) | (u64)0xffffffff )
#endif
- if( !u.bg.pC->useRandomRowid ){
- u.bg.v = sqlite3BtreeGetCachedRowid(u.bg.pC->pCursor);
- if( u.bg.v==0 ){
- rc = sqlite3BtreeLast(u.bg.pC->pCursor, &u.bg.res);
+ if( !u.bh.pC->useRandomRowid ){
+ u.bh.v = sqlite3BtreeGetCachedRowid(u.bh.pC->pCursor);
+ if( u.bh.v==0 ){
+ rc = sqlite3BtreeLast(u.bh.pC->pCursor, &u.bh.res);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
- if( u.bg.res ){
- u.bg.v = 1; /* IMP: R-61914-48074 */
+ if( u.bh.res ){
+ u.bh.v = 1; /* IMP: R-61914-48074 */
}else{
- assert( sqlite3BtreeCursorIsValid(u.bg.pC->pCursor) );
- rc = sqlite3BtreeKeySize(u.bg.pC->pCursor, &u.bg.v);
+ assert( sqlite3BtreeCursorIsValid(u.bh.pC->pCursor) );
+ rc = sqlite3BtreeKeySize(u.bh.pC->pCursor, &u.bh.v);
assert( rc==SQLITE_OK ); /* Cannot fail following BtreeLast() */
- if( u.bg.v>=MAX_ROWID ){
- u.bg.pC->useRandomRowid = 1;
+ if( u.bh.v>=MAX_ROWID ){
+ u.bh.pC->useRandomRowid = 1;
}else{
- u.bg.v++; /* IMP: R-29538-34987 */
+ u.bh.v++; /* IMP: R-29538-34987 */
}
}
}
@@ -67403,35 +69305,35 @@ case OP_NewRowid: { /* out2-prerelease */
/* Assert that P3 is a valid memory cell. */
assert( pOp->p3>0 );
if( p->pFrame ){
- for(u.bg.pFrame=p->pFrame; u.bg.pFrame->pParent; u.bg.pFrame=u.bg.pFrame->pParent);
+ for(u.bh.pFrame=p->pFrame; u.bh.pFrame->pParent; u.bh.pFrame=u.bh.pFrame->pParent);
/* Assert that P3 is a valid memory cell. */
- assert( pOp->p3<=u.bg.pFrame->nMem );
- u.bg.pMem = &u.bg.pFrame->aMem[pOp->p3];
+ assert( pOp->p3<=u.bh.pFrame->nMem );
+ u.bh.pMem = &u.bh.pFrame->aMem[pOp->p3];
}else{
/* Assert that P3 is a valid memory cell. */
assert( pOp->p3<=p->nMem );
- u.bg.pMem = &aMem[pOp->p3];
- memAboutToChange(p, u.bg.pMem);
+ u.bh.pMem = &aMem[pOp->p3];
+ memAboutToChange(p, u.bh.pMem);
}
- assert( memIsValid(u.bg.pMem) );
+ assert( memIsValid(u.bh.pMem) );
- REGISTER_TRACE(pOp->p3, u.bg.pMem);
- sqlite3VdbeMemIntegerify(u.bg.pMem);
- assert( (u.bg.pMem->flags & MEM_Int)!=0 ); /* mem(P3) holds an integer */
- if( u.bg.pMem->u.i==MAX_ROWID || u.bg.pC->useRandomRowid ){
+ REGISTER_TRACE(pOp->p3, u.bh.pMem);
+ sqlite3VdbeMemIntegerify(u.bh.pMem);
+ assert( (u.bh.pMem->flags & MEM_Int)!=0 ); /* mem(P3) holds an integer */
+ if( u.bh.pMem->u.i==MAX_ROWID || u.bh.pC->useRandomRowid ){
rc = SQLITE_FULL; /* IMP: R-12275-61338 */
goto abort_due_to_error;
}
- if( u.bg.v<u.bg.pMem->u.i+1 ){
- u.bg.v = u.bg.pMem->u.i + 1;
+ if( u.bh.v<u.bh.pMem->u.i+1 ){
+ u.bh.v = u.bh.pMem->u.i + 1;
}
- u.bg.pMem->u.i = u.bg.v;
+ u.bh.pMem->u.i = u.bh.v;
}
#endif
- sqlite3BtreeSetCachedRowid(u.bg.pC->pCursor, u.bg.v<MAX_ROWID ? u.bg.v+1 : 0);
+ sqlite3BtreeSetCachedRowid(u.bh.pC->pCursor, u.bh.v<MAX_ROWID ? u.bh.v+1 : 0);
}
- if( u.bg.pC->useRandomRowid ){
+ if( u.bh.pC->useRandomRowid ){
/* IMPLEMENTATION-OF: R-07677-41881 If the largest ROWID is equal to the
** largest possible integer (9223372036854775807) then the database
** engine starts picking positive candidate ROWIDs at random until
@@ -67439,35 +69341,35 @@ case OP_NewRowid: { /* out2-prerelease */
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 */
- u.bg.v = lastRowid;
- u.bg.v &= (MAX_ROWID>>1); /* ensure doesn't go negative */
- u.bg.v++; /* ensure non-zero */
- u.bg.cnt = 0;
- while( ((rc = sqlite3BtreeMovetoUnpacked(u.bg.pC->pCursor, 0, (u64)u.bg.v,
- 0, &u.bg.res))==SQLITE_OK)
- && (u.bg.res==0)
- && (++u.bg.cnt<100)){
+ u.bh.v = lastRowid;
+ u.bh.v &= (MAX_ROWID>>1); /* ensure doesn't go negative */
+ u.bh.v++; /* ensure non-zero */
+ u.bh.cnt = 0;
+ while( ((rc = sqlite3BtreeMovetoUnpacked(u.bh.pC->pCursor, 0, (u64)u.bh.v,
+ 0, &u.bh.res))==SQLITE_OK)
+ && (u.bh.res==0)
+ && (++u.bh.cnt<100)){
/* collision - try another random rowid */
- sqlite3_randomness(sizeof(u.bg.v), &u.bg.v);
- if( u.bg.cnt<5 ){
+ sqlite3_randomness(sizeof(u.bh.v), &u.bh.v);
+ if( u.bh.cnt<5 ){
/* try "small" random rowids for the initial attempts */
- u.bg.v &= 0xffffff;
+ u.bh.v &= 0xffffff;
}else{
- u.bg.v &= (MAX_ROWID>>1); /* ensure doesn't go negative */
+ u.bh.v &= (MAX_ROWID>>1); /* ensure doesn't go negative */
}
- u.bg.v++; /* ensure non-zero */
+ u.bh.v++; /* ensure non-zero */
}
- if( rc==SQLITE_OK && u.bg.res==0 ){
+ if( rc==SQLITE_OK && u.bh.res==0 ){
rc = SQLITE_FULL; /* IMP: R-38219-53002 */
goto abort_due_to_error;
}
- assert( u.bg.v>0 ); /* EV: R-40812-03570 */
+ assert( u.bh.v>0 ); /* EV: R-40812-03570 */
}
- u.bg.pC->rowidIsValid = 0;
- u.bg.pC->deferredMoveto = 0;
- u.bg.pC->cacheStatus = CACHE_STALE;
+ u.bh.pC->rowidIsValid = 0;
+ u.bh.pC->deferredMoveto = 0;
+ u.bh.pC->cacheStatus = CACHE_STALE;
}
- pOut->u.i = u.bg.v;
+ pOut->u.i = u.bh.v;
break;
}
@@ -67517,7 +69419,7 @@ case OP_NewRowid: { /* out2-prerelease */
*/
case OP_Insert:
case OP_InsertInt: {
-#if 0 /* local variables moved into u.bh */
+#if 0 /* local variables moved into u.bi */
Mem *pData; /* MEM cell holding data for the record to be inserted */
Mem *pKey; /* MEM cell holding key for the record */
i64 iKey; /* The integer ROWID or key for the record to be inserted */
@@ -67527,60 +69429,60 @@ case OP_InsertInt: {
const char *zDb; /* database name - used by the update hook */
const char *zTbl; /* Table name - used by the opdate hook */
int op; /* Opcode for update hook: SQLITE_UPDATE or SQLITE_INSERT */
-#endif /* local variables moved into u.bh */
+#endif /* local variables moved into u.bi */
- u.bh.pData = &aMem[pOp->p2];
+ u.bi.pData = &aMem[pOp->p2];
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- assert( memIsValid(u.bh.pData) );
- u.bh.pC = p->apCsr[pOp->p1];
- assert( u.bh.pC!=0 );
- assert( u.bh.pC->pCursor!=0 );
- assert( u.bh.pC->pseudoTableReg==0 );
- assert( u.bh.pC->isTable );
- REGISTER_TRACE(pOp->p2, u.bh.pData);
+ assert( memIsValid(u.bi.pData) );
+ u.bi.pC = p->apCsr[pOp->p1];
+ assert( u.bi.pC!=0 );
+ assert( u.bi.pC->pCursor!=0 );
+ assert( u.bi.pC->pseudoTableReg==0 );
+ assert( u.bi.pC->isTable );
+ REGISTER_TRACE(pOp->p2, u.bi.pData);
if( pOp->opcode==OP_Insert ){
- u.bh.pKey = &aMem[pOp->p3];
- assert( u.bh.pKey->flags & MEM_Int );
- assert( memIsValid(u.bh.pKey) );
- REGISTER_TRACE(pOp->p3, u.bh.pKey);
- u.bh.iKey = u.bh.pKey->u.i;
+ u.bi.pKey = &aMem[pOp->p3];
+ assert( u.bi.pKey->flags & MEM_Int );
+ assert( memIsValid(u.bi.pKey) );
+ REGISTER_TRACE(pOp->p3, u.bi.pKey);
+ u.bi.iKey = u.bi.pKey->u.i;
}else{
assert( pOp->opcode==OP_InsertInt );
- u.bh.iKey = pOp->p3;
+ u.bi.iKey = pOp->p3;
}
if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
- if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = lastRowid = u.bh.iKey;
- if( u.bh.pData->flags & MEM_Null ){
- u.bh.pData->z = 0;
- u.bh.pData->n = 0;
+ if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = lastRowid = u.bi.iKey;
+ if( u.bi.pData->flags & MEM_Null ){
+ u.bi.pData->z = 0;
+ u.bi.pData->n = 0;
}else{
- assert( u.bh.pData->flags & (MEM_Blob|MEM_Str) );
+ assert( u.bi.pData->flags & (MEM_Blob|MEM_Str) );
}
- u.bh.seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? u.bh.pC->seekResult : 0);
- if( u.bh.pData->flags & MEM_Zero ){
- u.bh.nZero = u.bh.pData->u.nZero;
+ u.bi.seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? u.bi.pC->seekResult : 0);
+ if( u.bi.pData->flags & MEM_Zero ){
+ u.bi.nZero = u.bi.pData->u.nZero;
}else{
- u.bh.nZero = 0;
+ u.bi.nZero = 0;
}
- sqlite3BtreeSetCachedRowid(u.bh.pC->pCursor, 0);
- rc = sqlite3BtreeInsert(u.bh.pC->pCursor, 0, u.bh.iKey,
- u.bh.pData->z, u.bh.pData->n, u.bh.nZero,
- pOp->p5 & OPFLAG_APPEND, u.bh.seekResult
+ sqlite3BtreeSetCachedRowid(u.bi.pC->pCursor, 0);
+ rc = sqlite3BtreeInsert(u.bi.pC->pCursor, 0, u.bi.iKey,
+ u.bi.pData->z, u.bi.pData->n, u.bi.nZero,
+ pOp->p5 & OPFLAG_APPEND, u.bi.seekResult
);
- u.bh.pC->rowidIsValid = 0;
- u.bh.pC->deferredMoveto = 0;
- u.bh.pC->cacheStatus = CACHE_STALE;
+ u.bi.pC->rowidIsValid = 0;
+ u.bi.pC->deferredMoveto = 0;
+ u.bi.pC->cacheStatus = CACHE_STALE;
/* Invoke the update-hook if required. */
if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z ){
- u.bh.zDb = db->aDb[u.bh.pC->iDb].zName;
- u.bh.zTbl = pOp->p4.z;
- u.bh.op = ((pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT);
- assert( u.bh.pC->isTable );
- db->xUpdateCallback(db->pUpdateArg, u.bh.op, u.bh.zDb, u.bh.zTbl, u.bh.iKey);
- assert( u.bh.pC->iDb>=0 );
+ u.bi.zDb = db->aDb[u.bi.pC->iDb].zName;
+ u.bi.zTbl = pOp->p4.z;
+ u.bi.op = ((pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT);
+ assert( u.bi.pC->isTable );
+ db->xUpdateCallback(db->pUpdateArg, u.bi.op, u.bi.zDb, u.bi.zTbl, u.bi.iKey);
+ assert( u.bi.pC->iDb>=0 );
}
break;
}
@@ -67606,47 +69508,47 @@ case OP_InsertInt: {
** using OP_NotFound prior to invoking this opcode.
*/
case OP_Delete: {
-#if 0 /* local variables moved into u.bi */
+#if 0 /* local variables moved into u.bj */
i64 iKey;
VdbeCursor *pC;
-#endif /* local variables moved into u.bi */
+#endif /* local variables moved into u.bj */
- u.bi.iKey = 0;
+ u.bj.iKey = 0;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- u.bi.pC = p->apCsr[pOp->p1];
- assert( u.bi.pC!=0 );
- assert( u.bi.pC->pCursor!=0 ); /* Only valid for real tables, no pseudotables */
+ u.bj.pC = p->apCsr[pOp->p1];
+ assert( u.bj.pC!=0 );
+ assert( u.bj.pC->pCursor!=0 ); /* Only valid for real tables, no pseudotables */
- /* If the update-hook will be invoked, set u.bi.iKey to the rowid of the
+ /* If the update-hook will be invoked, set u.bj.iKey to the rowid of the
** row being deleted.
*/
if( db->xUpdateCallback && pOp->p4.z ){
- assert( u.bi.pC->isTable );
- assert( u.bi.pC->rowidIsValid ); /* lastRowid set by previous OP_NotFound */
- u.bi.iKey = u.bi.pC->lastRowid;
+ assert( u.bj.pC->isTable );
+ assert( u.bj.pC->rowidIsValid ); /* lastRowid set by previous OP_NotFound */
+ u.bj.iKey = u.bj.pC->lastRowid;
}
/* 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 u.bi.pC is always pointing
+ ** might move or invalidate the cursor. Hence cursor u.bj.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( u.bi.pC->deferredMoveto==0 );
- rc = sqlite3VdbeCursorMoveto(u.bi.pC);
+ assert( u.bj.pC->deferredMoveto==0 );
+ rc = sqlite3VdbeCursorMoveto(u.bj.pC);
if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error;
- sqlite3BtreeSetCachedRowid(u.bi.pC->pCursor, 0);
- rc = sqlite3BtreeDelete(u.bi.pC->pCursor);
- u.bi.pC->cacheStatus = CACHE_STALE;
+ sqlite3BtreeSetCachedRowid(u.bj.pC->pCursor, 0);
+ rc = sqlite3BtreeDelete(u.bj.pC->pCursor);
+ u.bj.pC->cacheStatus = CACHE_STALE;
/* Invoke the update-hook if required. */
if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z ){
- const char *zDb = db->aDb[u.bi.pC->iDb].zName;
+ const char *zDb = db->aDb[u.bj.pC->iDb].zName;
const char *zTbl = pOp->p4.z;
- db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, zTbl, u.bi.iKey);
- assert( u.bi.pC->iDb>=0 );
+ db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, zTbl, u.bj.iKey);
+ assert( u.bj.pC->iDb>=0 );
}
if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++;
break;
@@ -67672,16 +69574,16 @@ case OP_ResetCount: {
** fall through to the next instruction. Otherwise, jump to instruction P2.
*/
case OP_SorterCompare: {
-#if 0 /* local variables moved into u.bj */
+#if 0 /* local variables moved into u.bk */
VdbeCursor *pC;
int res;
-#endif /* local variables moved into u.bj */
+#endif /* local variables moved into u.bk */
- u.bj.pC = p->apCsr[pOp->p1];
- assert( isSorter(u.bj.pC) );
+ u.bk.pC = p->apCsr[pOp->p1];
+ assert( isSorter(u.bk.pC) );
pIn3 = &aMem[pOp->p3];
- rc = sqlite3VdbeSorterCompare(u.bj.pC, pIn3, &u.bj.res);
- if( u.bj.res ){
+ rc = sqlite3VdbeSorterCompare(u.bk.pC, pIn3, &u.bk.res);
+ if( u.bk.res ){
pc = pOp->p2-1;
}
break;
@@ -67692,18 +69594,14 @@ case OP_SorterCompare: {
** Write into register P2 the current sorter data for sorter cursor P1.
*/
case OP_SorterData: {
-#if 0 /* local variables moved into u.bk */
+#if 0 /* local variables moved into u.bl */
VdbeCursor *pC;
-#endif /* local variables moved into u.bk */
-#ifndef SQLITE_OMIT_MERGE_SORT
+#endif /* local variables moved into u.bl */
+
pOut = &aMem[pOp->p2];
- u.bk.pC = p->apCsr[pOp->p1];
- assert( u.bk.pC->isSorter );
- rc = sqlite3VdbeSorterRowkey(u.bk.pC, pOut);
-#else
- pOp->opcode = OP_RowKey;
- pc--;
-#endif
+ u.bl.pC = p->apCsr[pOp->p1];
+ assert( u.bl.pC->isSorter );
+ rc = sqlite3VdbeSorterRowkey(u.bl.pC, pOut);
break;
}
@@ -67729,62 +69627,62 @@ case OP_SorterData: {
*/
case OP_RowKey:
case OP_RowData: {
-#if 0 /* local variables moved into u.bl */
+#if 0 /* local variables moved into u.bm */
VdbeCursor *pC;
BtCursor *pCrsr;
u32 n;
i64 n64;
-#endif /* local variables moved into u.bl */
+#endif /* local variables moved into u.bm */
pOut = &aMem[pOp->p2];
memAboutToChange(p, pOut);
/* Note that RowKey and RowData are really exactly the same instruction */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- u.bl.pC = p->apCsr[pOp->p1];
- assert( u.bl.pC->isSorter==0 );
- assert( u.bl.pC->isTable || pOp->opcode!=OP_RowData );
- assert( u.bl.pC->isIndex || pOp->opcode==OP_RowData );
- assert( u.bl.pC!=0 );
- assert( u.bl.pC->nullRow==0 );
- assert( u.bl.pC->pseudoTableReg==0 );
- assert( u.bl.pC->pCursor!=0 );
- u.bl.pCrsr = u.bl.pC->pCursor;
- assert( sqlite3BtreeCursorIsValid(u.bl.pCrsr) );
+ u.bm.pC = p->apCsr[pOp->p1];
+ assert( u.bm.pC->isSorter==0 );
+ assert( u.bm.pC->isTable || pOp->opcode!=OP_RowData );
+ assert( u.bm.pC->isIndex || pOp->opcode==OP_RowData );
+ assert( u.bm.pC!=0 );
+ assert( u.bm.pC->nullRow==0 );
+ assert( u.bm.pC->pseudoTableReg==0 );
+ assert( u.bm.pC->pCursor!=0 );
+ u.bm.pCrsr = u.bm.pC->pCursor;
+ assert( sqlite3BtreeCursorIsValid(u.bm.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.
*/
- assert( u.bl.pC->deferredMoveto==0 );
- rc = sqlite3VdbeCursorMoveto(u.bl.pC);
+ assert( u.bm.pC->deferredMoveto==0 );
+ rc = sqlite3VdbeCursorMoveto(u.bm.pC);
if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error;
- if( u.bl.pC->isIndex ){
- assert( !u.bl.pC->isTable );
- VVA_ONLY(rc =) sqlite3BtreeKeySize(u.bl.pCrsr, &u.bl.n64);
+ if( u.bm.pC->isIndex ){
+ assert( !u.bm.pC->isTable );
+ VVA_ONLY(rc =) sqlite3BtreeKeySize(u.bm.pCrsr, &u.bm.n64);
assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */
- if( u.bl.n64>db->aLimit[SQLITE_LIMIT_LENGTH] ){
+ if( u.bm.n64>db->aLimit[SQLITE_LIMIT_LENGTH] ){
goto too_big;
}
- u.bl.n = (u32)u.bl.n64;
+ u.bm.n = (u32)u.bm.n64;
}else{
- VVA_ONLY(rc =) sqlite3BtreeDataSize(u.bl.pCrsr, &u.bl.n);
+ VVA_ONLY(rc =) sqlite3BtreeDataSize(u.bm.pCrsr, &u.bm.n);
assert( rc==SQLITE_OK ); /* DataSize() cannot fail */
- if( u.bl.n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
+ if( u.bm.n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
goto too_big;
}
}
- if( sqlite3VdbeMemGrow(pOut, u.bl.n, 0) ){
+ if( sqlite3VdbeMemGrow(pOut, u.bm.n, 0) ){
goto no_mem;
}
- pOut->n = u.bl.n;
+ pOut->n = u.bm.n;
MemSetTypeFlag(pOut, MEM_Blob);
- if( u.bl.pC->isIndex ){
- rc = sqlite3BtreeKey(u.bl.pCrsr, 0, u.bl.n, pOut->z);
+ if( u.bm.pC->isIndex ){
+ rc = sqlite3BtreeKey(u.bm.pCrsr, 0, u.bm.n, pOut->z);
}else{
- rc = sqlite3BtreeData(u.bl.pCrsr, 0, u.bl.n, pOut->z);
+ rc = sqlite3BtreeData(u.bm.pCrsr, 0, u.bm.n, pOut->z);
}
pOut->enc = SQLITE_UTF8; /* In case the blob is ever cast to text */
UPDATE_MAX_BLOBSIZE(pOut);
@@ -67801,42 +69699,42 @@ case OP_RowData: {
** one opcode now works for both table types.
*/
case OP_Rowid: { /* out2-prerelease */
-#if 0 /* local variables moved into u.bm */
+#if 0 /* local variables moved into u.bn */
VdbeCursor *pC;
i64 v;
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
-#endif /* local variables moved into u.bm */
+#endif /* local variables moved into u.bn */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- u.bm.pC = p->apCsr[pOp->p1];
- assert( u.bm.pC!=0 );
- assert( u.bm.pC->pseudoTableReg==0 );
- if( u.bm.pC->nullRow ){
+ u.bn.pC = p->apCsr[pOp->p1];
+ assert( u.bn.pC!=0 );
+ assert( u.bn.pC->pseudoTableReg==0 || u.bn.pC->nullRow );
+ if( u.bn.pC->nullRow ){
pOut->flags = MEM_Null;
break;
- }else if( u.bm.pC->deferredMoveto ){
- u.bm.v = u.bm.pC->movetoTarget;
+ }else if( u.bn.pC->deferredMoveto ){
+ u.bn.v = u.bn.pC->movetoTarget;
#ifndef SQLITE_OMIT_VIRTUALTABLE
- }else if( u.bm.pC->pVtabCursor ){
- u.bm.pVtab = u.bm.pC->pVtabCursor->pVtab;
- u.bm.pModule = u.bm.pVtab->pModule;
- assert( u.bm.pModule->xRowid );
- rc = u.bm.pModule->xRowid(u.bm.pC->pVtabCursor, &u.bm.v);
- importVtabErrMsg(p, u.bm.pVtab);
+ }else if( u.bn.pC->pVtabCursor ){
+ u.bn.pVtab = u.bn.pC->pVtabCursor->pVtab;
+ u.bn.pModule = u.bn.pVtab->pModule;
+ assert( u.bn.pModule->xRowid );
+ rc = u.bn.pModule->xRowid(u.bn.pC->pVtabCursor, &u.bn.v);
+ importVtabErrMsg(p, u.bn.pVtab);
#endif /* SQLITE_OMIT_VIRTUALTABLE */
}else{
- assert( u.bm.pC->pCursor!=0 );
- rc = sqlite3VdbeCursorMoveto(u.bm.pC);
+ assert( u.bn.pC->pCursor!=0 );
+ rc = sqlite3VdbeCursorMoveto(u.bn.pC);
if( rc ) goto abort_due_to_error;
- if( u.bm.pC->rowidIsValid ){
- u.bm.v = u.bm.pC->lastRowid;
+ if( u.bn.pC->rowidIsValid ){
+ u.bn.v = u.bn.pC->lastRowid;
}else{
- rc = sqlite3BtreeKeySize(u.bm.pC->pCursor, &u.bm.v);
+ rc = sqlite3BtreeKeySize(u.bn.pC->pCursor, &u.bn.v);
assert( rc==SQLITE_OK ); /* Always so because of CursorMoveto() above */
}
}
- pOut->u.i = u.bm.v;
+ pOut->u.i = u.bn.v;
break;
}
@@ -67847,18 +69745,18 @@ case OP_Rowid: { /* out2-prerelease */
** write a NULL.
*/
case OP_NullRow: {
-#if 0 /* local variables moved into u.bn */
+#if 0 /* local variables moved into u.bo */
VdbeCursor *pC;
-#endif /* local variables moved into u.bn */
+#endif /* local variables moved into u.bo */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- u.bn.pC = p->apCsr[pOp->p1];
- assert( u.bn.pC!=0 );
- u.bn.pC->nullRow = 1;
- u.bn.pC->rowidIsValid = 0;
- assert( u.bn.pC->pCursor || u.bn.pC->pVtabCursor );
- if( u.bn.pC->pCursor ){
- sqlite3BtreeClearCursor(u.bn.pC->pCursor);
+ u.bo.pC = p->apCsr[pOp->p1];
+ assert( u.bo.pC!=0 );
+ u.bo.pC->nullRow = 1;
+ u.bo.pC->rowidIsValid = 0;
+ assert( u.bo.pC->pCursor || u.bo.pC->pVtabCursor );
+ if( u.bo.pC->pCursor ){
+ sqlite3BtreeClearCursor(u.bo.pC->pCursor);
}
break;
}
@@ -67872,25 +69770,25 @@ case OP_NullRow: {
** to the following instruction.
*/
case OP_Last: { /* jump */
-#if 0 /* local variables moved into u.bo */
+#if 0 /* local variables moved into u.bp */
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
-#endif /* local variables moved into u.bo */
+#endif /* local variables moved into u.bp */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- u.bo.pC = p->apCsr[pOp->p1];
- assert( u.bo.pC!=0 );
- u.bo.pCrsr = u.bo.pC->pCursor;
- u.bo.res = 0;
- if( ALWAYS(u.bo.pCrsr!=0) ){
- rc = sqlite3BtreeLast(u.bo.pCrsr, &u.bo.res);
+ u.bp.pC = p->apCsr[pOp->p1];
+ assert( u.bp.pC!=0 );
+ u.bp.pCrsr = u.bp.pC->pCursor;
+ u.bp.res = 0;
+ if( ALWAYS(u.bp.pCrsr!=0) ){
+ rc = sqlite3BtreeLast(u.bp.pCrsr, &u.bp.res);
}
- u.bo.pC->nullRow = (u8)u.bo.res;
- u.bo.pC->deferredMoveto = 0;
- u.bo.pC->rowidIsValid = 0;
- u.bo.pC->cacheStatus = CACHE_STALE;
- if( pOp->p2>0 && u.bo.res ){
+ u.bp.pC->nullRow = (u8)u.bp.res;
+ u.bp.pC->deferredMoveto = 0;
+ u.bp.pC->rowidIsValid = 0;
+ u.bp.pC->cacheStatus = CACHE_STALE;
+ if( pOp->p2>0 && u.bp.res ){
pc = pOp->p2 - 1;
}
break;
@@ -67910,9 +69808,6 @@ case OP_Last: { /* jump */
** correctly optimizing out sorts.
*/
case OP_SorterSort: /* jump */
-#ifdef SQLITE_OMIT_MERGE_SORT
- pOp->opcode = OP_Sort;
-#endif
case OP_Sort: { /* jump */
#ifdef SQLITE_TEST
sqlite3_sort_count++;
@@ -67930,31 +69825,31 @@ case OP_Sort: { /* jump */
** to the following instruction.
*/
case OP_Rewind: { /* jump */
-#if 0 /* local variables moved into u.bp */
+#if 0 /* local variables moved into u.bq */
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
-#endif /* local variables moved into u.bp */
+#endif /* local variables moved into u.bq */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- u.bp.pC = p->apCsr[pOp->p1];
- assert( u.bp.pC!=0 );
- assert( u.bp.pC->isSorter==(pOp->opcode==OP_SorterSort) );
- u.bp.res = 1;
- if( isSorter(u.bp.pC) ){
- rc = sqlite3VdbeSorterRewind(db, u.bp.pC, &u.bp.res);
- }else{
- u.bp.pCrsr = u.bp.pC->pCursor;
- assert( u.bp.pCrsr );
- rc = sqlite3BtreeFirst(u.bp.pCrsr, &u.bp.res);
- u.bp.pC->atFirst = u.bp.res==0 ?1:0;
- u.bp.pC->deferredMoveto = 0;
- u.bp.pC->cacheStatus = CACHE_STALE;
- u.bp.pC->rowidIsValid = 0;
+ u.bq.pC = p->apCsr[pOp->p1];
+ assert( u.bq.pC!=0 );
+ assert( u.bq.pC->isSorter==(pOp->opcode==OP_SorterSort) );
+ u.bq.res = 1;
+ if( isSorter(u.bq.pC) ){
+ rc = sqlite3VdbeSorterRewind(db, u.bq.pC, &u.bq.res);
+ }else{
+ u.bq.pCrsr = u.bq.pC->pCursor;
+ assert( u.bq.pCrsr );
+ rc = sqlite3BtreeFirst(u.bq.pCrsr, &u.bq.res);
+ u.bq.pC->atFirst = u.bq.res==0 ?1:0;
+ u.bq.pC->deferredMoveto = 0;
+ u.bq.pC->cacheStatus = CACHE_STALE;
+ u.bq.pC->rowidIsValid = 0;
}
- u.bp.pC->nullRow = (u8)u.bp.res;
+ u.bq.pC->nullRow = (u8)u.bq.res;
assert( pOp->p2>0 && pOp->p2<p->nOp );
- if( u.bp.res ){
+ if( u.bq.res ){
pc = pOp->p2 - 1;
}
break;
@@ -67993,45 +69888,42 @@ case OP_Rewind: { /* jump */
** number P5-1 in the prepared statement is incremented.
*/
case OP_SorterNext: /* jump */
-#ifdef SQLITE_OMIT_MERGE_SORT
- pOp->opcode = OP_Next;
-#endif
case OP_Prev: /* jump */
case OP_Next: { /* jump */
-#if 0 /* local variables moved into u.bq */
+#if 0 /* local variables moved into u.br */
VdbeCursor *pC;
int res;
-#endif /* local variables moved into u.bq */
+#endif /* local variables moved into u.br */
CHECK_FOR_INTERRUPT;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( pOp->p5<=ArraySize(p->aCounter) );
- u.bq.pC = p->apCsr[pOp->p1];
- if( u.bq.pC==0 ){
+ u.br.pC = p->apCsr[pOp->p1];
+ if( u.br.pC==0 ){
break; /* See ticket #2273 */
}
- assert( u.bq.pC->isSorter==(pOp->opcode==OP_SorterNext) );
- if( isSorter(u.bq.pC) ){
+ assert( u.br.pC->isSorter==(pOp->opcode==OP_SorterNext) );
+ if( isSorter(u.br.pC) ){
assert( pOp->opcode==OP_SorterNext );
- rc = sqlite3VdbeSorterNext(db, u.bq.pC, &u.bq.res);
+ rc = sqlite3VdbeSorterNext(db, u.br.pC, &u.br.res);
}else{
- u.bq.res = 1;
- assert( u.bq.pC->deferredMoveto==0 );
- assert( u.bq.pC->pCursor );
+ u.br.res = 1;
+ assert( u.br.pC->deferredMoveto==0 );
+ assert( u.br.pC->pCursor );
assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext );
assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious );
- rc = pOp->p4.xAdvance(u.bq.pC->pCursor, &u.bq.res);
+ rc = pOp->p4.xAdvance(u.br.pC->pCursor, &u.br.res);
}
- u.bq.pC->nullRow = (u8)u.bq.res;
- u.bq.pC->cacheStatus = CACHE_STALE;
- if( u.bq.res==0 ){
+ u.br.pC->nullRow = (u8)u.br.res;
+ u.br.pC->cacheStatus = CACHE_STALE;
+ if( u.br.res==0 ){
pc = pOp->p2 - 1;
if( pOp->p5 ) p->aCounter[pOp->p5-1]++;
#ifdef SQLITE_TEST
sqlite3_search_count++;
#endif
}
- u.bq.pC->rowidIsValid = 0;
+ u.br.pC->rowidIsValid = 0;
break;
}
@@ -68048,38 +69940,35 @@ case OP_Next: { /* jump */
** for tables is OP_Insert.
*/
case OP_SorterInsert: /* in2 */
-#ifdef SQLITE_OMIT_MERGE_SORT
- pOp->opcode = OP_IdxInsert;
-#endif
case OP_IdxInsert: { /* in2 */
-#if 0 /* local variables moved into u.br */
+#if 0 /* local variables moved into u.bs */
VdbeCursor *pC;
BtCursor *pCrsr;
int nKey;
const char *zKey;
-#endif /* local variables moved into u.br */
+#endif /* local variables moved into u.bs */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- u.br.pC = p->apCsr[pOp->p1];
- assert( u.br.pC!=0 );
- assert( u.br.pC->isSorter==(pOp->opcode==OP_SorterInsert) );
+ u.bs.pC = p->apCsr[pOp->p1];
+ assert( u.bs.pC!=0 );
+ assert( u.bs.pC->isSorter==(pOp->opcode==OP_SorterInsert) );
pIn2 = &aMem[pOp->p2];
assert( pIn2->flags & MEM_Blob );
- u.br.pCrsr = u.br.pC->pCursor;
- if( ALWAYS(u.br.pCrsr!=0) ){
- assert( u.br.pC->isTable==0 );
+ u.bs.pCrsr = u.bs.pC->pCursor;
+ if( ALWAYS(u.bs.pCrsr!=0) ){
+ assert( u.bs.pC->isTable==0 );
rc = ExpandBlob(pIn2);
if( rc==SQLITE_OK ){
- if( isSorter(u.br.pC) ){
- rc = sqlite3VdbeSorterWrite(db, u.br.pC, pIn2);
+ if( isSorter(u.bs.pC) ){
+ rc = sqlite3VdbeSorterWrite(db, u.bs.pC, pIn2);
}else{
- u.br.nKey = pIn2->n;
- u.br.zKey = pIn2->z;
- rc = sqlite3BtreeInsert(u.br.pCrsr, u.br.zKey, u.br.nKey, "", 0, 0, pOp->p3,
- ((pOp->p5 & OPFLAG_USESEEKRESULT) ? u.br.pC->seekResult : 0)
+ u.bs.nKey = pIn2->n;
+ u.bs.zKey = pIn2->z;
+ rc = sqlite3BtreeInsert(u.bs.pCrsr, u.bs.zKey, u.bs.nKey, "", 0, 0, pOp->p3,
+ ((pOp->p5 & OPFLAG_USESEEKRESULT) ? u.bs.pC->seekResult : 0)
);
- assert( u.br.pC->deferredMoveto==0 );
- u.br.pC->cacheStatus = CACHE_STALE;
+ assert( u.bs.pC->deferredMoveto==0 );
+ u.bs.pC->cacheStatus = CACHE_STALE;
}
}
}
@@ -68093,33 +69982,33 @@ case OP_IdxInsert: { /* in2 */
** index opened by cursor P1.
*/
case OP_IdxDelete: {
-#if 0 /* local variables moved into u.bs */
+#if 0 /* local variables moved into u.bt */
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
UnpackedRecord r;
-#endif /* local variables moved into u.bs */
+#endif /* local variables moved into u.bt */
assert( pOp->p3>0 );
assert( pOp->p2>0 && pOp->p2+pOp->p3<=p->nMem+1 );
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- u.bs.pC = p->apCsr[pOp->p1];
- assert( u.bs.pC!=0 );
- u.bs.pCrsr = u.bs.pC->pCursor;
- if( ALWAYS(u.bs.pCrsr!=0) ){
- u.bs.r.pKeyInfo = u.bs.pC->pKeyInfo;
- u.bs.r.nField = (u16)pOp->p3;
- u.bs.r.flags = 0;
- u.bs.r.aMem = &aMem[pOp->p2];
+ u.bt.pC = p->apCsr[pOp->p1];
+ assert( u.bt.pC!=0 );
+ u.bt.pCrsr = u.bt.pC->pCursor;
+ if( ALWAYS(u.bt.pCrsr!=0) ){
+ u.bt.r.pKeyInfo = u.bt.pC->pKeyInfo;
+ u.bt.r.nField = (u16)pOp->p3;
+ u.bt.r.flags = 0;
+ u.bt.r.aMem = &aMem[pOp->p2];
#ifdef SQLITE_DEBUG
- { int i; for(i=0; i<u.bs.r.nField; i++) assert( memIsValid(&u.bs.r.aMem[i]) ); }
+ { int i; for(i=0; i<u.bt.r.nField; i++) assert( memIsValid(&u.bt.r.aMem[i]) ); }
#endif
- rc = sqlite3BtreeMovetoUnpacked(u.bs.pCrsr, &u.bs.r, 0, 0, &u.bs.res);
- if( rc==SQLITE_OK && u.bs.res==0 ){
- rc = sqlite3BtreeDelete(u.bs.pCrsr);
+ rc = sqlite3BtreeMovetoUnpacked(u.bt.pCrsr, &u.bt.r, 0, 0, &u.bt.res);
+ if( rc==SQLITE_OK && u.bt.res==0 ){
+ rc = sqlite3BtreeDelete(u.bt.pCrsr);
}
- assert( u.bs.pC->deferredMoveto==0 );
- u.bs.pC->cacheStatus = CACHE_STALE;
+ assert( u.bt.pC->deferredMoveto==0 );
+ u.bt.pC->cacheStatus = CACHE_STALE;
}
break;
}
@@ -68133,28 +70022,28 @@ case OP_IdxDelete: {
** See also: Rowid, MakeRecord.
*/
case OP_IdxRowid: { /* out2-prerelease */
-#if 0 /* local variables moved into u.bt */
+#if 0 /* local variables moved into u.bu */
BtCursor *pCrsr;
VdbeCursor *pC;
i64 rowid;
-#endif /* local variables moved into u.bt */
+#endif /* local variables moved into u.bu */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- u.bt.pC = p->apCsr[pOp->p1];
- assert( u.bt.pC!=0 );
- u.bt.pCrsr = u.bt.pC->pCursor;
+ u.bu.pC = p->apCsr[pOp->p1];
+ assert( u.bu.pC!=0 );
+ u.bu.pCrsr = u.bu.pC->pCursor;
pOut->flags = MEM_Null;
- if( ALWAYS(u.bt.pCrsr!=0) ){
- rc = sqlite3VdbeCursorMoveto(u.bt.pC);
+ if( ALWAYS(u.bu.pCrsr!=0) ){
+ rc = sqlite3VdbeCursorMoveto(u.bu.pC);
if( NEVER(rc) ) goto abort_due_to_error;
- assert( u.bt.pC->deferredMoveto==0 );
- assert( u.bt.pC->isTable==0 );
- if( !u.bt.pC->nullRow ){
- rc = sqlite3VdbeIdxRowid(db, u.bt.pCrsr, &u.bt.rowid);
+ assert( u.bu.pC->deferredMoveto==0 );
+ assert( u.bu.pC->isTable==0 );
+ if( !u.bu.pC->nullRow ){
+ rc = sqlite3VdbeIdxRowid(db, u.bu.pCrsr, &u.bu.rowid);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
- pOut->u.i = u.bt.rowid;
+ pOut->u.i = u.bu.rowid;
pOut->flags = MEM_Int;
}
}
@@ -68189,39 +70078,39 @@ case OP_IdxRowid: { /* out2-prerelease */
*/
case OP_IdxLT: /* jump */
case OP_IdxGE: { /* jump */
-#if 0 /* local variables moved into u.bu */
+#if 0 /* local variables moved into u.bv */
VdbeCursor *pC;
int res;
UnpackedRecord r;
-#endif /* local variables moved into u.bu */
+#endif /* local variables moved into u.bv */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- u.bu.pC = p->apCsr[pOp->p1];
- assert( u.bu.pC!=0 );
- assert( u.bu.pC->isOrdered );
- if( ALWAYS(u.bu.pC->pCursor!=0) ){
- assert( u.bu.pC->deferredMoveto==0 );
+ u.bv.pC = p->apCsr[pOp->p1];
+ assert( u.bv.pC!=0 );
+ assert( u.bv.pC->isOrdered );
+ if( ALWAYS(u.bv.pC->pCursor!=0) ){
+ assert( u.bv.pC->deferredMoveto==0 );
assert( pOp->p5==0 || pOp->p5==1 );
assert( pOp->p4type==P4_INT32 );
- u.bu.r.pKeyInfo = u.bu.pC->pKeyInfo;
- u.bu.r.nField = (u16)pOp->p4.i;
+ u.bv.r.pKeyInfo = u.bv.pC->pKeyInfo;
+ u.bv.r.nField = (u16)pOp->p4.i;
if( pOp->p5 ){
- u.bu.r.flags = UNPACKED_INCRKEY | UNPACKED_PREFIX_MATCH;
+ u.bv.r.flags = UNPACKED_INCRKEY | UNPACKED_PREFIX_MATCH;
}else{
- u.bu.r.flags = UNPACKED_PREFIX_MATCH;
+ u.bv.r.flags = UNPACKED_PREFIX_MATCH;
}
- u.bu.r.aMem = &aMem[pOp->p3];
+ u.bv.r.aMem = &aMem[pOp->p3];
#ifdef SQLITE_DEBUG
- { int i; for(i=0; i<u.bu.r.nField; i++) assert( memIsValid(&u.bu.r.aMem[i]) ); }
+ { int i; for(i=0; i<u.bv.r.nField; i++) assert( memIsValid(&u.bv.r.aMem[i]) ); }
#endif
- rc = sqlite3VdbeIdxKeyCompare(u.bu.pC, &u.bu.r, &u.bu.res);
+ rc = sqlite3VdbeIdxKeyCompare(u.bv.pC, &u.bv.r, &u.bv.res);
if( pOp->opcode==OP_IdxLT ){
- u.bu.res = -u.bu.res;
+ u.bv.res = -u.bv.res;
}else{
assert( pOp->opcode==OP_IdxGE );
- u.bu.res++;
+ u.bv.res++;
}
- if( u.bu.res>0 ){
+ if( u.bv.res>0 ){
pc = pOp->p2 - 1 ;
}
}
@@ -68249,39 +70138,40 @@ case OP_IdxGE: { /* jump */
** See also: Clear
*/
case OP_Destroy: { /* out2-prerelease */
-#if 0 /* local variables moved into u.bv */
+#if 0 /* local variables moved into u.bw */
int iMoved;
int iCnt;
Vdbe *pVdbe;
int iDb;
-#endif /* local variables moved into u.bv */
+#endif /* local variables moved into u.bw */
+
#ifndef SQLITE_OMIT_VIRTUALTABLE
- u.bv.iCnt = 0;
- for(u.bv.pVdbe=db->pVdbe; u.bv.pVdbe; u.bv.pVdbe = u.bv.pVdbe->pNext){
- if( u.bv.pVdbe->magic==VDBE_MAGIC_RUN && u.bv.pVdbe->inVtabMethod<2 && u.bv.pVdbe->pc>=0 ){
- u.bv.iCnt++;
+ u.bw.iCnt = 0;
+ for(u.bw.pVdbe=db->pVdbe; u.bw.pVdbe; u.bw.pVdbe = u.bw.pVdbe->pNext){
+ if( u.bw.pVdbe->magic==VDBE_MAGIC_RUN && u.bw.pVdbe->inVtabMethod<2 && u.bw.pVdbe->pc>=0 ){
+ u.bw.iCnt++;
}
}
#else
- u.bv.iCnt = db->activeVdbeCnt;
+ u.bw.iCnt = db->activeVdbeCnt;
#endif
pOut->flags = MEM_Null;
- if( u.bv.iCnt>1 ){
+ if( u.bw.iCnt>1 ){
rc = SQLITE_LOCKED;
p->errorAction = OE_Abort;
}else{
- u.bv.iDb = pOp->p3;
- assert( u.bv.iCnt==1 );
- assert( (p->btreeMask & (((yDbMask)1)<<u.bv.iDb))!=0 );
- rc = sqlite3BtreeDropTable(db->aDb[u.bv.iDb].pBt, pOp->p1, &u.bv.iMoved);
+ u.bw.iDb = pOp->p3;
+ assert( u.bw.iCnt==1 );
+ assert( (p->btreeMask & (((yDbMask)1)<<u.bw.iDb))!=0 );
+ rc = sqlite3BtreeDropTable(db->aDb[u.bw.iDb].pBt, pOp->p1, &u.bw.iMoved);
pOut->flags = MEM_Int;
- pOut->u.i = u.bv.iMoved;
+ pOut->u.i = u.bw.iMoved;
#ifndef SQLITE_OMIT_AUTOVACUUM
- if( rc==SQLITE_OK && u.bv.iMoved!=0 ){
- sqlite3RootPageMoved(db, u.bv.iDb, u.bv.iMoved, pOp->p1);
+ if( rc==SQLITE_OK && u.bw.iMoved!=0 ){
+ sqlite3RootPageMoved(db, u.bw.iDb, u.bw.iMoved, pOp->p1);
/* All OP_Destroy operations occur on the same btree */
- assert( resetSchemaOnFault==0 || resetSchemaOnFault==u.bv.iDb+1 );
- resetSchemaOnFault = u.bv.iDb+1;
+ assert( resetSchemaOnFault==0 || resetSchemaOnFault==u.bw.iDb+1 );
+ resetSchemaOnFault = u.bw.iDb+1;
}
#endif
}
@@ -68307,21 +70197,21 @@ case OP_Destroy: { /* out2-prerelease */
** See also: Destroy
*/
case OP_Clear: {
-#if 0 /* local variables moved into u.bw */
+#if 0 /* local variables moved into u.bx */
int nChange;
-#endif /* local variables moved into u.bw */
+#endif /* local variables moved into u.bx */
- u.bw.nChange = 0;
+ u.bx.nChange = 0;
assert( (p->btreeMask & (((yDbMask)1)<<pOp->p2))!=0 );
rc = sqlite3BtreeClearTable(
- db->aDb[pOp->p2].pBt, pOp->p1, (pOp->p3 ? &u.bw.nChange : 0)
+ db->aDb[pOp->p2].pBt, pOp->p1, (pOp->p3 ? &u.bx.nChange : 0)
);
if( pOp->p3 ){
- p->nChange += u.bw.nChange;
+ p->nChange += u.bx.nChange;
if( pOp->p3>0 ){
assert( memIsValid(&aMem[pOp->p3]) );
memAboutToChange(p, &aMem[pOp->p3]);
- aMem[pOp->p3].u.i += u.bw.nChange;
+ aMem[pOp->p3].u.i += u.bx.nChange;
}
}
break;
@@ -68351,25 +70241,25 @@ case OP_Clear: {
*/
case OP_CreateIndex: /* out2-prerelease */
case OP_CreateTable: { /* out2-prerelease */
-#if 0 /* local variables moved into u.bx */
+#if 0 /* local variables moved into u.by */
int pgno;
int flags;
Db *pDb;
-#endif /* local variables moved into u.bx */
+#endif /* local variables moved into u.by */
- u.bx.pgno = 0;
+ u.by.pgno = 0;
assert( pOp->p1>=0 && pOp->p1<db->nDb );
assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
- u.bx.pDb = &db->aDb[pOp->p1];
- assert( u.bx.pDb->pBt!=0 );
+ u.by.pDb = &db->aDb[pOp->p1];
+ assert( u.by.pDb->pBt!=0 );
if( pOp->opcode==OP_CreateTable ){
- /* u.bx.flags = BTREE_INTKEY; */
- u.bx.flags = BTREE_INTKEY;
+ /* u.by.flags = BTREE_INTKEY; */
+ u.by.flags = BTREE_INTKEY;
}else{
- u.bx.flags = BTREE_BLOBKEY;
+ u.by.flags = BTREE_BLOBKEY;
}
- rc = sqlite3BtreeCreateTable(u.bx.pDb->pBt, &u.bx.pgno, u.bx.flags);
- pOut->u.i = u.bx.pgno;
+ rc = sqlite3BtreeCreateTable(u.by.pDb->pBt, &u.by.pgno, u.by.flags);
+ pOut->u.i = u.by.pgno;
break;
}
@@ -68382,44 +70272,44 @@ case OP_CreateTable: { /* out2-prerelease */
** then runs the new virtual machine. It is thus a re-entrant opcode.
*/
case OP_ParseSchema: {
-#if 0 /* local variables moved into u.by */
+#if 0 /* local variables moved into u.bz */
int iDb;
const char *zMaster;
char *zSql;
InitData initData;
-#endif /* local variables moved into u.by */
+#endif /* local variables moved into u.bz */
/* Any prepared statement that invokes this opcode will hold mutexes
** on every btree. This is a prerequisite for invoking
** sqlite3InitCallback().
*/
#ifdef SQLITE_DEBUG
- for(u.by.iDb=0; u.by.iDb<db->nDb; u.by.iDb++){
- assert( u.by.iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[u.by.iDb].pBt) );
+ for(u.bz.iDb=0; u.bz.iDb<db->nDb; u.bz.iDb++){
+ assert( u.bz.iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[u.bz.iDb].pBt) );
}
#endif
- u.by.iDb = pOp->p1;
- assert( u.by.iDb>=0 && u.by.iDb<db->nDb );
- assert( DbHasProperty(db, u.by.iDb, DB_SchemaLoaded) );
+ u.bz.iDb = pOp->p1;
+ assert( u.bz.iDb>=0 && u.bz.iDb<db->nDb );
+ assert( DbHasProperty(db, u.bz.iDb, DB_SchemaLoaded) );
/* Used to be a conditional */ {
- u.by.zMaster = SCHEMA_TABLE(u.by.iDb);
- u.by.initData.db = db;
- u.by.initData.iDb = pOp->p1;
- u.by.initData.pzErrMsg = &p->zErrMsg;
- u.by.zSql = sqlite3MPrintf(db,
+ u.bz.zMaster = SCHEMA_TABLE(u.bz.iDb);
+ u.bz.initData.db = db;
+ u.bz.initData.iDb = pOp->p1;
+ u.bz.initData.pzErrMsg = &p->zErrMsg;
+ u.bz.zSql = sqlite3MPrintf(db,
"SELECT name, rootpage, sql FROM '%q'.%s WHERE %s ORDER BY rowid",
- db->aDb[u.by.iDb].zName, u.by.zMaster, pOp->p4.z);
- if( u.by.zSql==0 ){
+ db->aDb[u.bz.iDb].zName, u.bz.zMaster, pOp->p4.z);
+ if( u.bz.zSql==0 ){
rc = SQLITE_NOMEM;
}else{
assert( db->init.busy==0 );
db->init.busy = 1;
- u.by.initData.rc = SQLITE_OK;
+ u.bz.initData.rc = SQLITE_OK;
assert( !db->mallocFailed );
- rc = sqlite3_exec(db, u.by.zSql, sqlite3InitCallback, &u.by.initData, 0);
- if( rc==SQLITE_OK ) rc = u.by.initData.rc;
- sqlite3DbFree(db, u.by.zSql);
+ rc = sqlite3_exec(db, u.bz.zSql, sqlite3InitCallback, &u.bz.initData, 0);
+ if( rc==SQLITE_OK ) rc = u.bz.initData.rc;
+ sqlite3DbFree(db, u.bz.zSql);
db->init.busy = 0;
}
}
@@ -68503,41 +70393,41 @@ case OP_DropTrigger: {
** This opcode is used to implement the integrity_check pragma.
*/
case OP_IntegrityCk: {
-#if 0 /* local variables moved into u.bz */
+#if 0 /* local variables moved into u.ca */
int nRoot; /* Number of tables to check. (Number of root pages.) */
int *aRoot; /* Array of rootpage numbers for tables to be checked */
int j; /* Loop counter */
int nErr; /* Number of errors reported */
char *z; /* Text of the error report */
Mem *pnErr; /* Register keeping track of errors remaining */
-#endif /* local variables moved into u.bz */
+#endif /* local variables moved into u.ca */
- u.bz.nRoot = pOp->p2;
- assert( u.bz.nRoot>0 );
- u.bz.aRoot = sqlite3DbMallocRaw(db, sizeof(int)*(u.bz.nRoot+1) );
- if( u.bz.aRoot==0 ) goto no_mem;
+ u.ca.nRoot = pOp->p2;
+ assert( u.ca.nRoot>0 );
+ u.ca.aRoot = sqlite3DbMallocRaw(db, sizeof(int)*(u.ca.nRoot+1) );
+ if( u.ca.aRoot==0 ) goto no_mem;
assert( pOp->p3>0 && pOp->p3<=p->nMem );
- u.bz.pnErr = &aMem[pOp->p3];
- assert( (u.bz.pnErr->flags & MEM_Int)!=0 );
- assert( (u.bz.pnErr->flags & (MEM_Str|MEM_Blob))==0 );
+ u.ca.pnErr = &aMem[pOp->p3];
+ assert( (u.ca.pnErr->flags & MEM_Int)!=0 );
+ assert( (u.ca.pnErr->flags & (MEM_Str|MEM_Blob))==0 );
pIn1 = &aMem[pOp->p1];
- for(u.bz.j=0; u.bz.j<u.bz.nRoot; u.bz.j++){
- u.bz.aRoot[u.bz.j] = (int)sqlite3VdbeIntValue(&pIn1[u.bz.j]);
+ for(u.ca.j=0; u.ca.j<u.ca.nRoot; u.ca.j++){
+ u.ca.aRoot[u.ca.j] = (int)sqlite3VdbeIntValue(&pIn1[u.ca.j]);
}
- u.bz.aRoot[u.bz.j] = 0;
+ u.ca.aRoot[u.ca.j] = 0;
assert( pOp->p5<db->nDb );
assert( (p->btreeMask & (((yDbMask)1)<<pOp->p5))!=0 );
- u.bz.z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, u.bz.aRoot, u.bz.nRoot,
- (int)u.bz.pnErr->u.i, &u.bz.nErr);
- sqlite3DbFree(db, u.bz.aRoot);
- u.bz.pnErr->u.i -= u.bz.nErr;
+ u.ca.z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, u.ca.aRoot, u.ca.nRoot,
+ (int)u.ca.pnErr->u.i, &u.ca.nErr);
+ sqlite3DbFree(db, u.ca.aRoot);
+ u.ca.pnErr->u.i -= u.ca.nErr;
sqlite3VdbeMemSetNull(pIn1);
- if( u.bz.nErr==0 ){
- assert( u.bz.z==0 );
- }else if( u.bz.z==0 ){
+ if( u.ca.nErr==0 ){
+ assert( u.ca.z==0 );
+ }else if( u.ca.z==0 ){
goto no_mem;
}else{
- sqlite3VdbeMemSetStr(pIn1, u.bz.z, -1, SQLITE_UTF8, sqlite3_free);
+ sqlite3VdbeMemSetStr(pIn1, u.ca.z, -1, SQLITE_UTF8, sqlite3_free);
}
UPDATE_MAX_BLOBSIZE(pIn1);
sqlite3VdbeChangeEncoding(pIn1, encoding);
@@ -68571,20 +70461,20 @@ case OP_RowSetAdd: { /* in1, in2 */
** unchanged and jump to instruction P2.
*/
case OP_RowSetRead: { /* jump, in1, out3 */
-#if 0 /* local variables moved into u.ca */
+#if 0 /* local variables moved into u.cb */
i64 val;
-#endif /* local variables moved into u.ca */
+#endif /* local variables moved into u.cb */
CHECK_FOR_INTERRUPT;
pIn1 = &aMem[pOp->p1];
if( (pIn1->flags & MEM_RowSet)==0
- || sqlite3RowSetNext(pIn1->u.pRowSet, &u.ca.val)==0
+ || sqlite3RowSetNext(pIn1->u.pRowSet, &u.cb.val)==0
){
/* The boolean index is empty */
sqlite3VdbeMemSetNull(pIn1);
pc = pOp->p2 - 1;
}else{
/* A value was pulled from the index */
- sqlite3VdbeMemSetInt64(&aMem[pOp->p3], u.ca.val);
+ sqlite3VdbeMemSetInt64(&aMem[pOp->p3], u.cb.val);
}
break;
}
@@ -68613,14 +70503,14 @@ case OP_RowSetRead: { /* jump, in1, out3 */
** inserted as part of some other set).
*/
case OP_RowSetTest: { /* jump, in1, in3 */
-#if 0 /* local variables moved into u.cb */
+#if 0 /* local variables moved into u.cc */
int iSet;
int exists;
-#endif /* local variables moved into u.cb */
+#endif /* local variables moved into u.cc */
pIn1 = &aMem[pOp->p1];
pIn3 = &aMem[pOp->p3];
- u.cb.iSet = pOp->p4.i;
+ u.cc.iSet = pOp->p4.i;
assert( pIn3->flags&MEM_Int );
/* If there is anything other than a rowset object in memory cell P1,
@@ -68632,17 +70522,17 @@ case OP_RowSetTest: { /* jump, in1, in3 */
}
assert( pOp->p4type==P4_INT32 );
- assert( u.cb.iSet==-1 || u.cb.iSet>=0 );
- if( u.cb.iSet ){
- u.cb.exists = sqlite3RowSetTest(pIn1->u.pRowSet,
- (u8)(u.cb.iSet>=0 ? u.cb.iSet & 0xf : 0xff),
+ assert( u.cc.iSet==-1 || u.cc.iSet>=0 );
+ if( u.cc.iSet ){
+ u.cc.exists = sqlite3RowSetTest(pIn1->u.pRowSet,
+ (u8)(u.cc.iSet>=0 ? u.cc.iSet & 0xf : 0xff),
pIn3->u.i);
- if( u.cb.exists ){
+ if( u.cc.exists ){
pc = pOp->p2 - 1;
break;
}
}
- if( u.cb.iSet>=0 ){
+ if( u.cc.iSet>=0 ){
sqlite3RowSetInsert(pIn1->u.pRowSet, pIn3->u.i);
}
break;
@@ -68665,7 +70555,7 @@ case OP_RowSetTest: { /* jump, in1, in3 */
** P4 is a pointer to the VM containing the trigger program.
*/
case OP_Program: { /* jump */
-#if 0 /* local variables moved into u.cc */
+#if 0 /* local variables moved into u.cd */
int nMem; /* Number of memory registers for sub-program */
int nByte; /* Bytes of runtime space required for sub-program */
Mem *pRt; /* Register to allocate runtime space */
@@ -68674,11 +70564,11 @@ case OP_Program: { /* jump */
VdbeFrame *pFrame; /* New vdbe frame to execute in */
SubProgram *pProgram; /* Sub-program to execute */
void *t; /* Token identifying trigger */
-#endif /* local variables moved into u.cc */
+#endif /* local variables moved into u.cd */
- u.cc.pProgram = pOp->p4.pProgram;
- u.cc.pRt = &aMem[pOp->p3];
- assert( u.cc.pProgram->nOp>0 );
+ u.cd.pProgram = pOp->p4.pProgram;
+ u.cd.pRt = &aMem[pOp->p3];
+ assert( u.cd.pProgram->nOp>0 );
/* If the p5 flag is clear, then recursive invocation of triggers is
** disabled for backwards compatibility (p5 is set if this sub-program
@@ -68692,9 +70582,9 @@ case OP_Program: { /* jump */
** single trigger all have the same value for the SubProgram.token
** variable. */
if( pOp->p5 ){
- u.cc.t = u.cc.pProgram->token;
- for(u.cc.pFrame=p->pFrame; u.cc.pFrame && u.cc.pFrame->token!=u.cc.t; u.cc.pFrame=u.cc.pFrame->pParent);
- if( u.cc.pFrame ) break;
+ u.cd.t = u.cd.pProgram->token;
+ for(u.cd.pFrame=p->pFrame; u.cd.pFrame && u.cd.pFrame->token!=u.cd.t; u.cd.pFrame=u.cd.pFrame->pParent);
+ if( u.cd.pFrame ) break;
}
if( p->nFrame>=db->aLimit[SQLITE_LIMIT_TRIGGER_DEPTH] ){
@@ -68703,69 +70593,69 @@ case OP_Program: { /* jump */
break;
}
- /* Register u.cc.pRt is used to store the memory required to save the state
+ /* Register u.cd.pRt is used to store the memory required to save the state
** of the current program, and the memory required at runtime to execute
- ** the trigger program. If this trigger has been fired before, then u.cc.pRt
+ ** the trigger program. If this trigger has been fired before, then u.cd.pRt
** is already allocated. Otherwise, it must be initialized. */
- if( (u.cc.pRt->flags&MEM_Frame)==0 ){
+ if( (u.cd.pRt->flags&MEM_Frame)==0 ){
/* SubProgram.nMem is set to the number of memory cells used by the
** program stored in SubProgram.aOp. As well as these, one memory
** cell is required for each cursor used by the program. Set local
- ** variable u.cc.nMem (and later, VdbeFrame.nChildMem) to this value.
+ ** variable u.cd.nMem (and later, VdbeFrame.nChildMem) to this value.
*/
- u.cc.nMem = u.cc.pProgram->nMem + u.cc.pProgram->nCsr;
- u.cc.nByte = ROUND8(sizeof(VdbeFrame))
- + u.cc.nMem * sizeof(Mem)
- + u.cc.pProgram->nCsr * sizeof(VdbeCursor *)
- + u.cc.pProgram->nOnce * sizeof(u8);
- u.cc.pFrame = sqlite3DbMallocZero(db, u.cc.nByte);
- if( !u.cc.pFrame ){
+ u.cd.nMem = u.cd.pProgram->nMem + u.cd.pProgram->nCsr;
+ u.cd.nByte = ROUND8(sizeof(VdbeFrame))
+ + u.cd.nMem * sizeof(Mem)
+ + u.cd.pProgram->nCsr * sizeof(VdbeCursor *)
+ + u.cd.pProgram->nOnce * sizeof(u8);
+ u.cd.pFrame = sqlite3DbMallocZero(db, u.cd.nByte);
+ if( !u.cd.pFrame ){
goto no_mem;
}
- sqlite3VdbeMemRelease(u.cc.pRt);
- u.cc.pRt->flags = MEM_Frame;
- u.cc.pRt->u.pFrame = u.cc.pFrame;
+ sqlite3VdbeMemRelease(u.cd.pRt);
+ u.cd.pRt->flags = MEM_Frame;
+ u.cd.pRt->u.pFrame = u.cd.pFrame;
- u.cc.pFrame->v = p;
- u.cc.pFrame->nChildMem = u.cc.nMem;
- u.cc.pFrame->nChildCsr = u.cc.pProgram->nCsr;
- u.cc.pFrame->pc = pc;
- u.cc.pFrame->aMem = p->aMem;
- u.cc.pFrame->nMem = p->nMem;
- u.cc.pFrame->apCsr = p->apCsr;
- u.cc.pFrame->nCursor = p->nCursor;
- u.cc.pFrame->aOp = p->aOp;
- u.cc.pFrame->nOp = p->nOp;
- u.cc.pFrame->token = u.cc.pProgram->token;
- u.cc.pFrame->aOnceFlag = p->aOnceFlag;
- u.cc.pFrame->nOnceFlag = p->nOnceFlag;
+ u.cd.pFrame->v = p;
+ u.cd.pFrame->nChildMem = u.cd.nMem;
+ u.cd.pFrame->nChildCsr = u.cd.pProgram->nCsr;
+ u.cd.pFrame->pc = pc;
+ u.cd.pFrame->aMem = p->aMem;
+ u.cd.pFrame->nMem = p->nMem;
+ u.cd.pFrame->apCsr = p->apCsr;
+ u.cd.pFrame->nCursor = p->nCursor;
+ u.cd.pFrame->aOp = p->aOp;
+ u.cd.pFrame->nOp = p->nOp;
+ u.cd.pFrame->token = u.cd.pProgram->token;
+ u.cd.pFrame->aOnceFlag = p->aOnceFlag;
+ u.cd.pFrame->nOnceFlag = p->nOnceFlag;
- u.cc.pEnd = &VdbeFrameMem(u.cc.pFrame)[u.cc.pFrame->nChildMem];
- for(u.cc.pMem=VdbeFrameMem(u.cc.pFrame); u.cc.pMem!=u.cc.pEnd; u.cc.pMem++){
- u.cc.pMem->flags = MEM_Invalid;
- u.cc.pMem->db = db;
+ u.cd.pEnd = &VdbeFrameMem(u.cd.pFrame)[u.cd.pFrame->nChildMem];
+ for(u.cd.pMem=VdbeFrameMem(u.cd.pFrame); u.cd.pMem!=u.cd.pEnd; u.cd.pMem++){
+ u.cd.pMem->flags = MEM_Invalid;
+ u.cd.pMem->db = db;
}
}else{
- u.cc.pFrame = u.cc.pRt->u.pFrame;
- assert( u.cc.pProgram->nMem+u.cc.pProgram->nCsr==u.cc.pFrame->nChildMem );
- assert( u.cc.pProgram->nCsr==u.cc.pFrame->nChildCsr );
- assert( pc==u.cc.pFrame->pc );
+ u.cd.pFrame = u.cd.pRt->u.pFrame;
+ assert( u.cd.pProgram->nMem+u.cd.pProgram->nCsr==u.cd.pFrame->nChildMem );
+ assert( u.cd.pProgram->nCsr==u.cd.pFrame->nChildCsr );
+ assert( pc==u.cd.pFrame->pc );
}
p->nFrame++;
- u.cc.pFrame->pParent = p->pFrame;
- u.cc.pFrame->lastRowid = lastRowid;
- u.cc.pFrame->nChange = p->nChange;
+ u.cd.pFrame->pParent = p->pFrame;
+ u.cd.pFrame->lastRowid = lastRowid;
+ u.cd.pFrame->nChange = p->nChange;
p->nChange = 0;
- p->pFrame = u.cc.pFrame;
- p->aMem = aMem = &VdbeFrameMem(u.cc.pFrame)[-1];
- p->nMem = u.cc.pFrame->nChildMem;
- p->nCursor = (u16)u.cc.pFrame->nChildCsr;
+ p->pFrame = u.cd.pFrame;
+ p->aMem = aMem = &VdbeFrameMem(u.cd.pFrame)[-1];
+ p->nMem = u.cd.pFrame->nChildMem;
+ p->nCursor = (u16)u.cd.pFrame->nChildCsr;
p->apCsr = (VdbeCursor **)&aMem[p->nMem+1];
- p->aOp = aOp = u.cc.pProgram->aOp;
- p->nOp = u.cc.pProgram->nOp;
+ p->aOp = aOp = u.cd.pProgram->aOp;
+ p->nOp = u.cd.pProgram->nOp;
p->aOnceFlag = (u8 *)&p->apCsr[p->nCursor];
- p->nOnceFlag = u.cc.pProgram->nOnce;
+ p->nOnceFlag = u.cd.pProgram->nOnce;
pc = -1;
memset(p->aOnceFlag, 0, p->nOnceFlag);
@@ -68785,13 +70675,13 @@ case OP_Program: { /* jump */
** calling OP_Program instruction.
*/
case OP_Param: { /* out2-prerelease */
-#if 0 /* local variables moved into u.cd */
+#if 0 /* local variables moved into u.ce */
VdbeFrame *pFrame;
Mem *pIn;
-#endif /* local variables moved into u.cd */
- u.cd.pFrame = p->pFrame;
- u.cd.pIn = &u.cd.pFrame->aMem[pOp->p1 + u.cd.pFrame->aOp[u.cd.pFrame->pc].p1];
- sqlite3VdbeMemShallowCopy(pOut, u.cd.pIn, MEM_Ephem);
+#endif /* local variables moved into u.ce */
+ u.ce.pFrame = p->pFrame;
+ u.ce.pIn = &u.ce.pFrame->aMem[pOp->p1 + u.ce.pFrame->aOp[u.ce.pFrame->pc].p1];
+ sqlite3VdbeMemShallowCopy(pOut, u.ce.pIn, MEM_Ephem);
break;
}
@@ -68847,22 +70737,22 @@ case OP_FkIfZero: { /* jump */
** an integer.
*/
case OP_MemMax: { /* in2 */
-#if 0 /* local variables moved into u.ce */
+#if 0 /* local variables moved into u.cf */
Mem *pIn1;
VdbeFrame *pFrame;
-#endif /* local variables moved into u.ce */
+#endif /* local variables moved into u.cf */
if( p->pFrame ){
- for(u.ce.pFrame=p->pFrame; u.ce.pFrame->pParent; u.ce.pFrame=u.ce.pFrame->pParent);
- u.ce.pIn1 = &u.ce.pFrame->aMem[pOp->p1];
+ for(u.cf.pFrame=p->pFrame; u.cf.pFrame->pParent; u.cf.pFrame=u.cf.pFrame->pParent);
+ u.cf.pIn1 = &u.cf.pFrame->aMem[pOp->p1];
}else{
- u.ce.pIn1 = &aMem[pOp->p1];
+ u.cf.pIn1 = &aMem[pOp->p1];
}
- assert( memIsValid(u.ce.pIn1) );
- sqlite3VdbeMemIntegerify(u.ce.pIn1);
+ assert( memIsValid(u.cf.pIn1) );
+ sqlite3VdbeMemIntegerify(u.cf.pIn1);
pIn2 = &aMem[pOp->p2];
sqlite3VdbeMemIntegerify(pIn2);
- if( u.ce.pIn1->u.i<pIn2->u.i){
- u.ce.pIn1->u.i = pIn2->u.i;
+ if( u.cf.pIn1->u.i<pIn2->u.i){
+ u.cf.pIn1->u.i = pIn2->u.i;
}
break;
}
@@ -68929,56 +70819,56 @@ case OP_IfZero: { /* jump, in1 */
** successors.
*/
case OP_AggStep: {
-#if 0 /* local variables moved into u.cf */
+#if 0 /* local variables moved into u.cg */
int n;
int i;
Mem *pMem;
Mem *pRec;
sqlite3_context ctx;
sqlite3_value **apVal;
-#endif /* local variables moved into u.cf */
+#endif /* local variables moved into u.cg */
- u.cf.n = pOp->p5;
- assert( u.cf.n>=0 );
- u.cf.pRec = &aMem[pOp->p2];
- u.cf.apVal = p->apArg;
- assert( u.cf.apVal || u.cf.n==0 );
- for(u.cf.i=0; u.cf.i<u.cf.n; u.cf.i++, u.cf.pRec++){
- assert( memIsValid(u.cf.pRec) );
- u.cf.apVal[u.cf.i] = u.cf.pRec;
- memAboutToChange(p, u.cf.pRec);
- sqlite3VdbeMemStoreType(u.cf.pRec);
- }
- u.cf.ctx.pFunc = pOp->p4.pFunc;
+ u.cg.n = pOp->p5;
+ assert( u.cg.n>=0 );
+ u.cg.pRec = &aMem[pOp->p2];
+ u.cg.apVal = p->apArg;
+ assert( u.cg.apVal || u.cg.n==0 );
+ for(u.cg.i=0; u.cg.i<u.cg.n; u.cg.i++, u.cg.pRec++){
+ assert( memIsValid(u.cg.pRec) );
+ u.cg.apVal[u.cg.i] = u.cg.pRec;
+ memAboutToChange(p, u.cg.pRec);
+ sqlite3VdbeMemStoreType(u.cg.pRec);
+ }
+ u.cg.ctx.pFunc = pOp->p4.pFunc;
assert( pOp->p3>0 && pOp->p3<=p->nMem );
- u.cf.ctx.pMem = u.cf.pMem = &aMem[pOp->p3];
- u.cf.pMem->n++;
- u.cf.ctx.s.flags = MEM_Null;
- u.cf.ctx.s.z = 0;
- u.cf.ctx.s.zMalloc = 0;
- u.cf.ctx.s.xDel = 0;
- u.cf.ctx.s.db = db;
- u.cf.ctx.isError = 0;
- u.cf.ctx.pColl = 0;
- u.cf.ctx.skipFlag = 0;
- if( u.cf.ctx.pFunc->flags & SQLITE_FUNC_NEEDCOLL ){
+ u.cg.ctx.pMem = u.cg.pMem = &aMem[pOp->p3];
+ u.cg.pMem->n++;
+ u.cg.ctx.s.flags = MEM_Null;
+ u.cg.ctx.s.z = 0;
+ u.cg.ctx.s.zMalloc = 0;
+ u.cg.ctx.s.xDel = 0;
+ u.cg.ctx.s.db = db;
+ u.cg.ctx.isError = 0;
+ u.cg.ctx.pColl = 0;
+ u.cg.ctx.skipFlag = 0;
+ if( u.cg.ctx.pFunc->flags & SQLITE_FUNC_NEEDCOLL ){
assert( pOp>p->aOp );
assert( pOp[-1].p4type==P4_COLLSEQ );
assert( pOp[-1].opcode==OP_CollSeq );
- u.cf.ctx.pColl = pOp[-1].p4.pColl;
+ u.cg.ctx.pColl = pOp[-1].p4.pColl;
}
- (u.cf.ctx.pFunc->xStep)(&u.cf.ctx, u.cf.n, u.cf.apVal); /* IMP: R-24505-23230 */
- if( u.cf.ctx.isError ){
- sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&u.cf.ctx.s));
- rc = u.cf.ctx.isError;
+ (u.cg.ctx.pFunc->xStep)(&u.cg.ctx, u.cg.n, u.cg.apVal); /* IMP: R-24505-23230 */
+ if( u.cg.ctx.isError ){
+ sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&u.cg.ctx.s));
+ rc = u.cg.ctx.isError;
}
- if( u.cf.ctx.skipFlag ){
+ if( u.cg.ctx.skipFlag ){
assert( pOp[-1].opcode==OP_CollSeq );
- u.cf.i = pOp[-1].p1;
- if( u.cf.i ) sqlite3VdbeMemSetInt64(&aMem[u.cf.i], 1);
+ u.cg.i = pOp[-1].p1;
+ if( u.cg.i ) sqlite3VdbeMemSetInt64(&aMem[u.cg.i], 1);
}
- sqlite3VdbeMemRelease(&u.cf.ctx.s);
+ sqlite3VdbeMemRelease(&u.cg.ctx.s);
break;
}
@@ -68996,19 +70886,19 @@ case OP_AggStep: {
** the step function was not previously called.
*/
case OP_AggFinal: {
-#if 0 /* local variables moved into u.cg */
+#if 0 /* local variables moved into u.ch */
Mem *pMem;
-#endif /* local variables moved into u.cg */
+#endif /* local variables moved into u.ch */
assert( pOp->p1>0 && pOp->p1<=p->nMem );
- u.cg.pMem = &aMem[pOp->p1];
- assert( (u.cg.pMem->flags & ~(MEM_Null|MEM_Agg))==0 );
- rc = sqlite3VdbeMemFinalize(u.cg.pMem, pOp->p4.pFunc);
+ u.ch.pMem = &aMem[pOp->p1];
+ assert( (u.ch.pMem->flags & ~(MEM_Null|MEM_Agg))==0 );
+ rc = sqlite3VdbeMemFinalize(u.ch.pMem, pOp->p4.pFunc);
if( rc ){
- sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(u.cg.pMem));
+ sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(u.ch.pMem));
}
- sqlite3VdbeChangeEncoding(u.cg.pMem, encoding);
- UPDATE_MAX_BLOBSIZE(u.cg.pMem);
- if( sqlite3VdbeMemTooBig(u.cg.pMem) ){
+ sqlite3VdbeChangeEncoding(u.ch.pMem, encoding);
+ UPDATE_MAX_BLOBSIZE(u.ch.pMem);
+ if( sqlite3VdbeMemTooBig(u.ch.pMem) ){
goto too_big;
}
break;
@@ -69027,25 +70917,25 @@ case OP_AggFinal: {
** mem[P3+2] are initialized to -1.
*/
case OP_Checkpoint: {
-#if 0 /* local variables moved into u.ch */
+#if 0 /* local variables moved into u.ci */
int i; /* Loop counter */
int aRes[3]; /* Results */
Mem *pMem; /* Write results here */
-#endif /* local variables moved into u.ch */
+#endif /* local variables moved into u.ci */
- u.ch.aRes[0] = 0;
- u.ch.aRes[1] = u.ch.aRes[2] = -1;
+ u.ci.aRes[0] = 0;
+ u.ci.aRes[1] = u.ci.aRes[2] = -1;
assert( pOp->p2==SQLITE_CHECKPOINT_PASSIVE
|| pOp->p2==SQLITE_CHECKPOINT_FULL
|| pOp->p2==SQLITE_CHECKPOINT_RESTART
);
- rc = sqlite3Checkpoint(db, pOp->p1, pOp->p2, &u.ch.aRes[1], &u.ch.aRes[2]);
+ rc = sqlite3Checkpoint(db, pOp->p1, pOp->p2, &u.ci.aRes[1], &u.ci.aRes[2]);
if( rc==SQLITE_BUSY ){
rc = SQLITE_OK;
- u.ch.aRes[0] = 1;
+ u.ci.aRes[0] = 1;
}
- for(u.ch.i=0, u.ch.pMem = &aMem[pOp->p3]; u.ch.i<3; u.ch.i++, u.ch.pMem++){
- sqlite3VdbeMemSetInt64(u.ch.pMem, (i64)u.ch.aRes[u.ch.i]);
+ for(u.ci.i=0, u.ci.pMem = &aMem[pOp->p3]; u.ci.i<3; u.ci.i++, u.ci.pMem++){
+ sqlite3VdbeMemSetInt64(u.ci.pMem, (i64)u.ci.aRes[u.ci.i]);
}
break;
};
@@ -69064,91 +70954,93 @@ case OP_Checkpoint: {
** Write a string containing the final journal-mode to register P2.
*/
case OP_JournalMode: { /* out2-prerelease */
-#if 0 /* local variables moved into u.ci */
+#if 0 /* local variables moved into u.cj */
Btree *pBt; /* Btree to change journal mode of */
Pager *pPager; /* Pager associated with pBt */
int eNew; /* New journal mode */
int eOld; /* The old journal mode */
+#ifndef SQLITE_OMIT_WAL
const char *zFilename; /* Name of database file for pPager */
-#endif /* local variables moved into u.ci */
+#endif
+#endif /* local variables moved into u.cj */
- u.ci.eNew = pOp->p3;
- assert( u.ci.eNew==PAGER_JOURNALMODE_DELETE
- || u.ci.eNew==PAGER_JOURNALMODE_TRUNCATE
- || u.ci.eNew==PAGER_JOURNALMODE_PERSIST
- || u.ci.eNew==PAGER_JOURNALMODE_OFF
- || u.ci.eNew==PAGER_JOURNALMODE_MEMORY
- || u.ci.eNew==PAGER_JOURNALMODE_WAL
- || u.ci.eNew==PAGER_JOURNALMODE_QUERY
+ u.cj.eNew = pOp->p3;
+ assert( u.cj.eNew==PAGER_JOURNALMODE_DELETE
+ || u.cj.eNew==PAGER_JOURNALMODE_TRUNCATE
+ || u.cj.eNew==PAGER_JOURNALMODE_PERSIST
+ || u.cj.eNew==PAGER_JOURNALMODE_OFF
+ || u.cj.eNew==PAGER_JOURNALMODE_MEMORY
+ || u.cj.eNew==PAGER_JOURNALMODE_WAL
+ || u.cj.eNew==PAGER_JOURNALMODE_QUERY
);
assert( pOp->p1>=0 && pOp->p1<db->nDb );
- u.ci.pBt = db->aDb[pOp->p1].pBt;
- u.ci.pPager = sqlite3BtreePager(u.ci.pBt);
- u.ci.eOld = sqlite3PagerGetJournalMode(u.ci.pPager);
- if( u.ci.eNew==PAGER_JOURNALMODE_QUERY ) u.ci.eNew = u.ci.eOld;
- if( !sqlite3PagerOkToChangeJournalMode(u.ci.pPager) ) u.ci.eNew = u.ci.eOld;
+ u.cj.pBt = db->aDb[pOp->p1].pBt;
+ u.cj.pPager = sqlite3BtreePager(u.cj.pBt);
+ u.cj.eOld = sqlite3PagerGetJournalMode(u.cj.pPager);
+ if( u.cj.eNew==PAGER_JOURNALMODE_QUERY ) u.cj.eNew = u.cj.eOld;
+ if( !sqlite3PagerOkToChangeJournalMode(u.cj.pPager) ) u.cj.eNew = u.cj.eOld;
#ifndef SQLITE_OMIT_WAL
- u.ci.zFilename = sqlite3PagerFilename(u.ci.pPager, 1);
+ u.cj.zFilename = sqlite3PagerFilename(u.cj.pPager, 1);
/* Do not allow a transition to journal_mode=WAL for a database
** in temporary storage or if the VFS does not support shared memory
*/
- if( u.ci.eNew==PAGER_JOURNALMODE_WAL
- && (sqlite3Strlen30(u.ci.zFilename)==0 /* Temp file */
- || !sqlite3PagerWalSupported(u.ci.pPager)) /* No shared-memory support */
+ if( u.cj.eNew==PAGER_JOURNALMODE_WAL
+ && (sqlite3Strlen30(u.cj.zFilename)==0 /* Temp file */
+ || !sqlite3PagerWalSupported(u.cj.pPager)) /* No shared-memory support */
){
- u.ci.eNew = u.ci.eOld;
+ u.cj.eNew = u.cj.eOld;
}
- if( (u.ci.eNew!=u.ci.eOld)
- && (u.ci.eOld==PAGER_JOURNALMODE_WAL || u.ci.eNew==PAGER_JOURNALMODE_WAL)
+ if( (u.cj.eNew!=u.cj.eOld)
+ && (u.cj.eOld==PAGER_JOURNALMODE_WAL || u.cj.eNew==PAGER_JOURNALMODE_WAL)
){
if( !db->autoCommit || db->activeVdbeCnt>1 ){
rc = SQLITE_ERROR;
sqlite3SetString(&p->zErrMsg, db,
"cannot change %s wal mode from within a transaction",
- (u.ci.eNew==PAGER_JOURNALMODE_WAL ? "into" : "out of")
+ (u.cj.eNew==PAGER_JOURNALMODE_WAL ? "into" : "out of")
);
break;
}else{
- if( u.ci.eOld==PAGER_JOURNALMODE_WAL ){
+ if( u.cj.eOld==PAGER_JOURNALMODE_WAL ){
/* If leaving WAL mode, close the log file. If successful, the call
** to PagerCloseWal() checkpoints and deletes the write-ahead-log
** file. An EXCLUSIVE lock may still be held on the database file
** after a successful return.
*/
- rc = sqlite3PagerCloseWal(u.ci.pPager);
+ rc = sqlite3PagerCloseWal(u.cj.pPager);
if( rc==SQLITE_OK ){
- sqlite3PagerSetJournalMode(u.ci.pPager, u.ci.eNew);
+ sqlite3PagerSetJournalMode(u.cj.pPager, u.cj.eNew);
}
- }else if( u.ci.eOld==PAGER_JOURNALMODE_MEMORY ){
+ }else if( u.cj.eOld==PAGER_JOURNALMODE_MEMORY ){
/* Cannot transition directly from MEMORY to WAL. Use mode OFF
** as an intermediate */
- sqlite3PagerSetJournalMode(u.ci.pPager, PAGER_JOURNALMODE_OFF);
+ sqlite3PagerSetJournalMode(u.cj.pPager, PAGER_JOURNALMODE_OFF);
}
/* Open a transaction on the database file. Regardless of the journal
** mode, this transaction always uses a rollback journal.
*/
- assert( sqlite3BtreeIsInTrans(u.ci.pBt)==0 );
+ assert( sqlite3BtreeIsInTrans(u.cj.pBt)==0 );
if( rc==SQLITE_OK ){
- rc = sqlite3BtreeSetVersion(u.ci.pBt, (u.ci.eNew==PAGER_JOURNALMODE_WAL ? 2 : 1));
+ rc = sqlite3BtreeSetVersion(u.cj.pBt, (u.cj.eNew==PAGER_JOURNALMODE_WAL ? 2 : 1));
}
}
}
#endif /* ifndef SQLITE_OMIT_WAL */
if( rc ){
- u.ci.eNew = u.ci.eOld;
+ u.cj.eNew = u.cj.eOld;
}
- u.ci.eNew = sqlite3PagerSetJournalMode(u.ci.pPager, u.ci.eNew);
+ u.cj.eNew = sqlite3PagerSetJournalMode(u.cj.pPager, u.cj.eNew);
pOut = &aMem[pOp->p2];
pOut->flags = MEM_Str|MEM_Static|MEM_Term;
- pOut->z = (char *)sqlite3JournalModename(u.ci.eNew);
+ pOut->z = (char *)sqlite3JournalModename(u.cj.eNew);
pOut->n = sqlite3Strlen30(pOut->z);
pOut->enc = SQLITE_UTF8;
sqlite3VdbeChangeEncoding(pOut, encoding);
@@ -69177,14 +71069,14 @@ case OP_Vacuum: {
** P2. Otherwise, fall through to the next instruction.
*/
case OP_IncrVacuum: { /* jump */
-#if 0 /* local variables moved into u.cj */
+#if 0 /* local variables moved into u.ck */
Btree *pBt;
-#endif /* local variables moved into u.cj */
+#endif /* local variables moved into u.ck */
assert( pOp->p1>=0 && pOp->p1<db->nDb );
assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
- u.cj.pBt = db->aDb[pOp->p1].pBt;
- rc = sqlite3BtreeIncrVacuum(u.cj.pBt);
+ u.ck.pBt = db->aDb[pOp->p1].pBt;
+ rc = sqlite3BtreeIncrVacuum(u.ck.pBt);
if( rc==SQLITE_DONE ){
pc = pOp->p2 - 1;
rc = SQLITE_OK;
@@ -69254,12 +71146,12 @@ case OP_TableLock: {
** code will be set to SQLITE_LOCKED.
*/
case OP_VBegin: {
-#if 0 /* local variables moved into u.ck */
+#if 0 /* local variables moved into u.cl */
VTable *pVTab;
-#endif /* local variables moved into u.ck */
- u.ck.pVTab = pOp->p4.pVtab;
- rc = sqlite3VtabBegin(db, u.ck.pVTab);
- if( u.ck.pVTab ) importVtabErrMsg(p, u.ck.pVTab->pVtab);
+#endif /* local variables moved into u.cl */
+ u.cl.pVTab = pOp->p4.pVtab;
+ rc = sqlite3VtabBegin(db, u.cl.pVTab);
+ if( u.cl.pVTab ) importVtabErrMsg(p, u.cl.pVTab->pVtab);
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -69298,32 +71190,32 @@ case OP_VDestroy: {
** table and stores that cursor in P1.
*/
case OP_VOpen: {
-#if 0 /* local variables moved into u.cl */
+#if 0 /* local variables moved into u.cm */
VdbeCursor *pCur;
sqlite3_vtab_cursor *pVtabCursor;
sqlite3_vtab *pVtab;
sqlite3_module *pModule;
-#endif /* local variables moved into u.cl */
+#endif /* local variables moved into u.cm */
- u.cl.pCur = 0;
- u.cl.pVtabCursor = 0;
- u.cl.pVtab = pOp->p4.pVtab->pVtab;
- u.cl.pModule = (sqlite3_module *)u.cl.pVtab->pModule;
- assert(u.cl.pVtab && u.cl.pModule);
- rc = u.cl.pModule->xOpen(u.cl.pVtab, &u.cl.pVtabCursor);
- importVtabErrMsg(p, u.cl.pVtab);
+ u.cm.pCur = 0;
+ u.cm.pVtabCursor = 0;
+ u.cm.pVtab = pOp->p4.pVtab->pVtab;
+ u.cm.pModule = (sqlite3_module *)u.cm.pVtab->pModule;
+ assert(u.cm.pVtab && u.cm.pModule);
+ rc = u.cm.pModule->xOpen(u.cm.pVtab, &u.cm.pVtabCursor);
+ importVtabErrMsg(p, u.cm.pVtab);
if( SQLITE_OK==rc ){
/* Initialize sqlite3_vtab_cursor base class */
- u.cl.pVtabCursor->pVtab = u.cl.pVtab;
+ u.cm.pVtabCursor->pVtab = u.cm.pVtab;
- /* Initialise vdbe cursor object */
- u.cl.pCur = allocateCursor(p, pOp->p1, 0, -1, 0);
- if( u.cl.pCur ){
- u.cl.pCur->pVtabCursor = u.cl.pVtabCursor;
- u.cl.pCur->pModule = u.cl.pVtabCursor->pVtab->pModule;
+ /* Initialize vdbe cursor object */
+ u.cm.pCur = allocateCursor(p, pOp->p1, 0, -1, 0);
+ if( u.cm.pCur ){
+ u.cm.pCur->pVtabCursor = u.cm.pVtabCursor;
+ u.cm.pCur->pModule = u.cm.pVtabCursor->pVtab->pModule;
}else{
db->mallocFailed = 1;
- u.cl.pModule->xClose(u.cl.pVtabCursor);
+ u.cm.pModule->xClose(u.cm.pVtabCursor);
}
}
break;
@@ -69350,7 +71242,7 @@ case OP_VOpen: {
** A jump is made to P2 if the result set after filtering would be empty.
*/
case OP_VFilter: { /* jump */
-#if 0 /* local variables moved into u.cm */
+#if 0 /* local variables moved into u.cn */
int nArg;
int iQuery;
const sqlite3_module *pModule;
@@ -69362,45 +71254,45 @@ case OP_VFilter: { /* jump */
int res;
int i;
Mem **apArg;
-#endif /* local variables moved into u.cm */
+#endif /* local variables moved into u.cn */
- u.cm.pQuery = &aMem[pOp->p3];
- u.cm.pArgc = &u.cm.pQuery[1];
- u.cm.pCur = p->apCsr[pOp->p1];
- assert( memIsValid(u.cm.pQuery) );
- REGISTER_TRACE(pOp->p3, u.cm.pQuery);
- assert( u.cm.pCur->pVtabCursor );
- u.cm.pVtabCursor = u.cm.pCur->pVtabCursor;
- u.cm.pVtab = u.cm.pVtabCursor->pVtab;
- u.cm.pModule = u.cm.pVtab->pModule;
+ u.cn.pQuery = &aMem[pOp->p3];
+ u.cn.pArgc = &u.cn.pQuery[1];
+ u.cn.pCur = p->apCsr[pOp->p1];
+ assert( memIsValid(u.cn.pQuery) );
+ REGISTER_TRACE(pOp->p3, u.cn.pQuery);
+ assert( u.cn.pCur->pVtabCursor );
+ u.cn.pVtabCursor = u.cn.pCur->pVtabCursor;
+ u.cn.pVtab = u.cn.pVtabCursor->pVtab;
+ u.cn.pModule = u.cn.pVtab->pModule;
/* Grab the index number and argc parameters */
- assert( (u.cm.pQuery->flags&MEM_Int)!=0 && u.cm.pArgc->flags==MEM_Int );
- u.cm.nArg = (int)u.cm.pArgc->u.i;
- u.cm.iQuery = (int)u.cm.pQuery->u.i;
+ assert( (u.cn.pQuery->flags&MEM_Int)!=0 && u.cn.pArgc->flags==MEM_Int );
+ u.cn.nArg = (int)u.cn.pArgc->u.i;
+ u.cn.iQuery = (int)u.cn.pQuery->u.i;
/* Invoke the xFilter method */
{
- u.cm.res = 0;
- u.cm.apArg = p->apArg;
- for(u.cm.i = 0; u.cm.i<u.cm.nArg; u.cm.i++){
- u.cm.apArg[u.cm.i] = &u.cm.pArgc[u.cm.i+1];
- sqlite3VdbeMemStoreType(u.cm.apArg[u.cm.i]);
+ u.cn.res = 0;
+ u.cn.apArg = p->apArg;
+ for(u.cn.i = 0; u.cn.i<u.cn.nArg; u.cn.i++){
+ u.cn.apArg[u.cn.i] = &u.cn.pArgc[u.cn.i+1];
+ sqlite3VdbeMemStoreType(u.cn.apArg[u.cn.i]);
}
p->inVtabMethod = 1;
- rc = u.cm.pModule->xFilter(u.cm.pVtabCursor, u.cm.iQuery, pOp->p4.z, u.cm.nArg, u.cm.apArg);
+ rc = u.cn.pModule->xFilter(u.cn.pVtabCursor, u.cn.iQuery, pOp->p4.z, u.cn.nArg, u.cn.apArg);
p->inVtabMethod = 0;
- importVtabErrMsg(p, u.cm.pVtab);
+ importVtabErrMsg(p, u.cn.pVtab);
if( rc==SQLITE_OK ){
- u.cm.res = u.cm.pModule->xEof(u.cm.pVtabCursor);
+ u.cn.res = u.cn.pModule->xEof(u.cn.pVtabCursor);
}
- if( u.cm.res ){
+ if( u.cn.res ){
pc = pOp->p2 - 1;
}
}
- u.cm.pCur->nullRow = 0;
+ u.cn.pCur->nullRow = 0;
break;
}
@@ -69414,51 +71306,51 @@ case OP_VFilter: { /* jump */
** P1 cursor is pointing to into register P3.
*/
case OP_VColumn: {
-#if 0 /* local variables moved into u.cn */
+#if 0 /* local variables moved into u.co */
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
Mem *pDest;
sqlite3_context sContext;
-#endif /* local variables moved into u.cn */
+#endif /* local variables moved into u.co */
VdbeCursor *pCur = p->apCsr[pOp->p1];
assert( pCur->pVtabCursor );
assert( pOp->p3>0 && pOp->p3<=p->nMem );
- u.cn.pDest = &aMem[pOp->p3];
- memAboutToChange(p, u.cn.pDest);
+ u.co.pDest = &aMem[pOp->p3];
+ memAboutToChange(p, u.co.pDest);
if( pCur->nullRow ){
- sqlite3VdbeMemSetNull(u.cn.pDest);
+ sqlite3VdbeMemSetNull(u.co.pDest);
break;
}
- u.cn.pVtab = pCur->pVtabCursor->pVtab;
- u.cn.pModule = u.cn.pVtab->pModule;
- assert( u.cn.pModule->xColumn );
- memset(&u.cn.sContext, 0, sizeof(u.cn.sContext));
+ u.co.pVtab = pCur->pVtabCursor->pVtab;
+ u.co.pModule = u.co.pVtab->pModule;
+ assert( u.co.pModule->xColumn );
+ memset(&u.co.sContext, 0, sizeof(u.co.sContext));
/* The output cell may already have a buffer allocated. Move
- ** the current contents to u.cn.sContext.s so in case the user-function
+ ** the current contents to u.co.sContext.s so in case the user-function
** can use the already allocated buffer instead of allocating a
** new one.
*/
- sqlite3VdbeMemMove(&u.cn.sContext.s, u.cn.pDest);
- MemSetTypeFlag(&u.cn.sContext.s, MEM_Null);
+ sqlite3VdbeMemMove(&u.co.sContext.s, u.co.pDest);
+ MemSetTypeFlag(&u.co.sContext.s, MEM_Null);
- rc = u.cn.pModule->xColumn(pCur->pVtabCursor, &u.cn.sContext, pOp->p2);
- importVtabErrMsg(p, u.cn.pVtab);
- if( u.cn.sContext.isError ){
- rc = u.cn.sContext.isError;
+ rc = u.co.pModule->xColumn(pCur->pVtabCursor, &u.co.sContext, pOp->p2);
+ importVtabErrMsg(p, u.co.pVtab);
+ if( u.co.sContext.isError ){
+ rc = u.co.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 u.cn.sContext.s (a Mem struct) is released.
+ ** dynamic allocation in u.co.sContext.s (a Mem struct) is released.
*/
- sqlite3VdbeChangeEncoding(&u.cn.sContext.s, encoding);
- sqlite3VdbeMemMove(u.cn.pDest, &u.cn.sContext.s);
- REGISTER_TRACE(pOp->p3, u.cn.pDest);
- UPDATE_MAX_BLOBSIZE(u.cn.pDest);
+ sqlite3VdbeChangeEncoding(&u.co.sContext.s, encoding);
+ sqlite3VdbeMemMove(u.co.pDest, &u.co.sContext.s);
+ REGISTER_TRACE(pOp->p3, u.co.pDest);
+ UPDATE_MAX_BLOBSIZE(u.co.pDest);
- if( sqlite3VdbeMemTooBig(u.cn.pDest) ){
+ if( sqlite3VdbeMemTooBig(u.co.pDest) ){
goto too_big;
}
break;
@@ -69473,22 +71365,22 @@ case OP_VColumn: {
** the end of its result set, then fall through to the next instruction.
*/
case OP_VNext: { /* jump */
-#if 0 /* local variables moved into u.co */
+#if 0 /* local variables moved into u.cp */
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
int res;
VdbeCursor *pCur;
-#endif /* local variables moved into u.co */
+#endif /* local variables moved into u.cp */
- u.co.res = 0;
- u.co.pCur = p->apCsr[pOp->p1];
- assert( u.co.pCur->pVtabCursor );
- if( u.co.pCur->nullRow ){
+ u.cp.res = 0;
+ u.cp.pCur = p->apCsr[pOp->p1];
+ assert( u.cp.pCur->pVtabCursor );
+ if( u.cp.pCur->nullRow ){
break;
}
- u.co.pVtab = u.co.pCur->pVtabCursor->pVtab;
- u.co.pModule = u.co.pVtab->pModule;
- assert( u.co.pModule->xNext );
+ u.cp.pVtab = u.cp.pCur->pVtabCursor->pVtab;
+ u.cp.pModule = u.cp.pVtab->pModule;
+ assert( u.cp.pModule->xNext );
/* Invoke the xNext() method of the module. There is no way for the
** underlying implementation to return an error if one occurs during
@@ -69497,14 +71389,14 @@ case OP_VNext: { /* jump */
** some other method is next invoked on the save virtual table cursor.
*/
p->inVtabMethod = 1;
- rc = u.co.pModule->xNext(u.co.pCur->pVtabCursor);
+ rc = u.cp.pModule->xNext(u.cp.pCur->pVtabCursor);
p->inVtabMethod = 0;
- importVtabErrMsg(p, u.co.pVtab);
+ importVtabErrMsg(p, u.cp.pVtab);
if( rc==SQLITE_OK ){
- u.co.res = u.co.pModule->xEof(u.co.pCur->pVtabCursor);
+ u.cp.res = u.cp.pModule->xEof(u.cp.pCur->pVtabCursor);
}
- if( !u.co.res ){
+ if( !u.cp.res ){
/* If there is data, jump to P2 */
pc = pOp->p2 - 1;
}
@@ -69520,24 +71412,24 @@ case OP_VNext: { /* jump */
** in register P1 is passed as the zName argument to the xRename method.
*/
case OP_VRename: {
-#if 0 /* local variables moved into u.cp */
+#if 0 /* local variables moved into u.cq */
sqlite3_vtab *pVtab;
Mem *pName;
-#endif /* local variables moved into u.cp */
+#endif /* local variables moved into u.cq */
- u.cp.pVtab = pOp->p4.pVtab->pVtab;
- u.cp.pName = &aMem[pOp->p1];
- assert( u.cp.pVtab->pModule->xRename );
- assert( memIsValid(u.cp.pName) );
- REGISTER_TRACE(pOp->p1, u.cp.pName);
- assert( u.cp.pName->flags & MEM_Str );
- testcase( u.cp.pName->enc==SQLITE_UTF8 );
- testcase( u.cp.pName->enc==SQLITE_UTF16BE );
- testcase( u.cp.pName->enc==SQLITE_UTF16LE );
- rc = sqlite3VdbeChangeEncoding(u.cp.pName, SQLITE_UTF8);
+ u.cq.pVtab = pOp->p4.pVtab->pVtab;
+ u.cq.pName = &aMem[pOp->p1];
+ assert( u.cq.pVtab->pModule->xRename );
+ assert( memIsValid(u.cq.pName) );
+ REGISTER_TRACE(pOp->p1, u.cq.pName);
+ assert( u.cq.pName->flags & MEM_Str );
+ testcase( u.cq.pName->enc==SQLITE_UTF8 );
+ testcase( u.cq.pName->enc==SQLITE_UTF16BE );
+ testcase( u.cq.pName->enc==SQLITE_UTF16LE );
+ rc = sqlite3VdbeChangeEncoding(u.cq.pName, SQLITE_UTF8);
if( rc==SQLITE_OK ){
- rc = u.cp.pVtab->pModule->xRename(u.cp.pVtab, u.cp.pName->z);
- importVtabErrMsg(p, u.cp.pVtab);
+ rc = u.cq.pVtab->pModule->xRename(u.cq.pVtab, u.cq.pName->z);
+ importVtabErrMsg(p, u.cq.pVtab);
p->expired = 0;
}
break;
@@ -69569,7 +71461,7 @@ case OP_VRename: {
** is set to the value of the rowid for the row just inserted.
*/
case OP_VUpdate: {
-#if 0 /* local variables moved into u.cq */
+#if 0 /* local variables moved into u.cr */
sqlite3_vtab *pVtab;
sqlite3_module *pModule;
int nArg;
@@ -69577,35 +71469,35 @@ case OP_VUpdate: {
sqlite_int64 rowid;
Mem **apArg;
Mem *pX;
-#endif /* local variables moved into u.cq */
+#endif /* local variables moved into u.cr */
assert( pOp->p2==1 || pOp->p5==OE_Fail || pOp->p5==OE_Rollback
|| pOp->p5==OE_Abort || pOp->p5==OE_Ignore || pOp->p5==OE_Replace
);
- u.cq.pVtab = pOp->p4.pVtab->pVtab;
- u.cq.pModule = (sqlite3_module *)u.cq.pVtab->pModule;
- u.cq.nArg = pOp->p2;
+ u.cr.pVtab = pOp->p4.pVtab->pVtab;
+ u.cr.pModule = (sqlite3_module *)u.cr.pVtab->pModule;
+ u.cr.nArg = pOp->p2;
assert( pOp->p4type==P4_VTAB );
- if( ALWAYS(u.cq.pModule->xUpdate) ){
+ if( ALWAYS(u.cr.pModule->xUpdate) ){
u8 vtabOnConflict = db->vtabOnConflict;
- u.cq.apArg = p->apArg;
- u.cq.pX = &aMem[pOp->p3];
- for(u.cq.i=0; u.cq.i<u.cq.nArg; u.cq.i++){
- assert( memIsValid(u.cq.pX) );
- memAboutToChange(p, u.cq.pX);
- sqlite3VdbeMemStoreType(u.cq.pX);
- u.cq.apArg[u.cq.i] = u.cq.pX;
- u.cq.pX++;
+ u.cr.apArg = p->apArg;
+ u.cr.pX = &aMem[pOp->p3];
+ for(u.cr.i=0; u.cr.i<u.cr.nArg; u.cr.i++){
+ assert( memIsValid(u.cr.pX) );
+ memAboutToChange(p, u.cr.pX);
+ sqlite3VdbeMemStoreType(u.cr.pX);
+ u.cr.apArg[u.cr.i] = u.cr.pX;
+ u.cr.pX++;
}
db->vtabOnConflict = pOp->p5;
- rc = u.cq.pModule->xUpdate(u.cq.pVtab, u.cq.nArg, u.cq.apArg, &u.cq.rowid);
+ rc = u.cr.pModule->xUpdate(u.cr.pVtab, u.cr.nArg, u.cr.apArg, &u.cr.rowid);
db->vtabOnConflict = vtabOnConflict;
- importVtabErrMsg(p, u.cq.pVtab);
+ importVtabErrMsg(p, u.cr.pVtab);
if( rc==SQLITE_OK && pOp->p1 ){
- assert( u.cq.nArg>1 && u.cq.apArg[0] && (u.cq.apArg[0]->flags&MEM_Null) );
- db->lastRowid = lastRowid = u.cq.rowid;
+ assert( u.cr.nArg>1 && u.cr.apArg[0] && (u.cr.apArg[0]->flags&MEM_Null) );
+ db->lastRowid = lastRowid = u.cr.rowid;
}
- if( rc==SQLITE_CONSTRAINT && pOp->p4.pVtab->bConstraint ){
+ if( (rc&0xff)==SQLITE_CONSTRAINT && pOp->p4.pVtab->bConstraint ){
if( pOp->p5==OE_Ignore ){
rc = SQLITE_OK;
}else{
@@ -69663,21 +71555,24 @@ case OP_MaxPgcnt: { /* out2-prerelease */
** the UTF-8 string contained in P4 is emitted on the trace callback.
*/
case OP_Trace: {
-#if 0 /* local variables moved into u.cr */
+#if 0 /* local variables moved into u.cs */
char *zTrace;
char *z;
-#endif /* local variables moved into u.cr */
+#endif /* local variables moved into u.cs */
- if( db->xTrace && (u.cr.zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0 ){
- u.cr.z = sqlite3VdbeExpandSql(p, u.cr.zTrace);
- db->xTrace(db->pTraceArg, u.cr.z);
- sqlite3DbFree(db, u.cr.z);
+ if( db->xTrace
+ && !p->doingRerun
+ && (u.cs.zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0
+ ){
+ u.cs.z = sqlite3VdbeExpandSql(p, u.cs.zTrace);
+ db->xTrace(db->pTraceArg, u.cs.z);
+ sqlite3DbFree(db, u.cs.z);
}
#ifdef SQLITE_DEBUG
if( (db->flags & SQLITE_SqlTrace)!=0
- && (u.cr.zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0
+ && (u.cs.zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0
){
- sqlite3DebugPrintf("SQL-trace: %s\n", u.cr.zTrace);
+ sqlite3DebugPrintf("SQL-trace: %s\n", u.cs.zTrace);
}
#endif /* SQLITE_DEBUG */
break;
@@ -70120,7 +72015,7 @@ SQLITE_API int sqlite3_blob_open(
}
sqlite3_bind_int64(pBlob->pStmt, 1, iRow);
rc = blobSeekToRow(pBlob, iRow, &zErr);
- } while( (++nAttempt)<5 && rc==SQLITE_SCHEMA );
+ } while( (++nAttempt)<SQLITE_MAX_SCHEMA_RETRY && rc==SQLITE_SCHEMA );
blob_open_out:
if( rc==SQLITE_OK && db->mallocFailed==0 ){
@@ -70295,7 +72190,6 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
*/
-#ifndef SQLITE_OMIT_MERGE_SORT
typedef struct VdbeSorterIter VdbeSorterIter;
typedef struct SorterRecord SorterRecord;
@@ -70472,8 +72366,11 @@ static int vdbeSorterIterRead(
int rc; /* sqlite3OsRead() return code */
/* Determine how many bytes of data to read. */
- nRead = (int)(p->iEof - p->iReadOff);
- if( nRead>p->nBuffer ) nRead = p->nBuffer;
+ if( (p->iEof - p->iReadOff) > (i64)p->nBuffer ){
+ nRead = p->nBuffer;
+ }else{
+ nRead = (int)(p->iEof - p->iReadOff);
+ }
assert( nRead>0 );
/* Read data from the file. Return early if an error occurs. */
@@ -71312,8 +73209,6 @@ SQLITE_PRIVATE int sqlite3VdbeSorterCompare(
return SQLITE_OK;
}
-#endif /* #ifndef SQLITE_OMIT_MERGE_SORT */
-
/************** End of vdbesort.c ********************************************/
/************** Begin file journal.c *****************************************/
/*
@@ -71376,6 +73271,14 @@ static int createFile(JournalFile *p){
assert(p->iSize<=p->nBuf);
rc = sqlite3OsWrite(p->pReal, p->zBuf, p->iSize, 0);
}
+ if( rc!=SQLITE_OK ){
+ /* If an error occurred while writing to the file, close it before
+ ** returning. This way, SQLite uses the in-memory journal data to
+ ** roll back changes made to the internal page-cache before this
+ ** function was called. */
+ sqlite3OsClose(pReal);
+ p->pReal = 0;
+ }
}
}
return rc;
@@ -71545,6 +73448,16 @@ SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *p){
return createFile((JournalFile *)p);
}
+/*
+** The file-handle passed as the only argument is guaranteed to be an open
+** file. It may or may not be of class JournalFile. If the file is a
+** JournalFile, and the underlying file on disk has not yet been opened,
+** return 0. Otherwise, return 1.
+*/
+SQLITE_PRIVATE int sqlite3JournalExists(sqlite3_file *p){
+ return (p->pMethods!=&JournalFileMethods || ((JournalFile *)p)->pReal!=0);
+}
+
/*
** Return the number of bytes required to store a JournalFile that uses vfs
** pVfs to create the underlying on-disk files.
@@ -71787,7 +73700,9 @@ static const struct sqlite3_io_methods MemJournalMethods = {
0, /* xShmMap */
0, /* xShmLock */
0, /* xShmBarrier */
- 0 /* xShmUnlock */
+ 0, /* xShmUnmap */
+ 0, /* xFetch */
+ 0 /* xUnfetch */
};
/*
@@ -71931,7 +73846,9 @@ SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){
/*
** Call sqlite3WalkExpr() for every expression in Select statement p.
** Invoke sqlite3WalkSelect() for subqueries in the FROM clause and
-** on the compound select chain, p->pPrior.
+** on the compound select chain, p->pPrior. Invoke the xSelectCallback()
+** either before or after the walk of expressions and FROM clause, depending
+** on whether pWalker->bSelectDepthFirst is false or true, respectively.
**
** Return WRC_Continue under normal conditions. Return WRC_Abort if
** there is an abort request.
@@ -71945,14 +73862,23 @@ SQLITE_PRIVATE int sqlite3WalkSelect(Walker *pWalker, Select *p){
rc = WRC_Continue;
pWalker->walkerDepth++;
while( p ){
- rc = pWalker->xSelectCallback(pWalker, p);
- if( rc ) break;
+ if( !pWalker->bSelectDepthFirst ){
+ rc = pWalker->xSelectCallback(pWalker, p);
+ if( rc ) break;
+ }
if( sqlite3WalkSelectExpr(pWalker, p)
|| sqlite3WalkSelectFrom(pWalker, p)
){
pWalker->walkerDepth--;
return WRC_Abort;
}
+ if( pWalker->bSelectDepthFirst ){
+ rc = pWalker->xSelectCallback(pWalker, p);
+ /* Depth-first search is currently only used for
+ ** selectAddSubqueryTypeInfo() and that routine always returns
+ ** WRC_Continue (0). So the following branch is never taken. */
+ if( NEVER(rc) ) break;
+ }
p = p->pPrior;
}
pWalker->walkerDepth--;
@@ -72030,6 +73956,15 @@ static void incrAggFunctionDepth(Expr *pExpr, int N){
** from the result in the result-set. We might fix this someday. Or
** then again, we might not...
**
+** If the reference is followed by a COLLATE operator, then make sure
+** the COLLATE operator is preserved. For example:
+**
+** SELECT a+b, c+d FROM t1 ORDER BY 1 COLLATE nocase;
+**
+** Should be transformed into:
+**
+** 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
** zero but it might be more if the alias is contained within a subquery
@@ -72053,8 +73988,9 @@ static void resolveAlias(
assert( pOrig!=0 );
assert( pOrig->flags & EP_Resolved );
db = pParse->db;
+ pDup = sqlite3ExprDup(db, pOrig, 0);
+ if( pDup==0 ) return;
if( pOrig->op!=TK_COLUMN && zType[0]!='G' ){
- pDup = sqlite3ExprDup(db, pOrig, 0);
incrAggFunctionDepth(pDup, nSubquery);
pDup = sqlite3PExpr(pParse, TK_AS, pDup, 0, 0);
if( pDup==0 ) return;
@@ -72062,32 +73998,26 @@ static void resolveAlias(
pEList->a[iCol].iAlias = (u16)(++pParse->nAlias);
}
pDup->iTable = pEList->a[iCol].iAlias;
- }else if( ExprHasProperty(pOrig, EP_IntValue) || pOrig->u.zToken==0 ){
- pDup = sqlite3ExprDup(db, pOrig, 0);
- if( pDup==0 ) return;
- }else{
- char *zToken = pOrig->u.zToken;
- assert( zToken!=0 );
- pOrig->u.zToken = 0;
- pDup = sqlite3ExprDup(db, pOrig, 0);
- pOrig->u.zToken = zToken;
- if( pDup==0 ) return;
- assert( (pDup->flags & (EP_Reduced|EP_TokenOnly))==0 );
- pDup->flags2 |= EP2_MallocedToken;
- pDup->u.zToken = sqlite3DbStrDup(db, zToken);
}
- if( pExpr->flags & EP_ExpCollate ){
- pDup->pColl = pExpr->pColl;
- pDup->flags |= EP_ExpCollate;
+ if( pExpr->op==TK_COLLATE ){
+ pDup = sqlite3ExprAddCollateString(pParse, pDup, pExpr->u.zToken);
}
/* Before calling sqlite3ExprDelete(), set the EP_Static flag. This
** prevents ExprDelete() from deleting the Expr structure itself,
** allowing it to be repopulated by the memcpy() on the following line.
+ ** The pExpr->u.zToken might point into memory that will be freed by the
+ ** sqlite3DbFree(db, pDup) on the last line of this block, so be sure to
+ ** make a copy of the token before doing the sqlite3DbFree().
*/
ExprSetProperty(pExpr, EP_Static);
sqlite3ExprDelete(db, pExpr);
memcpy(pExpr, pDup, sizeof(*pExpr));
+ if( !ExprHasProperty(pExpr, EP_IntValue) && pExpr->u.zToken!=0 ){
+ assert( (pExpr->flags & (EP_Reduced|EP_TokenOnly))==0 );
+ pExpr->u.zToken = sqlite3DbStrDup(db, pExpr->u.zToken);
+ pExpr->flags2 |= EP2_MallocedToken;
+ }
sqlite3DbFree(db, pDup);
}
@@ -72108,6 +74038,35 @@ static int nameInUsingClause(IdList *pUsing, const char *zCol){
return 0;
}
+/*
+** Subqueries stores the original database, table and column names for their
+** result sets in ExprList.a[].zSpan, in the form "DATABASE.TABLE.COLUMN".
+** Check to see if the zSpan given to this routine matches the zDb, zTab,
+** and zCol. If any of zDb, zTab, and zCol are NULL then those fields will
+** match anything.
+*/
+SQLITE_PRIVATE int sqlite3MatchSpanName(
+ const char *zSpan,
+ const char *zCol,
+ const char *zTab,
+ const char *zDb
+){
+ int n;
+ for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
+ if( zDb && (sqlite3StrNICmp(zSpan, zDb, n)!=0 || zDb[n]!=0) ){
+ return 0;
+ }
+ zSpan += n+1;
+ for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
+ if( zTab && (sqlite3StrNICmp(zSpan, zTab, n)!=0 || zTab[n]!=0) ){
+ return 0;
+ }
+ zSpan += n+1;
+ if( zCol && sqlite3StrICmp(zSpan, zCol)!=0 ){
+ return 0;
+ }
+ return 1;
+}
/*
** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up
@@ -72157,13 +74116,27 @@ static int lookupName(
assert( pNC ); /* the name context cannot be NULL. */
assert( zCol ); /* The Z in X.Y.Z cannot be NULL */
- assert( ~ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_Reduced) );
+ assert( !ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_Reduced) );
/* Initialize the node to no-match */
pExpr->iTable = -1;
pExpr->pTab = 0;
ExprSetIrreducible(pExpr);
+ /* Translate the schema name in zDb into a pointer to the corresponding
+ ** schema. If not found, pSchema will remain NULL and nothing will match
+ ** resulting in an appropriate error message toward the end of this routine
+ */
+ if( zDb ){
+ for(i=0; i<db->nDb; i++){
+ assert( db->aDb[i].zName );
+ if( sqlite3StrICmp(db->aDb[i].zName,zDb)==0 ){
+ pSchema = db->aDb[i].pSchema;
+ break;
+ }
+ }
+ }
+
/* Start at the inner-most context and move outward until a match is found */
while( pNC && cnt==0 ){
ExprList *pEList;
@@ -72172,31 +74145,36 @@ static int lookupName(
if( pSrcList ){
for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){
Table *pTab;
- int iDb;
Column *pCol;
pTab = pItem->pTab;
assert( pTab!=0 && pTab->zName!=0 );
- iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
assert( pTab->nCol>0 );
- if( zTab ){
- if( pItem->zAlias ){
- char *zTabName = pItem->zAlias;
- if( sqlite3StrICmp(zTabName, zTab)!=0 ) continue;
- }else{
- char *zTabName = pTab->zName;
- if( NEVER(zTabName==0) || sqlite3StrICmp(zTabName, zTab)!=0 ){
- continue;
- }
- if( zDb!=0 && sqlite3StrICmp(db->aDb[iDb].zName, zDb)!=0 ){
- continue;
+ if( pItem->pSelect && (pItem->pSelect->selFlags & SF_NestedFrom)!=0 ){
+ int hit = 0;
+ pEList = pItem->pSelect->pEList;
+ for(j=0; j<pEList->nExpr; j++){
+ if( sqlite3MatchSpanName(pEList->a[j].zSpan, zCol, zTab, zDb) ){
+ cnt++;
+ cntTab = 2;
+ pMatch = pItem;
+ pExpr->iColumn = j;
+ hit = 1;
}
}
+ if( hit || zTab==0 ) continue;
+ }
+ if( zDb && pTab->pSchema!=pSchema ){
+ continue;
+ }
+ if( zTab ){
+ const char *zTabName = pItem->zAlias ? pItem->zAlias : pTab->zName;
+ assert( zTabName!=0 );
+ if( sqlite3StrICmp(zTabName, zTab)!=0 ){
+ continue;
+ }
}
if( 0==(cntTab++) ){
- pExpr->iTable = pItem->iCursor;
- pExpr->pTab = pTab;
- pSchema = pTab->pSchema;
pMatch = pItem;
}
for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
@@ -72210,17 +74188,19 @@ static int lookupName(
if( nameInUsingClause(pItem->pUsing, zCol) ) continue;
}
cnt++;
- pExpr->iTable = pItem->iCursor;
- pExpr->pTab = pTab;
pMatch = pItem;
- pSchema = pTab->pSchema;
/* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j;
break;
}
}
}
- }
+ if( pMatch ){
+ pExpr->iTable = pMatch->iCursor;
+ pExpr->pTab = pMatch->pTab;
+ pSchema = pExpr->pTab->pSchema;
+ }
+ } /* if( pSrcList ) */
#ifndef SQLITE_OMIT_TRIGGER
/* If we have not already resolved the name, then maybe
@@ -72296,7 +74276,10 @@ static int lookupName(
** Note that the expression in the result set should have already been
** resolved by the time the WHERE clause is resolved.
*/
- if( cnt==0 && (pEList = pNC->pEList)!=0 && zTab==0 ){
+ if( (pEList = pNC->pEList)!=0
+ && zTab==0
+ && ((pNC->ncFlags & NC_AsMaybe)==0 || cnt==0)
+ ){
for(j=0; j<pEList->nExpr; j++){
char *zAs = pEList->a[j].zName;
if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){
@@ -72387,7 +74370,9 @@ static int lookupName(
lookupname_end:
if( cnt==1 ){
assert( pNC!=0 );
- sqlite3AuthRead(pParse, pExpr, pSchema, pNC->pSrcList);
+ if( pExpr->op!=TK_AS ){
+ sqlite3AuthRead(pParse, pExpr, pSchema, pNC->pSrcList);
+ }
/* Increment the nRef value on all name contexts from TopNC up to
** the point where the name matched. */
for(;;){
@@ -72555,7 +74540,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId);
pNC->nErr++;
is_agg = 0;
- }else if( no_such_func ){
+ }else if( no_such_func && pParse->db->init.busy==0 ){
sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId);
pNC->nErr++;
}else if( wrong_num_args ){
@@ -72774,7 +74759,7 @@ static int resolveCompoundOrderBy(
int iCol = -1;
Expr *pE, *pDup;
if( pItem->done ) continue;
- pE = pItem->pExpr;
+ pE = sqlite3ExprSkipCollate(pItem->pExpr);
if( sqlite3ExprIsInteger(pE, &iCol) ){
if( iCol<=0 || iCol>pEList->nExpr ){
resolveOutOfRangeError(pParse, "ORDER", i+1, pEList->nExpr);
@@ -72792,14 +74777,20 @@ static int resolveCompoundOrderBy(
}
}
if( iCol>0 ){
- CollSeq *pColl = pE->pColl;
- int flags = pE->flags & EP_ExpCollate;
+ /* Convert the ORDER BY term into an integer column number iCol,
+ ** taking care to preserve the COLLATE clause if it exists */
+ Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0);
+ if( pNew==0 ) return 1;
+ pNew->flags |= EP_IntValue;
+ pNew->u.iValue = iCol;
+ if( pItem->pExpr==pE ){
+ pItem->pExpr = pNew;
+ }else{
+ assert( pItem->pExpr->op==TK_COLLATE );
+ assert( pItem->pExpr->pLeft==pE );
+ pItem->pExpr->pLeft = pNew;
+ }
sqlite3ExprDelete(db, pE);
- pItem->pExpr = pE = sqlite3Expr(db, TK_INTEGER, 0);
- if( pE==0 ) return 1;
- pE->pColl = pColl;
- pE->flags |= EP_IntValue | flags;
- pE->u.iValue = iCol;
pItem->iOrderByCol = (u16)iCol;
pItem->done = 1;
}else{
@@ -72904,11 +74895,11 @@ static int resolveOrderGroupBy(
pItem->iOrderByCol = (u16)iCol;
continue;
}
- if( sqlite3ExprIsInteger(pE, &iCol) ){
+ if( sqlite3ExprIsInteger(sqlite3ExprSkipCollate(pE), &iCol) ){
/* The ORDER BY term is an integer constant. Again, set the column
** number so that sqlite3ResolveOrderGroupBy() will convert the
** order-by term to a copy of the result-set expression */
- if( iCol<1 ){
+ if( iCol<1 || iCol>0xffff ){
resolveOutOfRangeError(pParse, zType, i+1, nResult);
return 1;
}
@@ -72985,23 +74976,6 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
return WRC_Abort;
}
- /* Set up the local name-context to pass to sqlite3ResolveExprNames() to
- ** resolve the result-set expression list.
- */
- sNC.ncFlags = NC_AllowAgg;
- sNC.pSrcList = p->pSrc;
- sNC.pNext = pOuterNC;
-
- /* Resolve names in the result set. */
- pEList = p->pEList;
- assert( pEList!=0 );
- for(i=0; i<pEList->nExpr; i++){
- Expr *pX = pEList->a[i].pExpr;
- if( sqlite3ResolveExprNames(&sNC, pX) ){
- return WRC_Abort;
- }
- }
-
/* Recursively resolve names in all subqueries
*/
for(i=0; i<p->pSrc->nSrc; i++){
@@ -73029,6 +75003,23 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
}
}
+ /* Set up the local name-context to pass to sqlite3ResolveExprNames() to
+ ** resolve the result-set expression list.
+ */
+ sNC.ncFlags = NC_AllowAgg;
+ sNC.pSrcList = p->pSrc;
+ sNC.pNext = pOuterNC;
+
+ /* Resolve names in the result set. */
+ pEList = p->pEList;
+ assert( pEList!=0 );
+ for(i=0; i<pEList->nExpr; i++){
+ Expr *pX = pEList->a[i].pExpr;
+ if( sqlite3ResolveExprNames(&sNC, pX) ){
+ return WRC_Abort;
+ }
+ }
+
/* If there are no aggregate functions in the result-set, and no GROUP BY
** expression, do not allow aggregates in any of the other expressions.
*/
@@ -73056,11 +75047,10 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
** re-evaluated for each reference to it.
*/
sNC.pEList = p->pEList;
- if( sqlite3ResolveExprNames(&sNC, p->pWhere) ||
- sqlite3ResolveExprNames(&sNC, p->pHaving)
- ){
- return WRC_Abort;
- }
+ sNC.ncFlags |= NC_AsMaybe;
+ if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort;
+ if( sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort;
+ sNC.ncFlags &= ~NC_AsMaybe;
/* The ORDER BY and GROUP BY clauses may not refer to terms in
** outer queries
@@ -73181,6 +75171,7 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames(
#endif
savedHasAgg = pNC->ncFlags & NC_HasAgg;
pNC->ncFlags &= ~NC_HasAgg;
+ memset(&w, 0, sizeof(w));
w.xExprCallback = resolveExprStep;
w.xSelectCallback = resolveSelectStep;
w.pParse = pNC->pParse;
@@ -73221,6 +75212,7 @@ SQLITE_PRIVATE void sqlite3ResolveSelectNames(
Walker w;
assert( p!=0 );
+ memset(&w, 0, sizeof(w));
w.xExprCallback = resolveExprStep;
w.xSelectCallback = resolveSelectStep;
w.pParse = pParse;
@@ -73262,7 +75254,9 @@ SQLITE_PRIVATE void sqlite3ResolveSelectNames(
** SELECT * FROM t1 WHERE (select a from t1);
*/
SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr){
- int op = pExpr->op;
+ int op;
+ pExpr = sqlite3ExprSkipCollate(pExpr);
+ op = pExpr->op;
if( op==TK_SELECT ){
assert( pExpr->flags&EP_xIsSelect );
return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
@@ -73287,66 +75281,89 @@ SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr){
}
/*
-** Set the explicit collating sequence for an expression to the
-** collating sequence supplied in the second argument.
+** Set the collating sequence for expression pExpr to be the collating
+** sequence named by pToken. Return a pointer to a new Expr node that
+** implements the COLLATE operator.
+**
+** If a memory allocation error occurs, that fact is recorded in pParse->db
+** and the pExpr parameter is returned unchanged.
*/
-SQLITE_PRIVATE Expr *sqlite3ExprSetColl(Expr *pExpr, CollSeq *pColl){
- if( pExpr && pColl ){
- pExpr->pColl = pColl;
- pExpr->flags |= EP_ExpCollate;
+SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr *pExpr, Token *pCollName){
+ if( pCollName->n>0 ){
+ Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, 1);
+ if( pNew ){
+ pNew->pLeft = pExpr;
+ pNew->flags |= EP_Collate;
+ pExpr = pNew;
+ }
}
return pExpr;
}
+SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse *pParse, Expr *pExpr, const char *zC){
+ Token s;
+ assert( zC!=0 );
+ s.z = zC;
+ s.n = sqlite3Strlen30(s.z);
+ return sqlite3ExprAddCollateToken(pParse, pExpr, &s);
+}
/*
-** Set the collating sequence for expression pExpr to be the collating
-** sequence named by pToken. Return a pointer to the revised expression.
-** The collating sequence is marked as "explicit" using the EP_ExpCollate
-** flag. An explicit collating sequence will override implicit
-** collating sequences.
+** Skip over any TK_COLLATE and/or TK_AS operators at the root of
+** an expression.
*/
-SQLITE_PRIVATE Expr *sqlite3ExprSetCollByToken(Parse *pParse, Expr *pExpr, Token *pCollName){
- char *zColl = 0; /* Dequoted name of collation sequence */
- CollSeq *pColl;
- sqlite3 *db = pParse->db;
- zColl = sqlite3NameFromToken(db, pCollName);
- pColl = sqlite3LocateCollSeq(pParse, zColl);
- sqlite3ExprSetColl(pExpr, pColl);
- sqlite3DbFree(db, zColl);
+SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr *pExpr){
+ while( pExpr && (pExpr->op==TK_COLLATE || pExpr->op==TK_AS) ){
+ pExpr = pExpr->pLeft;
+ }
return pExpr;
}
/*
-** Return the default collation sequence for the expression pExpr. If
-** there is no default collation type, return 0.
+** Return the collation sequence for the expression pExpr. If
+** there is no defined collating sequence, return NULL.
+**
+** The collating sequence might be determined by a COLLATE operator
+** or by the presence of a column with a defined collating sequence.
+** COLLATE operators take first precedence. Left operands take
+** precedence over right operands.
*/
SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
+ sqlite3 *db = pParse->db;
CollSeq *pColl = 0;
Expr *p = pExpr;
while( p ){
- int op;
- pColl = p->pColl;
- if( pColl ) break;
- op = p->op;
- if( p->pTab!=0 && (
- op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_REGISTER || op==TK_TRIGGER
- )){
+ int op = p->op;
+ if( op==TK_CAST || op==TK_UPLUS ){
+ p = p->pLeft;
+ continue;
+ }
+ assert( op!=TK_REGISTER || p->op2!=TK_COLLATE );
+ if( op==TK_COLLATE ){
+ pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken);
+ break;
+ }
+ if( p->pTab!=0
+ && (op==TK_AGG_COLUMN || op==TK_COLUMN
+ || op==TK_REGISTER || op==TK_TRIGGER)
+ ){
/* op==TK_REGISTER && p->pTab!=0 happens when pExpr was originally
** a TK_COLUMN but was previously evaluated and cached in a register */
- const char *zColl;
int j = p->iColumn;
if( j>=0 ){
- sqlite3 *db = pParse->db;
- zColl = p->pTab->aCol[j].zColl;
+ const char *zColl = p->pTab->aCol[j].zColl;
pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0);
- pExpr->pColl = pColl;
}
break;
}
- if( op!=TK_CAST && op!=TK_UPLUS ){
+ if( p->flags & EP_Collate ){
+ if( ALWAYS(p->pLeft) && (p->pLeft->flags & EP_Collate)!=0 ){
+ p = p->pLeft;
+ }else{
+ p = p->pRight;
+ }
+ }else{
break;
}
- p = p->pLeft;
}
if( sqlite3CheckCollSeq(pParse, pColl) ){
pColl = 0;
@@ -73450,12 +75467,10 @@ SQLITE_PRIVATE CollSeq *sqlite3BinaryCompareCollSeq(
){
CollSeq *pColl;
assert( pLeft );
- if( pLeft->flags & EP_ExpCollate ){
- assert( pLeft->pColl );
- pColl = pLeft->pColl;
- }else if( pRight && pRight->flags & EP_ExpCollate ){
- assert( pRight->pColl );
- pColl = pRight->pColl;
+ if( pLeft->flags & EP_Collate ){
+ pColl = sqlite3ExprCollSeq(pParse, pLeft);
+ }else if( pRight && (pRight->flags & EP_Collate)!=0 ){
+ pColl = sqlite3ExprCollSeq(pParse, pRight);
}else{
pColl = sqlite3ExprCollSeq(pParse, pLeft);
if( !pColl ){
@@ -73685,17 +75700,11 @@ SQLITE_PRIVATE void sqlite3ExprAttachSubtrees(
}else{
if( pRight ){
pRoot->pRight = pRight;
- if( pRight->flags & EP_ExpCollate ){
- pRoot->flags |= EP_ExpCollate;
- pRoot->pColl = pRight->pColl;
- }
+ pRoot->flags |= EP_Collate & pRight->flags;
}
if( pLeft ){
pRoot->pLeft = pLeft;
- if( pLeft->flags & EP_ExpCollate ){
- pRoot->flags |= EP_ExpCollate;
- pRoot->pColl = pLeft->pColl;
- }
+ pRoot->flags |= EP_Collate & pLeft->flags;
}
exprSetHeight(pRoot);
}
@@ -73847,7 +75856,7 @@ SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
*/
ynVar i;
for(i=0; i<pParse->nzVar; i++){
- if( pParse->azVar[i] && memcmp(pParse->azVar[i],z,n+1)==0 ){
+ if( pParse->azVar[i] && strcmp(pParse->azVar[i],z)==0 ){
pExpr->iColumn = x = (ynVar)i+1;
break;
}
@@ -73953,7 +75962,7 @@ static int dupedExprStructSize(Expr *p, int flags){
assert( !ExprHasProperty(p, EP_FromJoin) );
assert( (p->flags2 & EP2_MallocedToken)==0 );
assert( (p->flags2 & EP2_Irreducible)==0 );
- if( p->pLeft || p->pRight || p->pColl || p->x.pList ){
+ if( p->pLeft || p->pRight || p->x.pList ){
nSize = EXPR_REDUCEDSIZE | EP_Reduced;
}else{
nSize = EXPR_TOKENONLYSIZE | EP_TokenOnly;
@@ -74161,6 +76170,7 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
struct SrcList_item *pNewItem = &pNew->a[i];
struct SrcList_item *pOldItem = &p->a[i];
Table *pTab;
+ pNewItem->pSchema = pOldItem->pSchema;
pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase);
pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias);
@@ -74169,6 +76179,7 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
pNewItem->addrFillSub = pOldItem->addrFillSub;
pNewItem->regReturn = pOldItem->regReturn;
pNewItem->isCorrelated = pOldItem->isCorrelated;
+ pNewItem->viaCoroutine = pOldItem->viaCoroutine;
pNewItem->zIndex = sqlite3DbStrDup(db, pOldItem->zIndex);
pNewItem->notIndexed = pOldItem->notIndexed;
pNewItem->pIndex = pOldItem->pIndex;
@@ -74421,6 +76432,7 @@ static int selectNodeIsConstant(Walker *pWalker, Select *NotUsed){
}
static int exprIsConst(Expr *p, int initFlag){
Walker w;
+ memset(&w, 0, sizeof(w));
w.u.i = initFlag;
w.xExprCallback = exprNodeIsConstant;
w.xSelectCallback = selectNodeIsConstant;
@@ -74651,24 +76663,34 @@ SQLITE_PRIVATE int sqlite3CodeOnce(Parse *pParse){
/*
** This function is used by the implementation of the IN (...) operator.
-** It's job is to find or create a b-tree structure that may be used
-** either to test for membership of the (...) set or to iterate through
-** its members, skipping duplicates.
+** The pX parameter is the expression on the RHS of the IN operator, which
+** might be either a list of expressions or a subquery.
+**
+** The job of this routine is to find or create a b-tree object that can
+** be used either to test for membership in the RHS set or to iterate through
+** all members of the RHS set, skipping duplicates.
+**
+** A cursor is opened on the b-tree object that the RHS of the IN operator
+** and pX->iTable is set to the index of that cursor.
**
-** The index of the cursor opened on the b-tree (database table, database index
-** or ephermal table) is stored in pX->iTable before this function returns.
** The returned value of this function indicates the b-tree type, as follows:
**
-** IN_INDEX_ROWID - The cursor was opened on a database table.
-** IN_INDEX_INDEX - The cursor was opened on a database index.
-** IN_INDEX_EPH - The cursor was opened on a specially created and
-** populated epheremal table.
+** IN_INDEX_ROWID - The cursor was opened on a database table.
+** IN_INDEX_INDEX_ASC - The cursor was opened on an ascending index.
+** IN_INDEX_INDEX_DESC - The cursor was opened on a descending index.
+** IN_INDEX_EPH - The cursor was opened on a specially created and
+** populated epheremal table.
**
-** An existing b-tree may only be used if the SELECT is of the simple
-** form:
+** An existing b-tree might be used if the RHS expression pX is a simple
+** subquery such as:
**
** SELECT <column> FROM <table>
**
+** 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
+** existing table.
+**
** If the prNotFound parameter is 0, then the b-tree will be used to iterate
** through the set members, skipping any duplicates. In this case an
** epheremal table must be used unless the selected <column> is guaranteed
@@ -74764,8 +76786,7 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
** comparison is the same as the affinity of the column. If
** it is not, it is not possible to use any index.
*/
- char aff = comparisonAffinity(pX);
- int affinity_ok = (pTab->aCol[iCol].affinity==aff||aff==SQLITE_AFF_NONE);
+ int affinity_ok = sqlite3IndexAffinityOk(pX, pTab->aCol[iCol].affinity);
for(pIdx=pTab->pIndex; pIdx && eType==0 && affinity_ok; pIdx=pIdx->pNext){
if( (pIdx->aiColumn[0]==iCol)
@@ -74781,7 +76802,8 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
sqlite3VdbeAddOp4(v, OP_OpenRead, iTab, pIdx->tnum, iDb,
pKey,P4_KEYINFO_HANDOFF);
VdbeComment((v, "%s", pIdx->zName));
- eType = IN_INDEX_INDEX;
+ assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 );
+ eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0];
sqlite3VdbeJumpHere(v, iAddr);
if( prNotFound && !pTab->aCol[iCol].notNull ){
@@ -74893,6 +76915,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
case TK_IN: {
char affinity; /* Affinity of the LHS of the IN */
KeyInfo keyInfo; /* Keyinfo for the generated table */
+ static u8 sortOrder = 0; /* Fake aSortOrder for keyInfo */
int addr; /* Address of OP_OpenEphemeral instruction */
Expr *pLeft = pExpr->pLeft; /* the LHS of the IN operator */
@@ -74920,6 +76943,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
if( rMayHaveNull==0 ) sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
memset(&keyInfo, 0, sizeof(keyInfo));
keyInfo.nField = 1;
+ keyInfo.aSortOrder = &sortOrder;
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
/* Case 1: expr IN (SELECT ...)
@@ -74960,6 +76984,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
affinity = SQLITE_AFF_NONE;
}
keyInfo.aColl[0] = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
+ keyInfo.aSortOrder = &sortOrder;
/* Loop through each expression in <exprlist>. */
r1 = sqlite3GetTempReg(pParse);
@@ -75286,7 +77311,7 @@ SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int
** for testing only - to verify that SQLite always gets the same answer
** with and without the column cache.
*/
- if( pParse->db->flags & SQLITE_ColumnCache ) return;
+ if( OptimizationDisabled(pParse->db, SQLITE_ColumnCache) ) return;
/* First replace any existing entry.
**
@@ -75483,8 +77508,8 @@ SQLITE_PRIVATE void sqlite3ExprCacheAffinityChange(Parse *pParse, int iStart, in
SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){
int i;
struct yColCache *p;
- if( NEVER(iFrom==iTo) ) return;
- sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg);
+ assert( iFrom>=iTo+nReg || iFrom+nReg<=iTo );
+ sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg-1);
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
int x = p->iReg;
if( x>=iFrom && x<iFrom+nReg ){
@@ -75493,18 +77518,6 @@ SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int n
}
}
-/*
-** Generate code to copy content from registers iFrom...iFrom+nReg-1
-** over to iTo..iTo+nReg-1.
-*/
-SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse *pParse, int iFrom, int iTo, int nReg){
- int i;
- if( NEVER(iFrom==iTo) ) return;
- for(i=0; i<nReg; i++){
- sqlite3VdbeAddOp2(pParse->pVdbe, OP_Copy, iFrom+i, iTo+i);
- }
-}
-
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
/*
** Return true if any register in the range iFrom..iTo (inclusive)
@@ -75976,6 +77989,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
sqlite3ReleaseTempReg(pParse, r4);
break;
}
+ case TK_COLLATE:
case TK_UPLUS: {
inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
break;
@@ -76142,7 +78156,8 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
sqlite3VdbeAddOp4(
v, OP_Halt, SQLITE_OK, OE_Ignore, 0, pExpr->u.zToken,0);
}else{
- sqlite3HaltConstraint(pParse, pExpr->affinity, pExpr->u.zToken, 0);
+ sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_TRIGGER,
+ pExpr->affinity, pExpr->u.zToken, 0);
}
break;
@@ -76345,6 +78360,12 @@ SQLITE_PRIVATE void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){
case TK_ISNULL: zUniOp = "ISNULL"; break;
case TK_NOTNULL: zUniOp = "NOTNULL"; break;
+ case TK_COLLATE: {
+ sqlite3ExplainExpr(pOut, pExpr->pLeft);
+ sqlite3ExplainPrintf(pOut,".COLLATE(%s)",pExpr->u.zToken);
+ break;
+ }
+
case TK_AGG_FUNCTION:
case TK_CONST_FUNC:
case TK_FUNCTION: {
@@ -76482,6 +78503,12 @@ SQLITE_PRIVATE void sqlite3ExplainExprList(Vdbe *pOut, ExprList *pList){
sqlite3ExplainPush(pOut);
sqlite3ExplainExpr(pOut, pList->a[i].pExpr);
sqlite3ExplainPop(pOut);
+ 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);
}
@@ -76563,6 +78590,9 @@ static int evalConstExpr(Walker *pWalker, Expr *pExpr){
case TK_REGISTER: {
return WRC_Prune;
}
+ case TK_COLLATE: {
+ return WRC_Continue;
+ }
case TK_FUNCTION:
case TK_AGG_FUNCTION:
case TK_CONST_FUNC: {
@@ -76584,9 +78614,11 @@ static int evalConstExpr(Walker *pWalker, Expr *pExpr){
}
if( isAppropriateForFactoring(pExpr) ){
int r1 = ++pParse->nMem;
- int r2;
- r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1);
- if( NEVER(r1!=r2) ) sqlite3ReleaseTempReg(pParse, r1);
+ int r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1);
+ /* If r2!=r1, it means that register r1 is never used. That is harmless
+ ** but suboptimal, so we want to know about the situation to fix it.
+ ** Hence the following assert: */
+ assert( r2==r1 );
pExpr->op2 = pExpr->op;
pExpr->op = TK_REGISTER;
pExpr->iTable = r2;
@@ -76614,9 +78646,9 @@ static int evalConstExpr(Walker *pWalker, Expr *pExpr){
SQLITE_PRIVATE void sqlite3ExprCodeConstants(Parse *pParse, Expr *pExpr){
Walker w;
if( pParse->cookieGoto ) return;
- if( (pParse->db->flags & SQLITE_FactorOutConst)!=0 ) return;
+ if( OptimizationDisabled(pParse->db, SQLITE_FactorOutConst) ) return;
+ memset(&w, 0, sizeof(w));
w.xExprCallback = evalConstExpr;
- w.xSelectCallback = 0;
w.pParse = pParse;
sqlite3WalkExpr(&w, pExpr);
}
@@ -76729,7 +78761,7 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int
int r1, r2;
assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 );
- if( NEVER(v==0) ) return; /* Existance of VDBE checked by caller */
+ if( NEVER(v==0) ) return; /* Existence of VDBE checked by caller */
if( NEVER(pExpr==0) ) return; /* No way this can happen */
op = pExpr->op;
switch( op ){
@@ -76849,7 +78881,7 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
int r1, r2;
assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 );
- if( NEVER(v==0) ) return; /* Existance of VDBE checked by caller */
+ if( NEVER(v==0) ) return; /* Existence of VDBE checked by caller */
if( pExpr==0 ) return;
/* The value of pExpr->op and op are related as follows:
@@ -77003,7 +79035,15 @@ SQLITE_PRIVATE int sqlite3ExprCompare(Expr *pA, Expr *pB){
return 2;
}
if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 2;
- if( pA->op!=pB->op ) return 2;
+ if( pA->op!=pB->op ){
+ if( pA->op==TK_COLLATE && sqlite3ExprCompare(pA->pLeft, pB)<2 ){
+ return 1;
+ }
+ if( pB->op==TK_COLLATE && sqlite3ExprCompare(pA, pB->pLeft)<2 ){
+ return 1;
+ }
+ return 2;
+ }
if( sqlite3ExprCompare(pA->pLeft, pB->pLeft) ) return 2;
if( sqlite3ExprCompare(pA->pRight, pB->pRight) ) return 2;
if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList) ) return 2;
@@ -77015,11 +79055,9 @@ SQLITE_PRIVATE int sqlite3ExprCompare(Expr *pA, Expr *pB){
}else if( pA->op!=TK_COLUMN && ALWAYS(pA->op!=TK_AGG_COLUMN) && pA->u.zToken){
if( ExprHasProperty(pB, EP_IntValue) || NEVER(pB->u.zToken==0) ) return 2;
if( strcmp(pA->u.zToken,pB->u.zToken)!=0 ){
- return 2;
+ return pA->op==TK_COLLATE ? 1 : 2;
}
}
- if( (pA->flags & EP_ExpCollate)!=(pB->flags & EP_ExpCollate) ) return 1;
- if( (pA->flags & EP_ExpCollate)!=0 && pA->pColl!=pB->pColl ) return 2;
return 0;
}
@@ -77260,8 +79298,10 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
ExprSetIrreducible(pExpr);
pExpr->iAgg = (i16)i;
pExpr->pAggInfo = pAggInfo;
+ return WRC_Prune;
+ }else{
+ return WRC_Continue;
}
- return WRC_Prune;
}
}
return WRC_Continue;
@@ -77273,9 +79313,10 @@ static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){
}
/*
-** Analyze the given expression looking for aggregate functions and
-** for variables that need to be added to the pParse->aAgg[] array.
-** Make additional entries to the pParse->aAgg[] array as necessary.
+** Analyze the pExpr expression looking for aggregate functions and
+** for variables that need to be added to AggInfo object that pNC->pAggInfo
+** points to. Additional entries are made on the AggInfo object as
+** necessary.
**
** This routine should only be called after the expression has been
** analyzed by sqlite3ResolveExprNames().
@@ -77788,7 +79829,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
assert( pSrc->nSrc==1 );
assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
- pTab = sqlite3LocateTable(pParse, 0, pSrc->a[0].zName, pSrc->a[0].zDatabase);
+ pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
if( !pTab ) goto exit_rename_table;
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
zDb = db->aDb[iDb].zName;
@@ -78038,7 +80079,7 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
** If there is a NOT NULL constraint, then the default value for the
** column must not be NULL.
*/
- if( pCol->isPrimKey ){
+ if( pCol->colFlags & COLFLAG_PRIMKEY ){
sqlite3ErrorMsg(pParse, "Cannot add a PRIMARY KEY column");
return;
}
@@ -78131,7 +80172,7 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
assert( pParse->pNewTable==0 );
assert( sqlite3BtreeHoldsAllMutexes(db) );
if( db->mallocFailed ) goto exit_begin_add_column;
- pTab = sqlite3LocateTable(pParse, 0, pSrc->a[0].zName, pSrc->a[0].zDatabase);
+ pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
if( !pTab ) goto exit_begin_add_column;
#ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -78675,7 +80716,7 @@ static void analyzeOneTable(
/* Do not gather statistics on views or virtual tables */
return;
}
- if( memcmp(pTab->zName, "sqlite_", 7)==0 ){
+ if( sqlite3_strnicmp(pTab->zName, "sqlite_", 7)==0 ){
/* Do not gather statistics on system tables */
return;
}
@@ -79085,7 +81126,7 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
if( pIndex==0 ) break;
pIndex->aiRowEst[i] = v;
if( *z==' ' ) z++;
- if( memcmp(z, "unordered", 10)==0 ){
+ if( strcmp(z, "unordered")==0 ){
pIndex->bUnordered = 1;
break;
}
@@ -79437,7 +81478,7 @@ static void attachFunc(
}
}
- /* Allocate the new entry in the db->aDb[] array and initialise the schema
+ /* Allocate the new entry in the db->aDb[] array and initialize the schema
** hash tables.
*/
if( db->aDb==db->aDbStatic ){
@@ -79454,7 +81495,7 @@ static void attachFunc(
/* Open the database file. If the btree is successfully opened, use
** it to obtain the database schema. At this point the schema may
- ** or may not be initialised.
+ ** or may not be initialized.
*/
flags = db->openFlags;
rc = sqlite3ParseUri(db->pVfs->zName, zFile, &flags, &pVfs, &zPath, &zErr);
@@ -79762,6 +81803,7 @@ SQLITE_PRIVATE int sqlite3FixInit(
assert( db->nDb>iDb );
pFix->pParse = pParse;
pFix->zDb = db->aDb[iDb].zName;
+ pFix->pSchema = db->aDb[iDb].pSchema;
pFix->zType = zType;
pFix->pName = pName;
return 1;
@@ -79792,14 +81834,15 @@ SQLITE_PRIVATE int sqlite3FixSrcList(
if( NEVER(pList==0) ) return 0;
zDb = pFix->zDb;
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
- if( pItem->zDatabase==0 ){
- pItem->zDatabase = sqlite3DbStrDup(pFix->pParse->db, zDb);
- }else if( sqlite3StrICmp(pItem->zDatabase,zDb)!=0 ){
+ if( pItem->zDatabase && sqlite3StrICmp(pItem->zDatabase, zDb) ){
sqlite3ErrorMsg(pFix->pParse,
"%s %T cannot reference objects in database %s",
pFix->zType, pFix->pName, pItem->zDatabase);
return 1;
}
+ sqlite3DbFree(pFix->pParse->db, pItem->zDatabase);
+ pItem->zDatabase = 0;
+ pItem->pSchema = pFix->pSchema;
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1;
if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1;
@@ -80265,6 +82308,7 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
sqlite3 *db;
Vdbe *v;
+ assert( pParse->pToplevel==0 );
db = pParse->db;
if( db->mallocFailed ) return;
if( pParse->nested ) return;
@@ -80458,6 +82502,31 @@ SQLITE_PRIVATE Table *sqlite3LocateTable(
}
/*
+** Locate the table identified by *p.
+**
+** This is a wrapper around sqlite3LocateTable(). The difference between
+** sqlite3LocateTable() and this function is that this function restricts
+** the search to schema (p->pSchema) if it is not NULL. p->pSchema may be
+** non-NULL if it is part of a view or trigger program definition. See
+** sqlite3FixSrcList() for details.
+*/
+SQLITE_PRIVATE Table *sqlite3LocateTableItem(
+ Parse *pParse,
+ int isView,
+ struct SrcList_item *p
+){
+ const char *zDb;
+ assert( p->pSchema==0 || p->zDatabase==0 );
+ if( p->pSchema ){
+ int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema);
+ zDb = pParse->db->aDb[iDb].zName;
+ }else{
+ zDb = p->zDatabase;
+ }
+ return sqlite3LocateTable(pParse, isView, p->zName, zDb);
+}
+
+/*
** Locate the in-memory structure that describes
** a particular index given the name of that index
** and the name of the database that contains the index.
@@ -81307,7 +83376,7 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey(
pTab->tabFlags |= TF_HasPrimaryKey;
if( pList==0 ){
iCol = pTab->nCol - 1;
- pTab->aCol[iCol].isPrimKey = 1;
+ pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY;
}else{
for(i=0; i<pList->nExpr; i++){
for(iCol=0; iCol<pTab->nCol; iCol++){
@@ -81316,7 +83385,7 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey(
}
}
if( iCol<pTab->nCol ){
- pTab->aCol[iCol].isPrimKey = 1;
+ pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY;
}
}
if( pList->nExpr>1 ) iCol = -1;
@@ -81433,10 +83502,7 @@ SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName){
pColl = sqlite3FindCollSeq(db, enc, zName, initbusy);
if( !initbusy && (!pColl || !pColl->xCmp) ){
- pColl = sqlite3GetCollSeq(db, enc, pColl, zName);
- if( !pColl ){
- sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName);
- }
+ pColl = sqlite3GetCollSeq(pParse, enc, pColl, zName);
}
return pColl;
@@ -82135,6 +84201,7 @@ static void destroyTable(Parse *pParse, Table *pTab){
return;
}else{
int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
+ assert( iDb>=0 && iDb<pParse->db->nDb );
destroyRootPage(pParse, iLargest, iDb);
iDestroyed = iLargest;
}
@@ -82214,7 +84281,7 @@ SQLITE_PRIVATE void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, in
/* Drop all SQLITE_MASTER table and index entries that refer to the
** table. The program name loops through the master table and deletes
** every row that refers to a table of the same name as the one being
- ** dropped. Triggers are handled seperately because a trigger can be
+ ** dropped. Triggers are handled separately because a trigger can be
** created in the temp database that refers to a table in another
** database.
*/
@@ -82252,8 +84319,7 @@ SQLITE_PRIVATE void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView,
assert( pParse->nErr==0 );
assert( pName->nSrc==1 );
if( noErr ) db->suppressErr++;
- pTab = sqlite3LocateTable(pParse, isView,
- pName->a[0].zName, pName->a[0].zDatabase);
+ pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]);
if( noErr ) db->suppressErr--;
if( pTab==0 ){
@@ -82507,9 +84573,6 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
int tnum; /* Root page of index */
Vdbe *v; /* Generate code into this virtual machine */
KeyInfo *pKey; /* KeyInfo for index */
-#ifdef SQLITE_OMIT_MERGE_SORT
- int regIdxKey; /* Registers containing the index key */
-#endif
int regRecord; /* Register holding assemblied index record */
sqlite3 *db = pParse->db; /* The database connection */
int iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);
@@ -82537,13 +84600,9 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
(char *)pKey, P4_KEYINFO_HANDOFF);
sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR|((memRootPage>=0)?OPFLAG_P2ISREG:0));
-#ifndef SQLITE_OMIT_MERGE_SORT
/* Open the sorter cursor if we are to use one. */
iSorter = pParse->nTab++;
sqlite3VdbeAddOp4(v, OP_SorterOpen, iSorter, 0, 0, (char*)pKey, P4_KEYINFO);
-#else
- iSorter = iTab;
-#endif
/* Open the table. Loop through all rows of the table, inserting index
** records into the sorter. */
@@ -82551,7 +84610,6 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0);
regRecord = sqlite3GetTempReg(pParse);
-#ifndef SQLITE_OMIT_MERGE_SORT
sqlite3GenerateIndexKey(pParse, pIndex, iTab, regRecord, 1);
sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord);
sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1);
@@ -82562,8 +84620,8 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
sqlite3VdbeAddOp2(v, OP_Goto, 0, j2);
addr2 = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp3(v, OP_SorterCompare, iSorter, j2, regRecord);
- sqlite3HaltConstraint(
- pParse, OE_Abort, "indexed columns are not unique", P4_STATIC
+ sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_UNIQUE,
+ OE_Abort, "indexed columns are not unique", P4_STATIC
);
}else{
addr2 = sqlite3VdbeCurrentAddr(v);
@@ -82571,30 +84629,6 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
sqlite3VdbeAddOp2(v, OP_SorterData, iSorter, regRecord);
sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 1);
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
-#else
- regIdxKey = sqlite3GenerateIndexKey(pParse, pIndex, iTab, regRecord, 1);
- addr2 = addr1 + 1;
- if( pIndex->onError!=OE_None ){
- const int regRowid = regIdxKey + pIndex->nColumn;
- const int j2 = sqlite3VdbeCurrentAddr(v) + 2;
- void * const pRegKey = SQLITE_INT_TO_PTR(regIdxKey);
-
- /* The registers accessed by the OP_IsUnique opcode were allocated
- ** using sqlite3GetTempRange() inside of the sqlite3GenerateIndexKey()
- ** call above. Just before that function was freed they were released
- ** (made available to the compiler for reuse) using
- ** sqlite3ReleaseTempRange(). So in some ways having the OP_IsUnique
- ** opcode use the values stored within seems dangerous. However, since
- ** we can be sure that no other temp registers have been allocated
- ** since sqlite3ReleaseTempRange() was called, it is safe to do so.
- */
- sqlite3VdbeAddOp4(v, OP_IsUnique, iIdx, j2, regRowid, pRegKey, P4_INT32);
- sqlite3HaltConstraint(
- pParse, OE_Abort, "indexed columns are not unique", P4_STATIC);
- }
- sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 0);
- sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
-#endif
sqlite3ReleaseTempReg(pParse, regRecord);
sqlite3VdbeAddOp2(v, OP_SorterNext, iSorter, addr2);
sqlite3VdbeJumpHere(v, addr1);
@@ -82693,9 +84727,9 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
** sqlite3FixSrcList can never fail. */
assert(0);
}
- pTab = sqlite3LocateTable(pParse, 0, pTblName->a[0].zName,
- pTblName->a[0].zDatabase);
- if( !pTab || db->mallocFailed ) goto exit_create_index;
+ pTab = sqlite3LocateTableItem(pParse, 0, &pTblName->a[0]);
+ assert( db->mallocFailed==0 || pTab==0 );
+ if( pTab==0 ) goto exit_create_index;
assert( db->aDb[iDb].pSchema==pTab->pSchema );
}else{
assert( pName==0 );
@@ -82709,7 +84743,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
assert( pTab!=0 );
assert( pParse->nErr==0 );
if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0
- && memcmp(&pTab->zName[7],"altertab_",9)!=0 ){
+ && sqlite3StrNICmp(&pTab->zName[7],"altertab_",9)!=0 ){
sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName);
goto exit_create_index;
}
@@ -82806,12 +84840,8 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
for(i=0; i<pList->nExpr; i++){
Expr *pExpr = pList->a[i].pExpr;
if( pExpr ){
- CollSeq *pColl = pExpr->pColl;
- /* Either pColl!=0 or there was an OOM failure. But if an OOM
- ** failure we have quit before reaching this point. */
- if( ALWAYS(pColl) ){
- nExtra += (1 + sqlite3Strlen30(pColl->zName));
- }
+ assert( pExpr->op==TK_COLLATE );
+ nExtra += (1 + sqlite3Strlen30(pExpr->u.zToken));
}
}
@@ -82884,14 +84914,10 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
goto exit_create_index;
}
pIndex->aiColumn[i] = j;
- /* Justification of the ALWAYS(pListItem->pExpr->pColl): Because of
- ** the way the "idxlist" non-terminal is constructed by the parser,
- ** if pListItem->pExpr is not null then either pListItem->pExpr->pColl
- ** must exist or else there must have been an OOM error. But if there
- ** was an OOM error, we would never reach this point. */
- if( pListItem->pExpr && ALWAYS(pListItem->pExpr->pColl) ){
+ if( pListItem->pExpr ){
int nColl;
- zColl = pListItem->pExpr->pColl->zName;
+ assert( pListItem->pExpr->op==TK_COLLATE );
+ zColl = pListItem->pExpr->u.zToken;
nColl = sqlite3Strlen30(zColl) + 1;
assert( nExtra>=nColl );
memcpy(zExtra, zColl, nColl);
@@ -82900,9 +84926,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
nExtra -= nColl;
}else{
zColl = pTab->aCol[j].zColl;
- if( !zColl ){
- zColl = "BINARY";
- }
+ if( !zColl ) zColl = "BINARY";
}
if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl) ){
goto exit_create_index;
@@ -82958,7 +84982,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
** However the ON CONFLICT clauses are different. If both this
** constraint and the previous equivalent constraint have explicit
** ON CONFLICT clauses this is an error. Otherwise, use the
- ** explicitly specified behaviour for the index.
+ ** explicitly specified behavior for the index.
*/
if( !(pIdx->onError==OE_Default || pIndex->onError==OE_Default) ){
sqlite3ErrorMsg(pParse,
@@ -83705,6 +85729,15 @@ SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *pParse){
SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
Parse *pToplevel = sqlite3ParseToplevel(pParse);
+#ifndef SQLITE_OMIT_TRIGGER
+ if( pToplevel!=pParse ){
+ /* This branch is taken if a trigger is currently being coded. In this
+ ** case, set cookieGoto to a non-zero value to show that this function
+ ** has been called. This is used by the sqlite3ExprCodeConstants()
+ ** function. */
+ pParse->cookieGoto = -1;
+ }
+#endif
if( pToplevel->cookieGoto==0 ){
Vdbe *v = sqlite3GetVdbe(pToplevel);
if( v==0 ) return; /* This only happens if there was a prior error */
@@ -83802,12 +85835,19 @@ SQLITE_PRIVATE void sqlite3MayAbort(Parse *pParse){
** error. The onError parameter determines which (if any) of the statement
** and/or current transaction is rolled back.
*/
-SQLITE_PRIVATE void sqlite3HaltConstraint(Parse *pParse, int onError, char *p4, int p4type){
+SQLITE_PRIVATE void sqlite3HaltConstraint(
+ Parse *pParse, /* Parsing context */
+ int errCode, /* extended error code */
+ int onError, /* Constraint type */
+ char *p4, /* Error message */
+ int p4type /* P4_STATIC or P4_TRANSIENT */
+){
Vdbe *v = sqlite3GetVdbe(pParse);
+ assert( (errCode&0xff)==SQLITE_CONSTRAINT );
if( onError==OE_Abort ){
sqlite3MayAbort(pParse);
}
- sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0, p4, p4type);
+ sqlite3VdbeAddOp4(v, OP_Halt, errCode, onError, 0, p4, p4type);
}
/*
@@ -84054,17 +86094,18 @@ static int synthCollSeq(sqlite3 *db, CollSeq *pColl){
**
** The return value is either the collation sequence to be used in database
** db for collation type name zName, length nName, or NULL, if no collation
-** sequence can be found.
+** sequence can be found. If no collation is found, leave an error message.
**
** See also: sqlite3LocateCollSeq(), sqlite3FindCollSeq()
*/
SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(
- sqlite3* db, /* The database connection */
+ Parse *pParse, /* Parsing context */
u8 enc, /* The desired encoding for the collating sequence */
CollSeq *pColl, /* Collating sequence with native encoding, or NULL */
const char *zName /* Collating sequence name */
){
CollSeq *p;
+ sqlite3 *db = pParse->db;
p = pColl;
if( !p ){
@@ -84081,6 +86122,9 @@ SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(
p = 0;
}
assert( !p || p->xCmp );
+ if( p==0 ){
+ sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName);
+ }
return p;
}
@@ -84099,10 +86143,8 @@ SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){
if( pColl ){
const char *zName = pColl->zName;
sqlite3 *db = pParse->db;
- CollSeq *p = sqlite3GetCollSeq(db, ENC(db), pColl, zName);
+ CollSeq *p = sqlite3GetCollSeq(pParse, ENC(db), pColl, zName);
if( !p ){
- sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName);
- pParse->nErr++;
return SQLITE_ERROR;
}
assert( p==pColl );
@@ -84489,7 +86531,7 @@ SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
struct SrcList_item *pItem = pSrc->a;
Table *pTab;
assert( pItem && pSrc->nSrc==1 );
- pTab = sqlite3LocateTable(pParse, 0, pItem->zName, pItem->zDatabase);
+ pTab = sqlite3LocateTableItem(pParse, 0, pItem);
sqlite3DeleteTable(pParse->db, pItem->pTab);
pItem->pTab = pTab;
if( pTab ){
@@ -84550,29 +86592,28 @@ SQLITE_PRIVATE void sqlite3MaterializeView(
int iCur /* Cursor number for ephemerial table */
){
SelectDest dest;
- Select *pDup;
+ Select *pSel;
+ SrcList *pFrom;
sqlite3 *db = pParse->db;
+ int iDb = sqlite3SchemaToIndex(db, pView->pSchema);
- pDup = sqlite3SelectDup(db, pView->pSelect, 0);
- if( pWhere ){
- SrcList *pFrom;
-
- pWhere = sqlite3ExprDup(db, pWhere, 0);
- pFrom = sqlite3SrcListAppend(db, 0, 0, 0);
- if( pFrom ){
- assert( pFrom->nSrc==1 );
- pFrom->a[0].zAlias = sqlite3DbStrDup(db, pView->zName);
- pFrom->a[0].pSelect = pDup;
- assert( pFrom->a[0].pOn==0 );
- assert( pFrom->a[0].pUsing==0 );
- }else{
- sqlite3SelectDelete(db, pDup);
- }
- pDup = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0, 0, 0, 0);
+ pWhere = sqlite3ExprDup(db, pWhere, 0);
+ pFrom = sqlite3SrcListAppend(db, 0, 0, 0);
+
+ if( pFrom ){
+ assert( pFrom->nSrc==1 );
+ pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName);
+ pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zName);
+ assert( pFrom->a[0].pOn==0 );
+ assert( pFrom->a[0].pUsing==0 );
}
+
+ pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0, 0, 0, 0);
+ if( pSel ) pSel->selFlags |= SF_Materialize;
+
sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur);
- sqlite3Select(pParse, pDup, &dest);
- sqlite3SelectDelete(db, pDup);
+ sqlite3Select(pParse, pSel, &dest);
+ sqlite3SelectDelete(db, pSel);
}
#endif /* !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) */
@@ -85095,7 +87136,9 @@ SQLITE_PRIVATE int sqlite3GenerateIndexKey(
}
if( doMakeRec ){
const char *zAff;
- if( pTab->pSelect || (pParse->db->flags & SQLITE_IdxRealAsInt)!=0 ){
+ if( pTab->pSelect
+ || OptimizationDisabled(pParse->db, SQLITE_IdxRealAsInt)
+ ){
zAff = 0;
}else{
zAff = sqlite3IndexAffinityStr(v, pIdx);
@@ -85278,6 +87321,56 @@ static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
}
/*
+** Implementation of the instr() function.
+**
+** instr(haystack,needle) finds the first occurrence of needle
+** in haystack and returns the number of previous characters plus 1,
+** or 0 if needle does not occur within haystack.
+**
+** If both haystack and needle are BLOBs, then the result is one more than
+** the number of bytes in haystack prior to the first occurrence of needle,
+** or 0 if needle never occurs in haystack.
+*/
+static void instrFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const unsigned char *zHaystack;
+ const unsigned char *zNeedle;
+ int nHaystack;
+ int nNeedle;
+ int typeHaystack, typeNeedle;
+ int N = 1;
+ int isText;
+
+ UNUSED_PARAMETER(argc);
+ typeHaystack = sqlite3_value_type(argv[0]);
+ typeNeedle = sqlite3_value_type(argv[1]);
+ if( typeHaystack==SQLITE_NULL || typeNeedle==SQLITE_NULL ) return;
+ nHaystack = sqlite3_value_bytes(argv[0]);
+ nNeedle = sqlite3_value_bytes(argv[1]);
+ if( typeHaystack==SQLITE_BLOB && typeNeedle==SQLITE_BLOB ){
+ zHaystack = sqlite3_value_blob(argv[0]);
+ zNeedle = sqlite3_value_blob(argv[1]);
+ isText = 0;
+ }else{
+ zHaystack = sqlite3_value_text(argv[0]);
+ zNeedle = sqlite3_value_text(argv[1]);
+ isText = 1;
+ }
+ while( nNeedle<=nHaystack && memcmp(zHaystack, zNeedle, nNeedle)!=0 ){
+ N++;
+ do{
+ nHaystack--;
+ zHaystack++;
+ }while( isText && (zHaystack[0]&0xc0)==0x80 );
+ }
+ if( nNeedle>nHaystack ) N = 0;
+ sqlite3_result_int(context, N);
+}
+
+/*
** Implementation of the substr() function.
**
** substr(x,p1,p2) returns p2 characters of x[] beginning with p1.
@@ -85476,33 +87569,14 @@ static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
}
}
-
-#if 0 /* This function is never used. */
-/*
-** The COALESCE() and IFNULL() functions used to be implemented as shown
-** here. But now they are implemented as VDBE code so that unused arguments
-** do not have to be computed. This legacy implementation is retained as
-** comment.
-*/
/*
-** Implementation of the IFNULL(), NVL(), and COALESCE() functions.
-** All three do the same thing. They return the first non-NULL
-** argument.
+** The COALESCE() and IFNULL() functions are implemented as VDBE code so
+** that unused argument values do not have to be computed. However, we
+** still need some kind of function implementation for this routines in
+** the function table. That function implementation will never be called
+** so it doesn't matter what the implementation is. We might as well use
+** the "version()" function as a substitute.
*/
-static void ifnullFunc(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- int i;
- for(i=0; i<argc; i++){
- if( SQLITE_NULL!=sqlite3_value_type(argv[i]) ){
- sqlite3_result_value(context, argv[i]);
- break;
- }
- }
-}
-#endif /* NOT USED */
#define ifnullFunc versionFunc /* Substitute function - never called */
/*
@@ -85621,7 +87695,7 @@ struct compareInfo {
** whereas only characters less than 0x80 do in ASCII.
*/
#if defined(SQLITE_EBCDIC)
-# define sqlite3Utf8Read(A,C) (*(A++))
+# define sqlite3Utf8Read(A) (*((*A)++))
# define GlogUpperToLower(A) A = sqlite3UpperToLower[A]
#else
# define GlogUpperToLower(A) if( !((A)&~0x7f) ){ A = sqlite3UpperToLower[A]; }
@@ -85678,18 +87752,18 @@ static int patternCompare(
u8 noCase = pInfo->noCase;
int prevEscape = 0; /* True if the previous character was 'escape' */
- while( (c = sqlite3Utf8Read(zPattern,&zPattern))!=0 ){
- if( !prevEscape && c==matchAll ){
- while( (c=sqlite3Utf8Read(zPattern,&zPattern)) == matchAll
+ while( (c = sqlite3Utf8Read(&zPattern))!=0 ){
+ if( c==matchAll && !prevEscape ){
+ while( (c=sqlite3Utf8Read(&zPattern)) == matchAll
|| c == matchOne ){
- if( c==matchOne && sqlite3Utf8Read(zString, &zString)==0 ){
+ if( c==matchOne && sqlite3Utf8Read(&zString)==0 ){
return 0;
}
}
if( c==0 ){
return 1;
}else if( c==esc ){
- c = sqlite3Utf8Read(zPattern, &zPattern);
+ c = sqlite3Utf8Read(&zPattern);
if( c==0 ){
return 0;
}
@@ -85701,25 +87775,25 @@ static int patternCompare(
}
return *zString!=0;
}
- while( (c2 = sqlite3Utf8Read(zString,&zString))!=0 ){
+ while( (c2 = sqlite3Utf8Read(&zString))!=0 ){
if( noCase ){
GlogUpperToLower(c2);
GlogUpperToLower(c);
while( c2 != 0 && c2 != c ){
- c2 = sqlite3Utf8Read(zString, &zString);
+ c2 = sqlite3Utf8Read(&zString);
GlogUpperToLower(c2);
}
}else{
while( c2 != 0 && c2 != c ){
- c2 = sqlite3Utf8Read(zString, &zString);
+ c2 = sqlite3Utf8Read(&zString);
}
}
if( c2==0 ) return 0;
if( patternCompare(zPattern,zString,pInfo,esc) ) return 1;
}
return 0;
- }else if( !prevEscape && c==matchOne ){
- if( sqlite3Utf8Read(zString, &zString)==0 ){
+ }else if( c==matchOne && !prevEscape ){
+ if( sqlite3Utf8Read(&zString)==0 ){
return 0;
}
}else if( c==matchSet ){
@@ -85727,20 +87801,20 @@ static int patternCompare(
assert( esc==0 ); /* This only occurs for GLOB, not LIKE */
seen = 0;
invert = 0;
- c = sqlite3Utf8Read(zString, &zString);
+ c = sqlite3Utf8Read(&zString);
if( c==0 ) return 0;
- c2 = sqlite3Utf8Read(zPattern, &zPattern);
+ c2 = sqlite3Utf8Read(&zPattern);
if( c2=='^' ){
invert = 1;
- c2 = sqlite3Utf8Read(zPattern, &zPattern);
+ c2 = sqlite3Utf8Read(&zPattern);
}
if( c2==']' ){
if( c==']' ) seen = 1;
- c2 = sqlite3Utf8Read(zPattern, &zPattern);
+ c2 = sqlite3Utf8Read(&zPattern);
}
while( c2 && c2!=']' ){
if( c2=='-' && zPattern[0]!=']' && zPattern[0]!=0 && prior_c>0 ){
- c2 = sqlite3Utf8Read(zPattern, &zPattern);
+ c2 = sqlite3Utf8Read(&zPattern);
if( c>=prior_c && c<=c2 ) seen = 1;
prior_c = 0;
}else{
@@ -85749,7 +87823,7 @@ static int patternCompare(
}
prior_c = c2;
}
- c2 = sqlite3Utf8Read(zPattern, &zPattern);
+ c2 = sqlite3Utf8Read(&zPattern);
}
if( c2==0 || (seen ^ invert)==0 ){
return 0;
@@ -85757,7 +87831,7 @@ static int patternCompare(
}else if( esc==c && !prevEscape ){
prevEscape = 1;
}else{
- c2 = sqlite3Utf8Read(zString, &zString);
+ c2 = sqlite3Utf8Read(&zString);
if( noCase ){
GlogUpperToLower(c);
GlogUpperToLower(c2);
@@ -85772,6 +87846,13 @@ static int patternCompare(
}
/*
+** The sqlite3_strglob() interface.
+*/
+SQLITE_API int sqlite3_strglob(const char *zGlobPattern, const char *zString){
+ return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, 0)==0;
+}
+
+/*
** Count the number of times that the LIKE operator (or GLOB which is
** just a variation of LIKE) gets called. This is used for testing
** only.
@@ -85829,7 +87910,7 @@ static void likeFunc(
"ESCAPE expression must be a single character", -1);
return;
}
- escape = sqlite3Utf8Read(zEsc, &zEsc);
+ escape = sqlite3Utf8Read(&zEsc);
}
if( zA && zB ){
struct compareInfo *pInfo = sqlite3_user_data(context);
@@ -86041,6 +88122,62 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
}
/*
+** The unicode() function. Return the integer unicode code-point value
+** for the first character of the input string.
+*/
+static void unicodeFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const unsigned char *z = sqlite3_value_text(argv[0]);
+ (void)argc;
+ if( z && z[0] ) sqlite3_result_int(context, sqlite3Utf8Read(&z));
+}
+
+/*
+** The char() function takes zero or more arguments, each of which is
+** an integer. It constructs a string where each character of the string
+** is the unicode character for the corresponding integer argument.
+*/
+static void charFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ unsigned char *z, *zOut;
+ int i;
+ zOut = z = sqlite3_malloc( argc*4 );
+ if( z==0 ){
+ sqlite3_result_error_nomem(context);
+ return;
+ }
+ for(i=0; i<argc; i++){
+ sqlite3_int64 x;
+ unsigned c;
+ x = sqlite3_value_int64(argv[i]);
+ if( x<0 || x>0x10ffff ) x = 0xfffd;
+ c = (unsigned)(x & 0x1fffff);
+ if( c<0x00080 ){
+ *zOut++ = (u8)(c&0xFF);
+ }else if( c<0x00800 ){
+ *zOut++ = 0xC0 + (u8)((c>>6)&0x1F);
+ *zOut++ = 0x80 + (u8)(c & 0x3F);
+ }else if( c<0x10000 ){
+ *zOut++ = 0xE0 + (u8)((c>>12)&0x0F);
+ *zOut++ = 0x80 + (u8)((c>>6) & 0x3F);
+ *zOut++ = 0x80 + (u8)(c & 0x3F);
+ }else{
+ *zOut++ = 0xF0 + (u8)((c>>18) & 0x07);
+ *zOut++ = 0x80 + (u8)((c>>12) & 0x3F);
+ *zOut++ = 0x80 + (u8)((c>>6) & 0x3F);
+ *zOut++ = 0x80 + (u8)(c & 0x3F);
+ } \
+ }
+ sqlite3_result_text(context, (char*)z, (int)(zOut-z), sqlite3_free);
+}
+
+/*
** The hex() function. Interpret the argument as a blob. Return
** a hexadecimal rendering as text.
*/
@@ -86664,8 +88801,11 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
AGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize ),
FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF),
FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH),
+ FUNCTION(instr, 2, 0, 0, instrFunc ),
FUNCTION(substr, 2, 0, 0, substrFunc ),
FUNCTION(substr, 3, 0, 0, substrFunc ),
+ FUNCTION(unicode, 1, 0, 0, unicodeFunc ),
+ FUNCTION(char, -1, 0, 0, charFunc ),
FUNCTION(abs, 1, 0, 0, absFunc ),
#ifndef SQLITE_OMIT_FLOATING_POINT
FUNCTION(round, 1, 0, 0, roundFunc ),
@@ -86757,8 +88897,9 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
** --------------------------
**
** Foreign keys in SQLite come in two flavours: deferred and immediate.
-** If an immediate foreign key constraint is violated, SQLITE_CONSTRAINT
-** is returned and the current statement transaction rolled back. If a
+** If an immediate foreign key constraint is violated,
+** SQLITE_CONSTRAINT_FOREIGNKEY is returned and the current
+** statement transaction rolled back. If a
** deferred foreign key constraint is violated, no action is taken
** immediately. However if the application attempts to commit the
** transaction before fixing the constraint violation, the attempt fails.
@@ -86822,7 +88963,8 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
** Immediate constraints are usually handled similarly. The only difference
** is that the counter used is stored as part of each individual statement
** object (struct Vdbe). If, after the statement has run, its immediate
-** constraint counter is greater than zero, it returns SQLITE_CONSTRAINT
+** constraint counter is greater than zero,
+** it returns SQLITE_CONSTRAINT_FOREIGNKEY
** and the statement transaction is rolled back. An exception is an INSERT
** statement that inserts a single row only (no triggers). In this case,
** instead of using a counter, an exception is thrown immediately if the
@@ -86878,7 +89020,7 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
** A foreign key constraint requires that the key columns in the parent
** table are collectively subject to a UNIQUE or PRIMARY KEY constraint.
** Given that pParent is the parent table for foreign key constraint pFKey,
-** search the schema a unique index on the parent key columns.
+** search the schema for a unique index on the parent key columns.
**
** If successful, zero is returned. If the parent key is an INTEGER PRIMARY
** KEY column, then output variable *ppIdx is set to NULL. Otherwise, *ppIdx
@@ -86914,7 +89056,7 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
** into pParse. If an OOM error occurs, non-zero is returned and the
** pParse->db->mallocFailed flag is set.
*/
-static int locateFkeyIndex(
+SQLITE_PRIVATE int sqlite3FkLocateIndex(
Parse *pParse, /* Parse context to store any error in */
Table *pParent, /* Parent table of FK constraint pFKey */
FKey *pFKey, /* Foreign key to find index for */
@@ -87011,7 +89153,9 @@ static int locateFkeyIndex(
if( !pIdx ){
if( !pParse->disableTriggers ){
- sqlite3ErrorMsg(pParse, "foreign key mismatch");
+ sqlite3ErrorMsg(pParse,
+ "foreign key mismatch - \"%w\" referencing \"%w\"",
+ pFKey->pFrom->zName, pFKey->zTo);
}
sqlite3DbFree(pParse->db, aiCol);
return 1;
@@ -87160,8 +89304,8 @@ static void fkLookupParent(
** incrementing a counter. This is necessary as the VM code is being
** generated for will not open a statement transaction. */
assert( nIncr==1 );
- sqlite3HaltConstraint(
- pParse, OE_Abort, "foreign key constraint failed", P4_STATIC
+ sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_FOREIGNKEY,
+ OE_Abort, "foreign key constraint failed", P4_STATIC
);
}else{
if( nIncr>0 && pFKey->isDeferred==0 ){
@@ -87247,12 +89391,15 @@ static void fkScanChildren(
** expression to the parent key column defaults. */
if( pIdx ){
Column *pCol;
+ const char *zColl;
iCol = pIdx->aiColumn[i];
pCol = &pTab->aCol[iCol];
if( pTab->iPKey==iCol ) iCol = -1;
pLeft->iTable = regData+iCol+1;
pLeft->affinity = pCol->affinity;
- pLeft->pColl = sqlite3LocateCollSeq(pParse, pCol->zColl);
+ zColl = pCol->zColl;
+ if( zColl==0 ) zColl = db->pDfltColl->zName;
+ pLeft = sqlite3ExprAddCollateString(pParse, pLeft, zColl);
}else{
pLeft->iTable = regData;
pLeft->affinity = SQLITE_AFF_INTEGER;
@@ -87398,8 +89545,8 @@ SQLITE_PRIVATE void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTa
** any modifications to the schema are made. This is because statement
** transactions are not able to rollback schema changes. */
sqlite3VdbeAddOp2(v, OP_FkIfZero, 0, sqlite3VdbeCurrentAddr(v)+2);
- sqlite3HaltConstraint(
- pParse, OE_Abort, "foreign key constraint failed", P4_STATIC
+ sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_FOREIGNKEY,
+ OE_Abort, "foreign key constraint failed", P4_STATIC
);
if( iSkip ){
@@ -87469,7 +89616,7 @@ SQLITE_PRIVATE void sqlite3FkCheck(
}else{
pTo = sqlite3LocateTable(pParse, 0, pFKey->zTo, zDb);
}
- if( !pTo || locateFkeyIndex(pParse, pTo, pFKey, &pIdx, &aiFree) ){
+ if( !pTo || sqlite3FkLocateIndex(pParse, pTo, pFKey, &pIdx, &aiFree) ){
assert( isIgnoreErrors==0 || (regOld!=0 && regNew==0) );
if( !isIgnoreErrors || db->mallocFailed ) return;
if( pTo==0 ){
@@ -87549,7 +89696,7 @@ SQLITE_PRIVATE void sqlite3FkCheck(
continue;
}
- if( locateFkeyIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ){
+ if( sqlite3FkLocateIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ){
if( !isIgnoreErrors || db->mallocFailed ) return;
continue;
}
@@ -87604,7 +89751,7 @@ SQLITE_PRIVATE u32 sqlite3FkOldmask(
}
for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){
Index *pIdx = 0;
- locateFkeyIndex(pParse, pTab, p, &pIdx, 0);
+ sqlite3FkLocateIndex(pParse, pTab, p, &pIdx, 0);
if( pIdx ){
for(i=0; i<pIdx->nColumn; i++) mask |= COLUMN_MASK(pIdx->aiColumn[i]);
}
@@ -87661,7 +89808,8 @@ SQLITE_PRIVATE int sqlite3FkRequired(
int iKey;
for(iKey=0; iKey<pTab->nCol; iKey++){
Column *pCol = &pTab->aCol[iKey];
- if( (zKey ? !sqlite3StrICmp(pCol->zName, zKey) : pCol->isPrimKey) ){
+ if( (zKey ? !sqlite3StrICmp(pCol->zName, zKey)
+ : (pCol->colFlags & COLFLAG_PRIMKEY)!=0) ){
if( aChange[iKey]>=0 ) return 1;
if( iKey==pTab->iPKey && chngRowid ) return 1;
}
@@ -87729,7 +89877,7 @@ static Trigger *fkActionTrigger(
int i; /* Iterator variable */
Expr *pWhen = 0; /* WHEN clause for the trigger */
- if( locateFkeyIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ) return 0;
+ if( sqlite3FkLocateIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ) return 0;
assert( aiCol || pFKey->nCol==1 );
for(i=0; i<pFKey->nCol; i++){
@@ -87982,7 +90130,7 @@ SQLITE_PRIVATE void sqlite3OpenTable(
int opcode /* OP_OpenRead or OP_OpenWrite */
){
Vdbe *v;
- if( IsVirtual(pTab) ) return;
+ assert( !IsVirtual(pTab) );
v = sqlite3GetVdbe(p);
assert( opcode==OP_OpenWrite || opcode==OP_OpenRead );
sqlite3TableLock(p, iDb, pTab->tnum, (opcode==OP_OpenWrite)?1:0, pTab->zName);
@@ -88277,6 +90425,97 @@ SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse){
#endif /* SQLITE_OMIT_AUTOINCREMENT */
+/*
+** Generate code for a co-routine that will evaluate a subquery one
+** row at a time.
+**
+** The pSelect parameter is the subquery that the co-routine will evaluation.
+** Information about the location of co-routine and the registers it will use
+** is returned by filling in the pDest object.
+**
+** Registers are allocated as follows:
+**
+** pDest->iSDParm The register holding the next entry-point of the
+** co-routine. Run the co-routine to its next breakpoint
+** by calling "OP_Yield $X" where $X is pDest->iSDParm.
+**
+** pDest->iSDParm+1 The register holding the "completed" flag for the
+** co-routine. This register is 0 if the previous Yield
+** generated a new result row, or 1 if the subquery
+** has completed. If the Yield is called again
+** after this register becomes 1, then the VDBE will
+** halt with an SQLITE_INTERNAL error.
+**
+** pDest->iSdst First result register.
+**
+** pDest->nSdst Number of result registers.
+**
+** This routine handles all of the register allocation and fills in the
+** pDest structure appropriately.
+**
+** Here is a schematic of the generated code assuming that X is the
+** co-routine entry-point register reg[pDest->iSDParm], that EOF is the
+** completed flag reg[pDest->iSDParm+1], and R and S are the range of
+** registers that hold the result set, reg[pDest->iSdst] through
+** reg[pDest->iSdst+pDest->nSdst-1]:
+**
+** X <- A
+** EOF <- 0
+** goto B
+** A: setup for the SELECT
+** loop rows in the SELECT
+** load results into registers R..S
+** yield X
+** end loop
+** cleanup after the SELECT
+** EOF <- 1
+** yield X
+** halt-error
+** B:
+**
+** To use this subroutine, the caller generates code as follows:
+**
+** [ Co-routine generated by this subroutine, shown above ]
+** S: yield X
+** if EOF goto E
+** if skip this row, goto C
+** if terminate loop, goto E
+** deal with this row
+** C: goto S
+** E:
+*/
+SQLITE_PRIVATE int sqlite3CodeCoroutine(Parse *pParse, Select *pSelect, SelectDest *pDest){
+ int regYield; /* Register holding co-routine entry-point */
+ int regEof; /* Register holding co-routine completion flag */
+ int addrTop; /* Top of the co-routine */
+ int j1; /* Jump instruction */
+ int rc; /* Result code */
+ Vdbe *v; /* VDBE under construction */
+
+ regYield = ++pParse->nMem;
+ regEof = ++pParse->nMem;
+ v = sqlite3GetVdbe(pParse);
+ addrTop = sqlite3VdbeCurrentAddr(v);
+ sqlite3VdbeAddOp2(v, OP_Integer, addrTop+2, regYield); /* X <- A */
+ VdbeComment((v, "Co-routine entry point"));
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, regEof); /* EOF <- 0 */
+ VdbeComment((v, "Co-routine completion flag"));
+ sqlite3SelectDestInit(pDest, SRT_Coroutine, regYield);
+ j1 = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
+ rc = sqlite3Select(pParse, pSelect, pDest);
+ assert( pParse->nErr==0 || rc );
+ if( pParse->db->mallocFailed && rc==SQLITE_OK ) rc = SQLITE_NOMEM;
+ if( rc ) return rc;
+ sqlite3VdbeAddOp2(v, OP_Integer, 1, regEof); /* EOF <- 1 */
+ sqlite3VdbeAddOp1(v, OP_Yield, regYield); /* yield X */
+ sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_INTERNAL, OE_Abort);
+ VdbeComment((v, "End of coroutine"));
+ sqlite3VdbeJumpHere(v, j1); /* label B: */
+ return rc;
+}
+
+
+
/* Forward declaration */
static int xferOptimization(
Parse *pParse, /* Parser context */
@@ -88525,51 +90764,12 @@ 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 code to implement that SELECT
- ** as a co-routine. The code is common to both the 3rd and 4th
- ** templates:
- **
- ** EOF <- 0
- ** X <- A
- ** goto B
- ** A: setup for the SELECT
- ** loop over the tables in the SELECT
- ** load value into register R..R+n
- ** yield X
- ** end loop
- ** cleanup after the SELECT
- ** EOF <- 1
- ** yield X
- ** halt-error
- **
- ** On each invocation of the co-routine, it puts a single row of the
- ** SELECT result into registers dest.iMem...dest.iMem+dest.nMem-1.
- ** (These output registers are allocated by sqlite3Select().) When
- ** the SELECT completes, it sets the EOF flag stored in regEof.
- */
- int rc, j1;
-
- regEof = ++pParse->nMem;
- sqlite3VdbeAddOp2(v, OP_Integer, 0, regEof); /* EOF <- 0 */
- VdbeComment((v, "SELECT eof flag"));
- sqlite3SelectDestInit(&dest, SRT_Coroutine, ++pParse->nMem);
- addrSelect = sqlite3VdbeCurrentAddr(v)+2;
- sqlite3VdbeAddOp2(v, OP_Integer, addrSelect-1, dest.iSDParm);
- j1 = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
- VdbeComment((v, "Jump over SELECT coroutine"));
-
- /* Resolve the expressions in the SELECT statement and execute it. */
- rc = sqlite3Select(pParse, pSelect, &dest);
- assert( pParse->nErr==0 || rc );
- if( rc || NEVER(pParse->nErr) || db->mallocFailed ){
- goto insert_cleanup;
- }
- sqlite3VdbeAddOp2(v, OP_Integer, 1, regEof); /* EOF <- 1 */
- sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm); /* yield X */
- sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_INTERNAL, OE_Abort);
- VdbeComment((v, "End of SELECT coroutine"));
- sqlite3VdbeJumpHere(v, j1); /* label B: */
+ /* Data is coming from a SELECT. Generate a co-routine to run that
+ ** SELECT. */
+ int rc = sqlite3CodeCoroutine(pParse, pSelect, &dest);
+ if( rc ) goto insert_cleanup;
+ regEof = dest.iSDParm + 1;
regFromSelect = dest.iSdst;
assert( pSelect->pEList );
nColumn = pSelect->pEList->nExpr;
@@ -89150,7 +91350,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
case OE_Fail: {
char *zMsg;
sqlite3VdbeAddOp3(v, OP_HaltIfNull,
- SQLITE_CONSTRAINT, onError, regData+i);
+ SQLITE_CONSTRAINT_NOTNULL, onError, regData+i);
zMsg = sqlite3MPrintf(db, "%s.%s may not be NULL",
pTab->zName, pTab->aCol[i].zName);
sqlite3VdbeChangeP4(v, -1, zMsg, P4_DYNAMIC);
@@ -89190,7 +91390,8 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
}else{
zConsName = 0;
}
- sqlite3HaltConstraint(pParse, onError, zConsName, P4_DYNAMIC);
+ sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_CHECK,
+ onError, zConsName, P4_DYNAMIC);
}
sqlite3VdbeResolveLabel(v, allOk);
}
@@ -89221,8 +91422,8 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
case OE_Rollback:
case OE_Abort:
case OE_Fail: {
- sqlite3HaltConstraint(
- pParse, onError, "PRIMARY KEY must be unique", P4_STATIC);
+ sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_PRIMARYKEY,
+ onError, "PRIMARY KEY must be unique", P4_STATIC);
break;
}
case OE_Replace: {
@@ -89349,7 +91550,8 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
sqlite3StrAccumAppend(&errMsg,
pIdx->nColumn>1 ? " are not unique" : " is not unique", -1);
zErr = sqlite3StrAccumFinish(&errMsg);
- sqlite3HaltConstraint(pParse, onError, zErr, 0);
+ sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_UNIQUE,
+ onError, zErr, 0);
sqlite3DbFree(errMsg.db, zErr);
break;
}
@@ -89648,7 +91850,7 @@ static int xferOptimization(
** we have to check the semantics.
*/
pItem = pSelect->pSrc->a;
- pSrc = sqlite3LocateTable(pParse, 0, pItem->zName, pItem->zDatabase);
+ pSrc = sqlite3LocateTableItem(pParse, 0, pItem);
if( pSrc==0 ){
return 0; /* FROM clause does not contain a real table */
}
@@ -89757,8 +91959,8 @@ static int xferOptimization(
if( pDest->iPKey>=0 ){
addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid);
- sqlite3HaltConstraint(
- pParse, onError, "PRIMARY KEY must be unique", P4_STATIC);
+ sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_PRIMARYKEY,
+ onError, "PRIMARY KEY must be unique", P4_STATIC);
sqlite3VdbeJumpHere(v, addr2);
autoIncStep(pParse, regAutoinc, regRowid);
}else if( pDest->pIndex==0 ){
@@ -89850,7 +92052,6 @@ SQLITE_API int sqlite3_exec(
const char *zLeftover; /* Tail of unprocessed SQL */
sqlite3_stmt *pStmt = 0; /* The current SQL statement */
char **azCols = 0; /* Names of result columns */
- int nRetry = 0; /* Number of retry attempts */
int callbackIsInit; /* True if callback data is initialized */
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
@@ -89858,12 +92059,12 @@ SQLITE_API int sqlite3_exec(
sqlite3_mutex_enter(db->mutex);
sqlite3Error(db, SQLITE_OK, 0);
- while( (rc==SQLITE_OK || (rc==SQLITE_SCHEMA && (++nRetry)<2)) && zSql[0] ){
+ while( rc==SQLITE_OK && zSql[0] ){
int nCol;
char **azVals = 0;
pStmt = 0;
- rc = sqlite3_prepare(db, zSql, -1, &pStmt, &zLeftover);
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover);
assert( rc==SQLITE_OK || pStmt==0 );
if( rc!=SQLITE_OK ){
continue;
@@ -89920,11 +92121,8 @@ SQLITE_API int sqlite3_exec(
if( rc!=SQLITE_ROW ){
rc = sqlite3VdbeFinalize((Vdbe *)pStmt);
pStmt = 0;
- if( rc!=SQLITE_SCHEMA ){
- nRetry = 0;
- zSql = zLeftover;
- while( sqlite3Isspace(zSql[0]) ) zSql++;
- }
+ zSql = zLeftover;
+ while( sqlite3Isspace(zSql[0]) ) zSql++;
break;
}
}
@@ -90215,6 +92413,20 @@ struct sqlite3_api_routines {
int (*blob_reopen)(sqlite3_blob*,sqlite3_int64);
int (*vtab_config)(sqlite3*,int op,...);
int (*vtab_on_conflict)(sqlite3*);
+ /* Version 3.7.16 and later */
+ int (*close_v2)(sqlite3*);
+ const char *(*db_filename)(sqlite3*,const char*);
+ int (*db_readonly)(sqlite3*,const char*);
+ int (*db_release_memory)(sqlite3*);
+ const char *(*errstr)(int);
+ int (*stmt_busy)(sqlite3_stmt*);
+ int (*stmt_readonly)(sqlite3_stmt*);
+ int (*stricmp)(const char*,const char*);
+ int (*uri_boolean)(const char*,const char*,int);
+ sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64);
+ 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*);
};
/*
@@ -90418,10 +92630,33 @@ struct sqlite3_api_routines {
#define sqlite3_blob_reopen sqlite3_api->blob_reopen
#define sqlite3_vtab_config sqlite3_api->vtab_config
#define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict
+/* Version 3.7.16 and later */
+#define sqlite3_close_v2 sqlite3_api->close_v2
+#define sqlite3_db_filename sqlite3_api->db_filename
+#define sqlite3_db_readonly sqlite3_api->db_readonly
+#define sqlite3_db_release_memory sqlite3_api->db_release_memory
+#define sqlite3_errstr sqlite3_api->errstr
+#define sqlite3_stmt_busy sqlite3_api->stmt_busy
+#define sqlite3_stmt_readonly sqlite3_api->stmt_readonly
+#define sqlite3_stricmp sqlite3_api->stricmp
+#define sqlite3_uri_boolean sqlite3_api->uri_boolean
+#define sqlite3_uri_int64 sqlite3_api->uri_int64
+#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
#endif /* SQLITE_CORE */
-#define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api = 0;
-#define SQLITE_EXTENSION_INIT2(v) sqlite3_api = v;
+#ifndef SQLITE_CORE
+ /* This case when the file really is being compiled as a loadable
+ ** extension */
+# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0;
+# define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v;
+#else
+ /* This case when the file is being statically linked into the
+ ** application */
+# define SQLITE_EXTENSION_INIT1 /*no-op*/
+# define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */
+#endif
#endif /* _SQLITE3EXT_H_ */
@@ -90787,6 +93022,19 @@ static const sqlite3_api_routines sqlite3Apis = {
sqlite3_blob_reopen,
sqlite3_vtab_config,
sqlite3_vtab_on_conflict,
+ sqlite3_close_v2,
+ sqlite3_db_filename,
+ sqlite3_db_readonly,
+ sqlite3_db_release_memory,
+ sqlite3_errstr,
+ sqlite3_stmt_busy,
+ sqlite3_stmt_readonly,
+ sqlite3_stricmp,
+ sqlite3_uri_boolean,
+ sqlite3_uri_int64,
+ sqlite3_uri_parameter,
+ sqlite3_vsnprintf,
+ sqlite3_wal_checkpoint_v2
};
/*
@@ -90811,8 +93059,23 @@ static int sqlite3LoadExtension(
void *handle;
int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
char *zErrmsg = 0;
+ const char *zEntry;
+ char *zAltEntry = 0;
void **aHandle;
int nMsg = 300 + sqlite3Strlen30(zFile);
+ int ii;
+
+ /* Shared library endings to try if zFile cannot be loaded as written */
+ static const char *azEndings[] = {
+#if SQLITE_OS_WIN
+ "dll"
+#elif defined(__APPLE__)
+ "dylib"
+#else
+ "so"
+#endif
+ };
+
if( pzErrMsg ) *pzErrMsg = 0;
@@ -90829,11 +93092,17 @@ static int sqlite3LoadExtension(
return SQLITE_ERROR;
}
- if( zProc==0 ){
- zProc = "sqlite3_extension_init";
- }
+ zEntry = zProc ? zProc : "sqlite3_extension_init";
handle = sqlite3OsDlOpen(pVfs, zFile);
+#if SQLITE_OS_UNIX || SQLITE_OS_WIN
+ for(ii=0; ii<ArraySize(azEndings) && handle==0; ii++){
+ char *zAltFile = sqlite3_mprintf("%s.%s", zFile, azEndings[ii]);
+ if( zAltFile==0 ) return SQLITE_NOMEM;
+ handle = sqlite3OsDlOpen(pVfs, zAltFile);
+ sqlite3_free(zAltFile);
+ }
+#endif
if( handle==0 ){
if( pzErrMsg ){
*pzErrMsg = zErrmsg = sqlite3_malloc(nMsg);
@@ -90846,20 +93115,57 @@ static int sqlite3LoadExtension(
return SQLITE_ERROR;
}
xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
- sqlite3OsDlSym(pVfs, handle, zProc);
+ sqlite3OsDlSym(pVfs, handle, zEntry);
+
+ /* If no entry point was specified and the default legacy
+ ** entry point name "sqlite3_extension_init" was not found, then
+ ** construct an entry point name "sqlite3_X_init" where the X is
+ ** replaced by the lowercase value of every ASCII alphabetic
+ ** character in the filename after the last "/" upto the first ".",
+ ** and eliding the first three characters if they are "lib".
+ ** Examples:
+ **
+ ** /usr/local/lib/libExample5.4.3.so ==> sqlite3_example_init
+ ** C:/lib/mathfuncs.dll ==> sqlite3_mathfuncs_init
+ */
+ if( xInit==0 && zProc==0 ){
+ int iFile, iEntry, c;
+ int ncFile = sqlite3Strlen30(zFile);
+ zAltEntry = sqlite3_malloc(ncFile+30);
+ if( zAltEntry==0 ){
+ sqlite3OsDlClose(pVfs, handle);
+ return SQLITE_NOMEM;
+ }
+ memcpy(zAltEntry, "sqlite3_", 8);
+ for(iFile=ncFile-1; iFile>=0 && zFile[iFile]!='/'; iFile--){}
+ iFile++;
+ if( sqlite3_strnicmp(zFile+iFile, "lib", 3)==0 ) iFile += 3;
+ for(iEntry=8; (c = zFile[iFile])!=0 && c!='.'; iFile++){
+ if( sqlite3Isalpha(c) ){
+ zAltEntry[iEntry++] = (char)sqlite3UpperToLower[(unsigned)c];
+ }
+ }
+ memcpy(zAltEntry+iEntry, "_init", 6);
+ zEntry = zAltEntry;
+ xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
+ sqlite3OsDlSym(pVfs, handle, zEntry);
+ }
if( xInit==0 ){
if( pzErrMsg ){
- nMsg += sqlite3Strlen30(zProc);
+ nMsg += sqlite3Strlen30(zEntry);
*pzErrMsg = zErrmsg = sqlite3_malloc(nMsg);
if( zErrmsg ){
sqlite3_snprintf(nMsg, zErrmsg,
- "no entry point [%s] in shared library [%s]", zProc,zFile);
+ "no entry point [%s] in shared library [%s]", zEntry, zFile);
sqlite3OsDlError(pVfs, nMsg-1, zErrmsg);
}
- sqlite3OsDlClose(pVfs, handle);
}
+ sqlite3OsDlClose(pVfs, handle);
+ sqlite3_free(zAltEntry);
return SQLITE_ERROR;
- }else if( xInit(db, &zErrmsg, &sqlite3Apis) ){
+ }
+ sqlite3_free(zAltEntry);
+ if( xInit(db, &zErrmsg, &sqlite3Apis) ){
if( pzErrMsg ){
*pzErrMsg = sqlite3_mprintf("error during initialization: %s", zErrmsg);
}
@@ -91253,6 +93559,9 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
{ "sql_trace", SQLITE_SqlTrace },
{ "vdbe_listing", SQLITE_VdbeListing },
{ "vdbe_trace", SQLITE_VdbeTrace },
+ { "vdbe_addoptrace", SQLITE_VdbeAddopTrace},
+ { "vdbe_debug", SQLITE_SqlTrace | SQLITE_VdbeListing
+ | SQLITE_VdbeTrace },
#endif
#ifndef SQLITE_OMIT_CHECK
{ "ignore_check_constraints", SQLITE_IgnoreChecks },
@@ -91385,7 +93694,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
int rc; /* return value form SQLITE_FCNTL_PRAGMA */
sqlite3 *db = pParse->db; /* The database connection */
Db *pDb; /* The specific database being pragmaed */
- Vdbe *v = pParse->pVdbe = sqlite3VdbeCreate(db); /* Prepared statement */
+ Vdbe *v = sqlite3GetVdbe(pParse); /* Prepared statement */
if( v==0 ) return;
sqlite3VdbeRunOnlyOnce(v);
@@ -91426,6 +93735,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
aFcntl[1] = zLeft;
aFcntl[2] = zRight;
aFcntl[3] = 0;
+ db->busyHandler.nBusy = 0;
rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_PRAGMA, (void*)aFcntl);
if( rc==SQLITE_OK ){
if( aFcntl[0] ){
@@ -91467,11 +93777,12 @@ SQLITE_PRIVATE void sqlite3Pragma(
static const VdbeOpList getCacheSize[] = {
{ OP_Transaction, 0, 0, 0}, /* 0 */
{ OP_ReadCookie, 0, 1, BTREE_DEFAULT_CACHE_SIZE}, /* 1 */
- { OP_IfPos, 1, 7, 0},
+ { OP_IfPos, 1, 8, 0},
{ OP_Integer, 0, 2, 0},
{ OP_Subtract, 1, 2, 1},
- { OP_IfPos, 1, 7, 0},
+ { OP_IfPos, 1, 8, 0},
{ OP_Integer, 0, 1, 0}, /* 6 */
+ { OP_Noop, 0, 0, 0},
{ OP_ResultRow, 1, 1, 0},
};
int addr;
@@ -91810,6 +94121,43 @@ SQLITE_PRIVATE void sqlite3Pragma(
}else
/*
+ ** PRAGMA [database.]mmap_size(N)
+ **
+ ** Used to set mapping size limit. The mapping size limit is
+ ** used to limit the aggregate size of all memory mapped regions of the
+ ** database file. If this parameter is set to zero, then memory mapping
+ ** is not used at all. If N is negative, then the default memory map
+ ** limit determined by sqlite3_config(SQLITE_CONFIG_MMAP_SIZE) is set.
+ ** The parameter N is measured in bytes.
+ **
+ ** This value is advisory. The underlying VFS is free to memory map
+ ** as little or as much as it wants. Except, if N is set to 0 then the
+ ** upper layers will never invoke the xFetch interfaces to the VFS.
+ */
+ if( sqlite3StrICmp(zLeft,"mmap_size")==0 ){
+ sqlite3_int64 sz;
+ assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
+ if( zRight ){
+ int ii;
+ sqlite3Atoi64(zRight, &sz, 1000, SQLITE_UTF8);
+ if( sz<0 ) sz = sqlite3GlobalConfig.szMmap;
+ if( pId2->n==0 ) db->szMmap = sz;
+ for(ii=db->nDb-1; ii>=0; ii--){
+ if( db->aDb[ii].pBt && (ii==iDb || pId2->n==0) ){
+ sqlite3BtreeSetMmapLimit(db->aDb[ii].pBt, sz);
+ }
+ }
+ }
+ sz = -1;
+ if( sqlite3_file_control(db,zDb,SQLITE_FCNTL_MMAP_SIZE,&sz)==SQLITE_OK ){
+#if SQLITE_MAX_MMAP_SIZE==0
+ sz = 0;
+#endif
+ returnSingleInt(pParse, "mmap_size", sz);
+ }
+ }else
+
+ /*
** PRAGMA temp_store
** PRAGMA temp_store = "default"|"memory"|"file"
**
@@ -92070,11 +94418,14 @@ SQLITE_PRIVATE void sqlite3Pragma(
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
pTab = sqlite3FindTable(db, zRight, zDb);
if( pTab ){
- int i;
+ int i, k;
int nHidden = 0;
Column *pCol;
+ Index *pPk;
+ for(pPk=pTab->pIndex; pPk && pPk->autoIndex!=2; pPk=pPk->pNext){}
sqlite3VdbeSetNumCols(v, 6);
pParse->nMem = 6;
+ sqlite3CodeVerifySchema(pParse, iDb);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cid", SQLITE_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "type", SQLITE_STATIC);
@@ -92097,7 +94448,14 @@ SQLITE_PRIVATE void sqlite3Pragma(
}else{
sqlite3VdbeAddOp2(v, OP_Null, 0, 5);
}
- sqlite3VdbeAddOp2(v, OP_Integer, pCol->isPrimKey, 6);
+ if( (pCol->colFlags & COLFLAG_PRIMKEY)==0 ){
+ k = 0;
+ }else if( pPk==0 ){
+ k = 1;
+ }else{
+ for(k=1; ALWAYS(k<=pTab->nCol) && pPk->aiColumn[k-1]!=i; k++){}
+ }
+ sqlite3VdbeAddOp2(v, OP_Integer, k, 6);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6);
}
}
@@ -92113,6 +94471,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
pTab = pIdx->pTable;
sqlite3VdbeSetNumCols(v, 3);
pParse->nMem = 3;
+ 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);
@@ -92139,6 +94498,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
int i = 0;
sqlite3VdbeSetNumCols(v, 3);
pParse->nMem = 3;
+ 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);
@@ -92202,6 +94562,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
int i = 0;
sqlite3VdbeSetNumCols(v, 8);
pParse->nMem = 8;
+ sqlite3CodeVerifySchema(pParse, iDb);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "id", SQLITE_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "seq", SQLITE_STATIC);
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "table", SQLITE_STATIC);
@@ -92235,6 +94596,122 @@ SQLITE_PRIVATE void sqlite3Pragma(
}else
#endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */
+#ifndef SQLITE_OMIT_FOREIGN_KEY
+#ifndef SQLITE_OMIT_TRIGGER
+ if( sqlite3StrICmp(zLeft, "foreign_key_check")==0 ){
+ FKey *pFK; /* A foreign key constraint */
+ Table *pTab; /* Child table contain "REFERENCES" keyword */
+ Table *pParent; /* Parent table that child points to */
+ Index *pIdx; /* Index in the parent table */
+ int i; /* Loop counter: Foreign key number for pTab */
+ int j; /* Loop counter: Field of the foreign key */
+ HashElem *k; /* Loop counter: Next table in schema */
+ int x; /* result variable */
+ int regResult; /* 3 registers to hold a result row */
+ int regKey; /* Register to hold key for checking the FK */
+ int regRow; /* Registers to hold a row from pTab */
+ int addrTop; /* Top of a loop checking foreign keys */
+ int addrOk; /* Jump here if the key is OK */
+ int *aiCols; /* child to parent column mapping */
+
+ if( sqlite3ReadSchema(pParse) ) goto pragma_out;
+ regResult = pParse->nMem+1;
+ pParse->nMem += 4;
+ regKey = ++pParse->nMem;
+ regRow = ++pParse->nMem;
+ v = sqlite3GetVdbe(pParse);
+ sqlite3VdbeSetNumCols(v, 4);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "table", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "rowid", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "parent", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "fkid", SQLITE_STATIC);
+ sqlite3CodeVerifySchema(pParse, iDb);
+ k = sqliteHashFirst(&db->aDb[iDb].pSchema->tblHash);
+ while( k ){
+ if( zRight ){
+ pTab = sqlite3LocateTable(pParse, 0, zRight, zDb);
+ k = 0;
+ }else{
+ pTab = (Table*)sqliteHashData(k);
+ k = sqliteHashNext(k);
+ }
+ if( pTab==0 || pTab->pFKey==0 ) continue;
+ sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
+ if( pTab->nCol+regRow>pParse->nMem ) pParse->nMem = pTab->nCol + regRow;
+ sqlite3OpenTable(pParse, 0, iDb, pTab, OP_OpenRead);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, regResult, 0, pTab->zName,
+ P4_TRANSIENT);
+ for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){
+ pParent = sqlite3LocateTable(pParse, 0, pFK->zTo, zDb);
+ if( pParent==0 ) break;
+ pIdx = 0;
+ sqlite3TableLock(pParse, iDb, pParent->tnum, 0, pParent->zName);
+ x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, 0);
+ if( x==0 ){
+ if( pIdx==0 ){
+ sqlite3OpenTable(pParse, i, iDb, pParent, OP_OpenRead);
+ }else{
+ KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
+ sqlite3VdbeAddOp3(v, OP_OpenRead, i, pIdx->tnum, iDb);
+ sqlite3VdbeChangeP4(v, -1, (char*)pKey, P4_KEYINFO_HANDOFF);
+ }
+ }else{
+ k = 0;
+ break;
+ }
+ }
+ if( pFK ) break;
+ if( pParse->nTab<i ) pParse->nTab = i;
+ addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, 0);
+ for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){
+ pParent = sqlite3LocateTable(pParse, 0, pFK->zTo, zDb);
+ assert( pParent!=0 );
+ pIdx = 0;
+ aiCols = 0;
+ x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, &aiCols);
+ assert( x==0 );
+ addrOk = sqlite3VdbeMakeLabel(v);
+ if( pIdx==0 ){
+ int iKey = pFK->aCol[0].iFrom;
+ assert( iKey>=0 && iKey<pTab->nCol );
+ if( iKey!=pTab->iPKey ){
+ sqlite3VdbeAddOp3(v, OP_Column, 0, iKey, regRow);
+ sqlite3ColumnDefault(v, pTab, iKey, regRow);
+ sqlite3VdbeAddOp2(v, OP_IsNull, regRow, addrOk);
+ sqlite3VdbeAddOp2(v, OP_MustBeInt, regRow,
+ sqlite3VdbeCurrentAddr(v)+3);
+ }else{
+ sqlite3VdbeAddOp2(v, OP_Rowid, 0, regRow);
+ }
+ sqlite3VdbeAddOp3(v, OP_NotExists, i, 0, regRow);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, addrOk);
+ sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2);
+ }else{
+ for(j=0; j<pFK->nCol; j++){
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, 0,
+ aiCols ? aiCols[j] : pFK->aCol[0].iFrom, regRow+j);
+ sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk);
+ }
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regRow, pFK->nCol, regKey);
+ sqlite3VdbeChangeP4(v, -1,
+ sqlite3IndexAffinityStr(v,pIdx), P4_TRANSIENT);
+ sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0);
+ }
+ sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, regResult+2, 0,
+ pFK->zTo, P4_TRANSIENT);
+ sqlite3VdbeAddOp2(v, OP_Integer, i-1, regResult+3);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, 4);
+ sqlite3VdbeResolveLabel(v, addrOk);
+ sqlite3DbFree(db, aiCols);
+ }
+ sqlite3VdbeAddOp2(v, OP_Next, 0, addrTop+1);
+ sqlite3VdbeJumpHere(v, addrTop);
+ }
+ }else
+#endif /* !defined(SQLITE_OMIT_TRIGGER) */
+#endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */
+
#ifndef NDEBUG
if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){
if( zRight ){
@@ -92356,7 +94833,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName),
P4_DYNAMIC);
- sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1);
+ sqlite3VdbeAddOp2(v, OP_Move, 2, 4);
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2);
sqlite3VdbeAddOp2(v, OP_ResultRow, 2, 1);
sqlite3VdbeJumpHere(v, addr);
@@ -92519,6 +94996,11 @@ SQLITE_PRIVATE void sqlite3Pragma(
** PRAGMA [database.]user_version
** PRAGMA [database.]user_version = <integer>
**
+ ** PRAGMA [database.]freelist_count = <integer>
+ **
+ ** PRAGMA [database.]application_id
+ ** PRAGMA [database.]application_id = <integer>
+ **
** The pragma's schema_version and user_version are used to set or get
** the value of the schema-version and user-version, respectively. Both
** the schema-version and the user-version are 32-bit signed integers
@@ -92540,10 +95022,14 @@ SQLITE_PRIVATE void sqlite3Pragma(
if( sqlite3StrICmp(zLeft, "schema_version")==0
|| sqlite3StrICmp(zLeft, "user_version")==0
|| sqlite3StrICmp(zLeft, "freelist_count")==0
+ || sqlite3StrICmp(zLeft, "application_id")==0
){
int iCookie; /* Cookie index. 1 for schema-cookie, 6 for user-cookie. */
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;
@@ -92659,6 +95145,22 @@ SQLITE_PRIVATE void sqlite3Pragma(
sqlite3_db_release_memory(db);
}else
+ /*
+ ** PRAGMA busy_timeout
+ ** PRAGMA busy_timeout = N
+ **
+ ** Call sqlite3_busy_timeout(db, N). Return the current timeout value
+ ** if one is set. If no busy handler or a different busy handler is set
+ ** then 0 is returned. Setting the busy_timeout to 0 or negative
+ ** disables the timeout.
+ */
+ if( sqlite3StrICmp(zLeft, "busy_timeout")==0 ){
+ if( zRight ){
+ sqlite3_busy_timeout(db, sqlite3Atoi(zRight));
+ }
+ returnSingleInt(pParse, "timeout", db->busyTimeout);
+ }else
+
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
/*
** Report the current state of file logs for all databases
@@ -92674,13 +95176,12 @@ SQLITE_PRIVATE void sqlite3Pragma(
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "status", SQLITE_STATIC);
for(i=0; i<db->nDb; i++){
Btree *pBt;
- Pager *pPager;
const char *zState = "unknown";
int j;
if( db->aDb[i].zName==0 ) continue;
sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, db->aDb[i].zName, P4_STATIC);
pBt = db->aDb[i].pBt;
- if( pBt==0 || (pPager = sqlite3BtreePager(pBt))==0 ){
+ if( pBt==0 || sqlite3BtreePager(pBt)==0 ){
zState = "closed";
}else if( sqlite3_file_control(db, i ? db->aDb[i].zName : 0,
SQLITE_FCNTL_LOCKSTATE, &j)==SQLITE_OK ){
@@ -92717,7 +95218,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
}else
#endif
#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
- if( sqlite3StrICmp(zLeft, "activate_extensions")==0 ){
+ if( sqlite3StrICmp(zLeft, "activate_extensions")==0 && zRight ){
#ifdef SQLITE_HAS_CODEC
if( sqlite3StrNICmp(zRight, "see-", 4)==0 ){
sqlite3_activate_see(&zRight[4]);
@@ -92889,7 +95390,9 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char
static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
int rc;
int i;
+#ifndef SQLITE_OMIT_DEPRECATED
int size;
+#endif
Table *pTab;
Db *pDb;
char const *azArg[4];
@@ -92932,7 +95435,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
/* zMasterSchema and zInitScript are set to point at the master schema
** and initialisation script appropriate for the database being
- ** initialised. zMasterName is the name of the master table.
+ ** initialized. zMasterName is the name of the master table.
*/
if( !OMIT_TEMPDB && iDb==1 ){
zMasterSchema = temp_master_schema;
@@ -93012,11 +95515,15 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
*/
if( meta[BTREE_TEXT_ENCODING-1] ){ /* text encoding */
if( iDb==0 ){
+#ifndef SQLITE_OMIT_UTF16
u8 encoding;
/* If opening the main database, set ENC(db). */
encoding = (u8)meta[BTREE_TEXT_ENCODING-1] & 3;
if( encoding==0 ) encoding = SQLITE_UTF8;
ENC(db) = encoding;
+#else
+ ENC(db) = SQLITE_UTF8;
+#endif
}else{
/* If opening an attached database, the encoding much match ENC(db) */
if( meta[BTREE_TEXT_ENCODING-1]!=ENC(db) ){
@@ -93153,7 +95660,7 @@ SQLITE_PRIVATE int sqlite3Init(sqlite3 *db, char **pzErrMsg){
}
}
- /* Once all the other databases have been initialised, load the schema
+ /* Once all the other databases have been initialized, load the schema
** for the TEMP database. This is loaded last, as the TEMP database
** schema may contain references to objects in other databases.
*/
@@ -93176,7 +95683,7 @@ SQLITE_PRIVATE int sqlite3Init(sqlite3 *db, char **pzErrMsg){
}
/*
-** This routine is a no-op if the database schema is already initialised.
+** This routine is a no-op if the database schema is already initialized.
** Otherwise, the schema is loaded. An error code is returned.
*/
SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse){
@@ -93403,7 +95910,6 @@ static int sqlite3Prepare(
}
#endif
- assert( db->init.busy==0 || saveSqlFlag==0 );
if( db->init.busy==0 ){
Vdbe *pVdbe = pParse->pVdbe;
sqlite3VdbeSetSql(pVdbe, zSql, (int)(pParse->zTail-zSql), saveSqlFlag);
@@ -93674,7 +96180,7 @@ SQLITE_PRIVATE Select *sqlite3SelectNew(
ExprList *pGroupBy, /* the GROUP BY clause */
Expr *pHaving, /* the HAVING clause */
ExprList *pOrderBy, /* the ORDER BY clause */
- int isDistinct, /* true if the DISTINCT keyword is present */
+ u16 selFlags, /* Flag parameters, such as SF_Distinct */
Expr *pLimit, /* LIMIT value. NULL means not used */
Expr *pOffset /* OFFSET value. NULL means no offset */
){
@@ -93698,7 +96204,7 @@ SQLITE_PRIVATE Select *sqlite3SelectNew(
pNew->pGroupBy = pGroupBy;
pNew->pHaving = pHaving;
pNew->pOrderBy = pOrderBy;
- pNew->selFlags = isDistinct ? SF_Distinct : 0;
+ pNew->selFlags = selFlags;
pNew->op = TK_SELECT;
pNew->pLimit = pLimit;
pNew->pOffset = pOffset;
@@ -94145,6 +96651,19 @@ static int checkForMultiColumnSelectError(
#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.
+*/
+typedef struct DistinctCtx DistinctCtx;
+struct DistinctCtx {
+ u8 isTnct; /* True if the DISTINCT keyword is present */
+ u8 eTnctType; /* One of the WHERE_DISTINCT_* operators */
+ int tabTnct; /* Ephemeral table used for DISTINCT processing */
+ int addrTnct; /* Address of OP_OpenEphemeral opcode for tabTnct */
+};
+
+/*
** This routine generates the code for the inside of the inner loop
** of a SELECT.
**
@@ -94160,7 +96679,7 @@ static void selectInnerLoop(
int srcTab, /* Pull data from this table */
int nColumn, /* Number of columns in the source table */
ExprList *pOrderBy, /* If not NULL, sort results using this key */
- int distinct, /* If >=0, make sure results are distinct */
+ DistinctCtx *pDistinct, /* If not NULL, info on how to process DISTINCT */
SelectDest *pDest, /* How to dispose of the results */
int iContinue, /* Jump here to continue with next row */
int iBreak /* Jump here to break out of the inner loop */
@@ -94176,7 +96695,7 @@ static void selectInnerLoop(
assert( v );
if( NEVER(v==0) ) return;
assert( pEList!=0 );
- hasDistinct = distinct>=0;
+ hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP;
if( pOrderBy==0 && !hasDistinct ){
codeOffset(v, p, iContinue);
}
@@ -94216,7 +96735,55 @@ static void selectInnerLoop(
if( hasDistinct ){
assert( pEList!=0 );
assert( pEList->nExpr==nColumn );
- codeDistinct(pParse, distinct, iContinue, nColumn, regResult);
+ switch( pDistinct->eTnctType ){
+ case WHERE_DISTINCT_ORDERED: {
+ VdbeOp *pOp; /* No longer required OpenEphemeral instr. */
+ int iJump; /* Jump destination */
+ int regPrev; /* Previous row content */
+
+ /* Allocate space for the previous row */
+ regPrev = pParse->nMem+1;
+ pParse->nMem += nColumn;
+
+ /* Change the OP_OpenEphemeral coded earlier to an OP_Null
+ ** sets the MEM_Cleared bit on the first register of the
+ ** previous value. This will cause the OP_Ne below to always
+ ** fail on the first iteration of the loop even if the first
+ ** row is all NULLs.
+ */
+ sqlite3VdbeChangeToNoop(v, pDistinct->addrTnct);
+ pOp = sqlite3VdbeGetOp(v, pDistinct->addrTnct);
+ pOp->opcode = OP_Null;
+ pOp->p1 = 1;
+ pOp->p2 = regPrev;
+
+ iJump = sqlite3VdbeCurrentAddr(v) + nColumn;
+ for(i=0; i<nColumn; i++){
+ CollSeq *pColl = sqlite3ExprCollSeq(pParse, pEList->a[i].pExpr);
+ if( i<nColumn-1 ){
+ sqlite3VdbeAddOp3(v, OP_Ne, regResult+i, iJump, regPrev+i);
+ }else{
+ sqlite3VdbeAddOp3(v, OP_Eq, regResult+i, iContinue, regPrev+i);
+ }
+ sqlite3VdbeChangeP4(v, -1, (const char *)pColl, P4_COLLSEQ);
+ sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
+ }
+ assert( sqlite3VdbeCurrentAddr(v)==iJump );
+ sqlite3VdbeAddOp3(v, OP_Copy, regResult, regPrev, nColumn-1);
+ break;
+ }
+
+ case WHERE_DISTINCT_UNIQUE: {
+ sqlite3VdbeChangeToNoop(v, pDistinct->addrTnct);
+ break;
+ }
+
+ default: {
+ assert( pDistinct->eTnctType==WHERE_DISTINCT_UNORDERED );
+ codeDistinct(pParse, pDistinct->tabTnct, iContinue, nColumn, regResult);
+ break;
+ }
+ }
if( pOrderBy==0 ){
codeOffset(v, p, iContinue);
}
@@ -94274,7 +96841,8 @@ static void selectInnerLoop(
*/
case SRT_Set: {
assert( nColumn==1 );
- p->affinity = sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affSdst);
+ pDest->affSdst =
+ sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affSdst);
if( pOrderBy ){
/* At first glance you would think we could optimize out the
** ORDER BY in this case since the order of entries in the set
@@ -94283,7 +96851,7 @@ static void selectInnerLoop(
pushOntoSorter(pParse, pOrderBy, p, regResult);
}else{
int r1 = sqlite3GetTempReg(pParse);
- sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, 1, r1, &p->affinity, 1);
+ sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult,1,r1, &pDest->affSdst, 1);
sqlite3ExprCacheAffinityChange(pParse, regResult, 1);
sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
sqlite3ReleaseTempReg(pParse, r1);
@@ -94550,7 +97118,8 @@ static void generateSortTail(
#ifndef SQLITE_OMIT_SUBQUERY
case SRT_Set: {
assert( nColumn==1 );
- sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, 1, regRowid, &p->affinity, 1);
+ sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, 1, regRowid,
+ &pDest->affSdst, 1);
sqlite3ExprCacheAffinityChange(pParse, regRow, 1);
sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, regRowid);
break;
@@ -94865,7 +97434,7 @@ static void generateColumnNames(
static int selectColumnsFromExprList(
Parse *pParse, /* Parsing context */
ExprList *pEList, /* Expr list from which to derive column names */
- int *pnCol, /* Write the number of columns here */
+ i16 *pnCol, /* Write the number of columns here */
Column **paCol /* Write the new column list here */
){
sqlite3 *db = pParse->db; /* Database connection */
@@ -94891,9 +97460,7 @@ static int selectColumnsFromExprList(
for(i=0, pCol=aCol; i<nCol; i++, pCol++){
/* Get an appropriate name for the column
*/
- p = pEList->a[i].pExpr;
- assert( p->pRight==0 || ExprHasProperty(p->pRight, EP_IntValue)
- || p->pRight->u.zToken==0 || p->pRight->u.zToken[0]!=0 );
+ p = sqlite3ExprSkipCollate(pEList->a[i].pExpr);
if( (zName = pEList->a[i].zName)!=0 ){
/* If the column contains an "AS <name>" phrase, use <name> as the name */
zName = sqlite3DbStrDup(db, zName);
@@ -94931,6 +97498,9 @@ static int selectColumnsFromExprList(
for(j=cnt=0; j<i; j++){
if( sqlite3StrICmp(aCol[j].zName, zName)==0 ){
char *zNewName;
+ int k;
+ for(k=nName-1; k>1 && sqlite3Isdigit(zName[k]); k--){}
+ if( zName[k]==':' ) nName = k;
zName[nName] = 0;
zNewName = sqlite3MPrintf(db, "%s:%d", zName, ++cnt);
sqlite3DbFree(db, zName);
@@ -95262,6 +97832,8 @@ static int multiSelect(
int addr = 0;
int nLimit;
assert( !pPrior->pLimit );
+ pPrior->iLimit = p->iLimit;
+ pPrior->iOffset = p->iOffset;
pPrior->pLimit = p->pLimit;
pPrior->pOffset = p->pOffset;
explainSetInteger(iSub1, pParse->iNextSelectId);
@@ -95387,7 +97959,7 @@ static int multiSelect(
sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak);
iStart = sqlite3VdbeCurrentAddr(v);
selectInnerLoop(pParse, p, p->pEList, unionTab, p->pEList->nExpr,
- 0, -1, &dest, iCont, iBreak);
+ 0, 0, &dest, iCont, iBreak);
sqlite3VdbeResolveLabel(v, iCont);
sqlite3VdbeAddOp2(v, OP_Next, unionTab, iStart);
sqlite3VdbeResolveLabel(v, iBreak);
@@ -95465,7 +98037,7 @@ static int multiSelect(
sqlite3VdbeAddOp4Int(v, OP_NotFound, tab2, iCont, r1, 0);
sqlite3ReleaseTempReg(pParse, r1);
selectInnerLoop(pParse, p, p->pEList, tab1, p->pEList->nExpr,
- 0, -1, &dest, iCont, iBreak);
+ 0, 0, &dest, iCont, iBreak);
sqlite3VdbeResolveLabel(v, iCont);
sqlite3VdbeAddOp2(v, OP_Next, tab1, iStart);
sqlite3VdbeResolveLabel(v, iBreak);
@@ -95511,6 +98083,7 @@ static int multiSelect(
*apColl = db->pDfltColl;
}
}
+ pKeyInfo->aSortOrder = (u8*)apColl;
for(pLoop=p; pLoop; pLoop=pLoop->pPrior){
for(i=0; i<2; i++){
@@ -95584,7 +98157,7 @@ static int generateOutputSubroutine(
(char*)pKeyInfo, p4type);
sqlite3VdbeAddOp3(v, OP_Jump, j2+2, iContinue, j2+2);
sqlite3VdbeJumpHere(v, j1);
- sqlite3ExprCodeCopy(pParse, pIn->iSdst, regPrev+1, pIn->nSdst);
+ sqlite3VdbeAddOp3(v, OP_Copy, pIn->iSdst, regPrev+1, pIn->nSdst-1);
sqlite3VdbeAddOp2(v, OP_Integer, 1, regPrev);
}
if( pParse->db->mallocFailed ) return 0;
@@ -95619,10 +98192,10 @@ static int generateOutputSubroutine(
case SRT_Set: {
int r1;
assert( pIn->nSdst==1 );
- p->affinity =
+ pDest->affSdst =
sqlite3CompareAffinity(p->pEList->a[0].pExpr, pDest->affSdst);
r1 = sqlite3GetTempReg(pParse);
- sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst, 1, r1, &p->affinity, 1);
+ sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst, 1, r1, &pDest->affSdst,1);
sqlite3ExprCacheAffinityChange(pParse, pIn->iSdst, 1);
sqlite3VdbeAddOp2(v, OP_IdxInsert, pDest->iSDParm, r1);
sqlite3ReleaseTempReg(pParse, r1);
@@ -95888,12 +98461,13 @@ static int multiSelectOrderBy(
for(i=0; i<nOrderBy; i++){
CollSeq *pColl;
Expr *pTerm = pOrderBy->a[i].pExpr;
- if( pTerm->flags & EP_ExpCollate ){
- pColl = pTerm->pColl;
+ if( pTerm->flags & EP_Collate ){
+ pColl = sqlite3ExprCollSeq(pParse, pTerm);
}else{
pColl = multiSelectCollSeq(pParse, p, aPermute[i]);
- pTerm->flags |= EP_ExpCollate;
- pTerm->pColl = pColl;
+ if( pColl==0 ) pColl = db->pDfltColl;
+ pOrderBy->a[i].pExpr =
+ sqlite3ExprAddCollateString(pParse, pTerm, pColl->zName);
}
pKeyMerge->aColl[i] = pColl;
pKeyMerge->aSortOrder[i] = pOrderBy->a[i].sortOrder;
@@ -95917,7 +98491,8 @@ static int multiSelectOrderBy(
}else{
int nExpr = p->pEList->nExpr;
assert( nOrderBy>=nExpr || db->mallocFailed );
- regPrev = sqlite3GetTempRange(pParse, nExpr+1);
+ regPrev = pParse->nMem+1;
+ pParse->nMem += nExpr+1;
sqlite3VdbeAddOp2(v, OP_Integer, 0, regPrev);
pKeyDup = sqlite3DbMallocZero(db,
sizeof(*pKeyDup) + nExpr*(sizeof(CollSeq*)+1) );
@@ -96096,14 +98671,9 @@ static int multiSelectOrderBy(
sqlite3VdbeAddOp4(v, OP_Permutation, 0, 0, 0, (char*)aPermute, P4_INTARRAY);
sqlite3VdbeAddOp4(v, OP_Compare, destA.iSdst, destB.iSdst, nOrderBy,
(char*)pKeyMerge, P4_KEYINFO_HANDOFF);
+ sqlite3VdbeChangeP5(v, OPFLAG_PERMUTE);
sqlite3VdbeAddOp3(v, OP_Jump, addrAltB, addrAeqB, addrAgtB);
- /* Release temporary registers
- */
- if( regPrev ){
- sqlite3ReleaseTempRange(pParse, regPrev, nOrderBy+1);
- }
-
/* Jump to the this point in order to terminate the query.
*/
sqlite3VdbeResolveLabel(v, labelEnd);
@@ -96163,9 +98733,6 @@ static Expr *substExpr(
assert( pEList!=0 && pExpr->iColumn<pEList->nExpr );
assert( pExpr->pLeft==0 && pExpr->pRight==0 );
pNew = sqlite3ExprDup(db, pEList->a[pExpr->iColumn].pExpr, 0);
- if( pNew && pExpr->pColl ){
- pNew->pColl = pExpr->pColl;
- }
sqlite3ExprDelete(db, pExpr);
pExpr = pNew;
}
@@ -96364,7 +98931,7 @@ static int flattenSubquery(
*/
assert( p!=0 );
assert( p->pPrior==0 ); /* Unable to flatten compound queries */
- if( db->flags & SQLITE_QueryFlattener ) return 0;
+ if( OptimizationDisabled(db, SQLITE_QueryFlattener) ) return 0;
pSrc = p->pSrc;
assert( pSrc && iFrom>=0 && iFrom<pSrc->nSrc );
pSubitem = &pSrc->a[iFrom];
@@ -96518,12 +99085,15 @@ static int flattenSubquery(
Select *pNew;
ExprList *pOrderBy = p->pOrderBy;
Expr *pLimit = p->pLimit;
+ Expr *pOffset = p->pOffset;
Select *pPrior = p->pPrior;
p->pOrderBy = 0;
p->pSrc = 0;
p->pPrior = 0;
p->pLimit = 0;
+ p->pOffset = 0;
pNew = sqlite3SelectDup(db, p, 0);
+ p->pOffset = pOffset;
p->pLimit = pLimit;
p->pOrderBy = pOrderBy;
p->pSrc = pSrc;
@@ -96653,10 +99223,9 @@ static int flattenSubquery(
pList = pParent->pEList;
for(i=0; i<pList->nExpr; i++){
if( pList->a[i].zName==0 ){
- const char *zSpan = pList->a[i].zSpan;
- if( ALWAYS(zSpan) ){
- pList->a[i].zName = sqlite3DbStrDup(db, zSpan);
- }
+ char *zName = sqlite3DbStrDup(db, pList->a[i].zSpan);
+ sqlite3Dequote(zName);
+ pList->a[i].zName = zName;
}
}
substExprList(db, pParent->pEList, iParent, pSub->pEList);
@@ -96717,34 +99286,43 @@ static int flattenSubquery(
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
/*
-** Analyze the SELECT statement passed as an argument to see if it
-** is a min() or max() query. Return WHERE_ORDERBY_MIN or WHERE_ORDERBY_MAX if
-** it is, or 0 otherwise. At present, a query is considered to be
-** a min()/max() query if:
+** Based on the contents of the AggInfo structure indicated by the first
+** argument, this function checks if the following are true:
**
-** 1. There is a single object in the FROM clause.
+** * the query contains just a single aggregate function,
+** * the aggregate function is either min() or max(), and
+** * the argument to the aggregate function is a column value.
**
-** 2. There is a single expression in the result set, and it is
-** either min(x) or max(x), where x is a column reference.
+** If all of the above are true, then WHERE_ORDERBY_MIN or WHERE_ORDERBY_MAX
+** is returned as appropriate. Also, *ppMinMax is set to point to the
+** list of arguments passed to the aggregate before returning.
+**
+** Or, if the conditions above are not met, *ppMinMax is set to 0 and
+** WHERE_ORDERBY_NORMAL is returned.
*/
-static u8 minMaxQuery(Select *p){
- Expr *pExpr;
- ExprList *pEList = p->pEList;
+static u8 minMaxQuery(AggInfo *pAggInfo, ExprList **ppMinMax){
+ int eRet = WHERE_ORDERBY_NORMAL; /* Return value */
- if( pEList->nExpr!=1 ) return WHERE_ORDERBY_NORMAL;
- pExpr = pEList->a[0].pExpr;
- if( pExpr->op!=TK_AGG_FUNCTION ) return 0;
- if( NEVER(ExprHasProperty(pExpr, EP_xIsSelect)) ) return 0;
- pEList = pExpr->x.pList;
- if( pEList==0 || pEList->nExpr!=1 ) return 0;
- if( pEList->a[0].pExpr->op!=TK_AGG_COLUMN ) return WHERE_ORDERBY_NORMAL;
- assert( !ExprHasProperty(pExpr, EP_IntValue) );
- if( sqlite3StrICmp(pExpr->u.zToken,"min")==0 ){
- return WHERE_ORDERBY_MIN;
- }else if( sqlite3StrICmp(pExpr->u.zToken,"max")==0 ){
- return WHERE_ORDERBY_MAX;
+ *ppMinMax = 0;
+ if( pAggInfo->nFunc==1 ){
+ Expr *pExpr = pAggInfo->aFunc[0].pExpr; /* Aggregate function */
+ ExprList *pEList = pExpr->x.pList; /* Arguments to agg function */
+
+ assert( pExpr->op==TK_AGG_FUNCTION );
+ if( pEList && pEList->nExpr==1 && pEList->a[0].pExpr->op==TK_AGG_COLUMN ){
+ const char *zFunc = pExpr->u.zToken;
+ if( sqlite3StrICmp(zFunc, "min")==0 ){
+ eRet = WHERE_ORDERBY_MIN;
+ *ppMinMax = pEList;
+ }else if( sqlite3StrICmp(zFunc, "max")==0 ){
+ eRet = WHERE_ORDERBY_MAX;
+ *ppMinMax = pEList;
+ }
+ }
}
- return WHERE_ORDERBY_NORMAL;
+
+ assert( *ppMinMax==0 || (*ppMinMax)->nExpr==1 );
+ return eRet;
}
/*
@@ -96807,6 +99385,69 @@ SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *pParse, struct SrcList_item *pF
}
return SQLITE_OK;
}
+/*
+** Detect compound SELECT statements that use an ORDER BY clause with
+** an alternative collating sequence.
+**
+** SELECT ... FROM t1 EXCEPT SELECT ... FROM t2 ORDER BY .. COLLATE ...
+**
+** These are rewritten as a subquery:
+**
+** SELECT * FROM (SELECT ... FROM t1 EXCEPT SELECT ... FROM t2)
+** ORDER BY ... COLLATE ...
+**
+** This transformation is necessary because the multiSelectOrderBy() routine
+** above that generates the code for a compound SELECT with an ORDER BY clause
+** uses a merge algorithm that requires the same collating sequence on the
+** result columns as on the ORDER BY clause. See ticket
+** http://www.sqlite.org/src/info/6709574d2a
+**
+** This transformation is only needed for EXCEPT, INTERSECT, and UNION.
+** The UNION ALL operator works fine with multiSelectOrderBy() even when
+** there are COLLATE terms in the ORDER BY.
+*/
+static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
+ int i;
+ Select *pNew;
+ Select *pX;
+ sqlite3 *db;
+ struct ExprList_item *a;
+ SrcList *pNewSrc;
+ Parse *pParse;
+ Token dummy;
+
+ if( p->pPrior==0 ) return WRC_Continue;
+ if( p->pOrderBy==0 ) return WRC_Continue;
+ for(pX=p; pX && (pX->op==TK_ALL || pX->op==TK_SELECT); pX=pX->pPrior){}
+ if( pX==0 ) return WRC_Continue;
+ a = p->pOrderBy->a;
+ for(i=p->pOrderBy->nExpr-1; i>=0; i--){
+ if( a[i].pExpr->flags & EP_Collate ) break;
+ }
+ if( i<0 ) return WRC_Continue;
+
+ /* If we reach this point, that means the transformation is required. */
+
+ pParse = pWalker->pParse;
+ db = pParse->db;
+ pNew = sqlite3DbMallocZero(db, sizeof(*pNew) );
+ if( pNew==0 ) return WRC_Abort;
+ memset(&dummy, 0, sizeof(dummy));
+ pNewSrc = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&dummy,pNew,0,0);
+ if( pNewSrc==0 ) return WRC_Abort;
+ *pNew = *p;
+ p->pSrc = pNewSrc;
+ p->pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ALL, 0));
+ p->op = TK_SELECT;
+ p->pWhere = 0;
+ pNew->pGroupBy = 0;
+ pNew->pHaving = 0;
+ pNew->pOrderBy = 0;
+ p->pPrior = 0;
+ pNew->pLimit = 0;
+ pNew->pOffset = 0;
+ return WRC_Continue;
+}
/*
** This routine is a Walker callback for "expanding" a SELECT statement.
@@ -96839,14 +99480,16 @@ static int selectExpander(Walker *pWalker, Select *p){
ExprList *pEList;
struct SrcList_item *pFrom;
sqlite3 *db = pParse->db;
+ Expr *pE, *pRight, *pExpr;
+ u16 selFlags = p->selFlags;
+ p->selFlags |= SF_Expanded;
if( db->mallocFailed ){
return WRC_Abort;
}
- if( NEVER(p->pSrc==0) || (p->selFlags & SF_Expanded)!=0 ){
+ if( NEVER(p->pSrc==0) || (selFlags & SF_Expanded)!=0 ){
return WRC_Prune;
}
- p->selFlags |= SF_Expanded;
pTabList = p->pSrc;
pEList = p->pEList;
@@ -96887,9 +99530,14 @@ static int selectExpander(Walker *pWalker, Select *p){
}else{
/* An ordinary table or view name in the FROM clause */
assert( pFrom->pTab==0 );
- pFrom->pTab = pTab =
- sqlite3LocateTable(pParse,0,pFrom->zName,pFrom->zDatabase);
+ pFrom->pTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom);
if( pTab==0 ) return WRC_Abort;
+ if( pTab->nRef==0xffff ){
+ sqlite3ErrorMsg(pParse, "too many references to \"%s\": max 65535",
+ pTab->zName);
+ pFrom->pTab = 0;
+ return WRC_Abort;
+ }
pTab->nRef++;
#if !defined(SQLITE_OMIT_VIEW) || !defined (SQLITE_OMIT_VIRTUALTABLE)
if( pTab->pSelect || IsVirtual(pTab) ){
@@ -96925,7 +99573,7 @@ static int selectExpander(Walker *pWalker, Select *p){
** that need expanding.
*/
for(k=0; k<pEList->nExpr; k++){
- Expr *pE = pEList->a[k].pExpr;
+ pE = pEList->a[k].pExpr;
if( pE->op==TK_ALL ) break;
assert( pE->op!=TK_DOT || pE->pRight!=0 );
assert( pE->op!=TK_DOT || (pE->pLeft!=0 && pE->pLeft->op==TK_ID) );
@@ -96943,10 +99591,18 @@ static int selectExpander(Walker *pWalker, Select *p){
int longNames = (flags & SQLITE_FullColNames)!=0
&& (flags & SQLITE_ShortColNames)==0;
+ /* When processing FROM-clause subqueries, it is always the case
+ ** that full_column_names=OFF and short_column_names=ON. The
+ ** sqlite3ResultSetOfSelect() routine makes it so. */
+ assert( (p->selFlags & SF_NestedFrom)==0
+ || ((flags & SQLITE_FullColNames)==0 &&
+ (flags & SQLITE_ShortColNames)!=0) );
+
for(k=0; k<pEList->nExpr; k++){
- Expr *pE = a[k].pExpr;
- assert( pE->op!=TK_DOT || pE->pRight!=0 );
- if( pE->op!=TK_ALL && (pE->op!=TK_DOT || pE->pRight->op!=TK_ALL) ){
+ pE = a[k].pExpr;
+ pRight = pE->pRight;
+ assert( pE->op!=TK_DOT || pRight!=0 );
+ if( pE->op!=TK_ALL && (pE->op!=TK_DOT || pRight->op!=TK_ALL) ){
/* This particular expression does not need to be expanded.
*/
pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr);
@@ -96961,32 +99617,43 @@ static int selectExpander(Walker *pWalker, Select *p){
/* This expression is a "*" or a "TABLE.*" and needs to be
** expanded. */
int tableSeen = 0; /* Set to 1 when TABLE matches */
- char *zTName; /* text of name of TABLE */
+ char *zTName = 0; /* text of name of TABLE */
if( pE->op==TK_DOT ){
assert( pE->pLeft!=0 );
assert( !ExprHasProperty(pE->pLeft, EP_IntValue) );
zTName = pE->pLeft->u.zToken;
- }else{
- zTName = 0;
}
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
Table *pTab = pFrom->pTab;
+ Select *pSub = pFrom->pSelect;
char *zTabName = pFrom->zAlias;
+ const char *zSchemaName = 0;
+ int iDb;
if( zTabName==0 ){
zTabName = pTab->zName;
}
if( db->mallocFailed ) break;
- if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){
- continue;
+ if( pSub==0 || (pSub->selFlags & SF_NestedFrom)==0 ){
+ pSub = 0;
+ if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){
+ continue;
+ }
+ iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
+ zSchemaName = iDb>=0 ? db->aDb[iDb].zName : "*";
}
- tableSeen = 1;
for(j=0; j<pTab->nCol; j++){
- Expr *pExpr, *pRight;
char *zName = pTab->aCol[j].zName;
char *zColname; /* The computed column name */
char *zToFree; /* Malloced string that needs to be freed */
Token sColname; /* Computed column name as a token */
+ assert( zName );
+ if( zTName && pSub
+ && sqlite3MatchSpanName(pSub->pEList->a[j].zSpan, 0, zTName, 0)==0
+ ){
+ continue;
+ }
+
/* If a column is marked as 'hidden' (currently only possible
** for virtual tables), do not include it in the expanded
** result-set list.
@@ -96995,6 +99662,7 @@ static int selectExpander(Walker *pWalker, Select *p){
assert(IsVirtual(pTab));
continue;
}
+ tableSeen = 1;
if( i>0 && zTName==0 ){
if( (pFrom->jointype & JT_NATURAL)!=0
@@ -97017,6 +99685,10 @@ static int selectExpander(Walker *pWalker, Select *p){
Expr *pLeft;
pLeft = sqlite3Expr(db, TK_ID, zTabName);
pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0);
+ if( zSchemaName ){
+ pLeft = sqlite3Expr(db, TK_ID, zSchemaName);
+ pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pExpr, 0);
+ }
if( longNames ){
zColname = sqlite3MPrintf(db, "%s.%s", zTabName, zName);
zToFree = zColname;
@@ -97028,6 +99700,18 @@ static int selectExpander(Walker *pWalker, Select *p){
sColname.z = zColname;
sColname.n = sqlite3Strlen30(zColname);
sqlite3ExprListSetName(pParse, pNew, &sColname, 0);
+ if( pNew && (p->selFlags & SF_NestedFrom)!=0 ){
+ struct ExprList_item *pX = &pNew->a[pNew->nExpr-1];
+ if( pSub ){
+ pX->zSpan = sqlite3DbStrDup(db, pSub->pEList->a[j].zSpan);
+ testcase( pX->zSpan==0 );
+ }else{
+ pX->zSpan = sqlite3MPrintf(db, "%s.%s.%s",
+ zSchemaName, zTabName, zColname);
+ testcase( pX->zSpan==0 );
+ }
+ pX->bSpanIsTab = 1;
+ }
sqlite3DbFree(db, zToFree);
}
}
@@ -97080,10 +99764,13 @@ static int exprWalkNoop(Walker *NotUsed, Expr *NotUsed2){
*/
static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){
Walker w;
- w.xSelectCallback = selectExpander;
+ memset(&w, 0, sizeof(w));
+ w.xSelectCallback = convertCompoundSelectToSubquery;
w.xExprCallback = exprWalkNoop;
w.pParse = pParse;
sqlite3WalkSelect(&w, pSelect);
+ w.xSelectCallback = selectExpander;
+ sqlite3WalkSelect(&w, pSelect);
}
@@ -97138,9 +99825,11 @@ static int selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
static void sqlite3SelectAddTypeInfo(Parse *pParse, Select *pSelect){
#ifndef SQLITE_OMIT_SUBQUERY
Walker w;
+ memset(&w, 0, sizeof(w));
w.xSelectCallback = selectAddSubqueryTypeInfo;
w.xExprCallback = exprWalkNoop;
w.pParse = pParse;
+ w.bSelectDepthFirst = 1;
sqlite3WalkSelect(&w, pSelect);
#endif
}
@@ -97166,6 +99855,7 @@ SQLITE_PRIVATE void sqlite3SelectPrep(
sqlite3 *db;
if( NEVER(p==0) ) return;
db = pParse->db;
+ if( db->mallocFailed ) return;
if( p->selFlags & SF_HasTypeInfo ) return;
sqlite3SelectExpand(pParse, p);
if( pParse->nErr || db->mallocFailed ) return;
@@ -97404,11 +100094,9 @@ SQLITE_PRIVATE int sqlite3Select(
ExprList *pOrderBy; /* The ORDER BY clause. May be NULL */
ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */
Expr *pHaving; /* The HAVING clause. May be NULL */
- int isDistinct; /* True if the DISTINCT keyword is present */
- int distinct; /* Table to use for the distinct set */
int rc = 1; /* Value to return from this function */
int addrSortIndex; /* Address of an OP_OpenEphemeral instruction */
- int addrDistinctIndex; /* Address of an OP_OpenEphemeral instruction */
+ DistinctCtx sDistinct; /* Info on how to code the DISTINCT keyword */
AggInfo sAggInfo; /* Information used by aggregate queries */
int iEnd; /* Address of the end of the query */
sqlite3 *db; /* The database connection */
@@ -97468,8 +100156,17 @@ SQLITE_PRIVATE int sqlite3Select(
int isAggSub;
if( pSub==0 ) continue;
+
+ /* Sometimes the code for a subquery will be generated more than
+ ** once, if the subquery is part of the WHERE clause in a LEFT JOIN,
+ ** for example. In that case, do not regenerate the code to manifest
+ ** a view or the co-routine to implement a view. The first instance
+ ** is sufficient, though the subroutine to manifest the view does need
+ ** to be invoked again. */
if( pItem->addrFillSub ){
- sqlite3VdbeAddOp2(v, OP_Gosub, pItem->regReturn, pItem->addrFillSub);
+ if( pItem->viaCoroutine==0 ){
+ sqlite3VdbeAddOp2(v, OP_Gosub, pItem->regReturn, pItem->addrFillSub);
+ }
continue;
}
@@ -97490,6 +100187,44 @@ SQLITE_PRIVATE int sqlite3Select(
p->selFlags |= SF_Aggregate;
}
i = -1;
+ }else if( pTabList->nSrc==1 && (p->selFlags & SF_Materialize)==0
+ && OptimizationEnabled(db, SQLITE_SubqCoroutine)
+ ){
+ /* Implement a co-routine that will return a single row of the result
+ ** set on each invocation.
+ */
+ int addrTop;
+ int addrEof;
+ pItem->regReturn = ++pParse->nMem;
+ addrEof = ++pParse->nMem;
+ /* Before coding the OP_Goto to jump to the start of the main routine,
+ ** ensure that the jump to the verify-schema routine has already
+ ** been coded. Otherwise, the verify-schema would likely be coded as
+ ** part of the co-routine. If the main routine then accessed the
+ ** database before invoking the co-routine for the first time (for
+ ** example to initialize a LIMIT register from a sub-select), it would
+ ** be doing so without having verified the schema version and obtained
+ ** the required db locks. See ticket d6b36be38. */
+ sqlite3CodeVerifySchema(pParse, -1);
+ sqlite3VdbeAddOp0(v, OP_Goto);
+ addrTop = sqlite3VdbeAddOp1(v, OP_OpenPseudo, pItem->iCursor);
+ sqlite3VdbeChangeP5(v, 1);
+ VdbeComment((v, "coroutine for %s", pItem->pTab->zName));
+ pItem->addrFillSub = addrTop;
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, addrEof);
+ sqlite3VdbeChangeP5(v, 1);
+ sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
+ explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
+ sqlite3Select(pParse, pSub, &dest);
+ pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow;
+ pItem->viaCoroutine = 1;
+ sqlite3VdbeChangeP2(v, addrTop, dest.iSdst);
+ sqlite3VdbeChangeP3(v, addrTop, dest.nSdst);
+ sqlite3VdbeAddOp2(v, OP_Integer, 1, addrEof);
+ sqlite3VdbeAddOp1(v, OP_Yield, pItem->regReturn);
+ VdbeComment((v, "end %s", pItem->pTab->zName));
+ sqlite3VdbeJumpHere(v, addrTop-1);
+ sqlite3ClearTempRegCache(pParse);
}else{
/* Generate a subroutine that will fill an ephemeral table with
** the content of this subquery. pItem->addrFillSub will point
@@ -97505,7 +100240,7 @@ SQLITE_PRIVATE int sqlite3Select(
pItem->addrFillSub = topAddr+1;
VdbeNoopComment((v, "materialize %s", pItem->pTab->zName));
if( pItem->isCorrelated==0 ){
- /* If the subquery is no correlated and if we are not inside of
+ /* If the subquery is not correlated and if we are not inside of
** a trigger, then we only need to compute the value of the subquery
** once. */
onceAddr = sqlite3CodeOnce(pParse);
@@ -97534,7 +100269,7 @@ SQLITE_PRIVATE int sqlite3Select(
pWhere = p->pWhere;
pGroupBy = p->pGroupBy;
pHaving = p->pHaving;
- isDistinct = (p->selFlags & SF_Distinct)!=0;
+ sDistinct.isTnct = (p->selFlags & SF_Distinct)!=0;
#ifndef SQLITE_OMIT_COMPOUND_SELECT
/* If there is are a sequence of queries, do the earlier ones first.
@@ -97569,7 +100304,7 @@ SQLITE_PRIVATE int sqlite3Select(
** to disable this optimization for testing purposes.
*/
if( sqlite3ExprListCompare(p->pGroupBy, pOrderBy)==0
- && (db->flags & SQLITE_GroupByOrder)==0 ){
+ && OptimizationEnabled(db, SQLITE_GroupByOrder) ){
pOrderBy = 0;
}
@@ -97595,6 +100330,10 @@ SQLITE_PRIVATE int sqlite3Select(
p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0);
pGroupBy = p->pGroupBy;
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 */
+ assert( sDistinct.isTnct );
}
/* If there is an ORDER BY clause, then this sorting
@@ -97635,24 +100374,27 @@ SQLITE_PRIVATE int sqlite3Select(
/* Open a virtual index to use for the distinct set.
*/
if( p->selFlags & SF_Distinct ){
- KeyInfo *pKeyInfo;
- distinct = pParse->nTab++;
- pKeyInfo = keyInfoFromExprList(pParse, p->pEList);
- addrDistinctIndex = sqlite3VdbeAddOp4(v, OP_OpenEphemeral, distinct, 0, 0,
- (char*)pKeyInfo, P4_KEYINFO_HANDOFF);
+ sDistinct.tabTnct = pParse->nTab++;
+ sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
+ sDistinct.tabTnct, 0, 0,
+ (char*)keyInfoFromExprList(pParse, p->pEList),
+ P4_KEYINFO_HANDOFF);
sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
+ sDistinct.eTnctType = WHERE_DISTINCT_UNORDERED;
}else{
- distinct = addrDistinctIndex = -1;
+ sDistinct.eTnctType = WHERE_DISTINCT_NOOP;
}
- /* Aggregate and non-aggregate queries are handled differently */
if( !isAgg && pGroupBy==0 ){
- ExprList *pDist = (isDistinct ? p->pEList : 0);
+ /* No aggregate functions and no GROUP BY clause */
+ ExprList *pDist = (sDistinct.isTnct ? p->pEList : 0);
/* Begin the database scan. */
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy, pDist, 0,0);
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pOrderBy, pDist, 0,0);
if( pWInfo==0 ) goto select_end;
if( pWInfo->nRowOut < p->nSelectRow ) p->nSelectRow = pWInfo->nRowOut;
+ if( pWInfo->eDistinct ) sDistinct.eTnctType = pWInfo->eDistinct;
+ if( pOrderBy && pWInfo->nOBSat==pOrderBy->nExpr ) pOrderBy = 0;
/* If sorting index that was created by a prior OP_OpenEphemeral
** instruction ended up not being needed, then change the OP_OpenEphemeral
@@ -97663,59 +100405,16 @@ SQLITE_PRIVATE int sqlite3Select(
p->addrOpenEphm[2] = -1;
}
- if( pWInfo->eDistinct ){
- VdbeOp *pOp; /* No longer required OpenEphemeral instr. */
-
- assert( addrDistinctIndex>=0 );
- pOp = sqlite3VdbeGetOp(v, addrDistinctIndex);
-
- assert( isDistinct );
- assert( pWInfo->eDistinct==WHERE_DISTINCT_ORDERED
- || pWInfo->eDistinct==WHERE_DISTINCT_UNIQUE
- );
- distinct = -1;
- if( pWInfo->eDistinct==WHERE_DISTINCT_ORDERED ){
- int iJump;
- int iExpr;
- int iFlag = ++pParse->nMem;
- int iBase = pParse->nMem+1;
- int iBase2 = iBase + pEList->nExpr;
- pParse->nMem += (pEList->nExpr*2);
-
- /* Change the OP_OpenEphemeral coded earlier to an OP_Integer. The
- ** OP_Integer initializes the "first row" flag. */
- pOp->opcode = OP_Integer;
- pOp->p1 = 1;
- pOp->p2 = iFlag;
-
- sqlite3ExprCodeExprList(pParse, pEList, iBase, 1);
- iJump = sqlite3VdbeCurrentAddr(v) + 1 + pEList->nExpr + 1 + 1;
- sqlite3VdbeAddOp2(v, OP_If, iFlag, iJump-1);
- for(iExpr=0; iExpr<pEList->nExpr; iExpr++){
- CollSeq *pColl = sqlite3ExprCollSeq(pParse, pEList->a[iExpr].pExpr);
- sqlite3VdbeAddOp3(v, OP_Ne, iBase+iExpr, iJump, iBase2+iExpr);
- sqlite3VdbeChangeP4(v, -1, (const char *)pColl, P4_COLLSEQ);
- sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
- }
- sqlite3VdbeAddOp2(v, OP_Goto, 0, pWInfo->iContinue);
-
- sqlite3VdbeAddOp2(v, OP_Integer, 0, iFlag);
- assert( sqlite3VdbeCurrentAddr(v)==iJump );
- sqlite3VdbeAddOp3(v, OP_Move, iBase, iBase2, pEList->nExpr);
- }else{
- pOp->opcode = OP_Noop;
- }
- }
-
/* Use the standard inner loop. */
- selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, distinct, pDest,
+ selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, &sDistinct, pDest,
pWInfo->iContinue, pWInfo->iBreak);
/* End the database scan loop.
*/
sqlite3WhereEnd(pWInfo);
}else{
- /* This is the processing for aggregate queries */
+ /* This case when there exist aggregate functions or a GROUP BY clause
+ ** or both */
NameContext sNC; /* Name context for processing aggregate information */
int iAMem; /* First Mem address for storing current GROUP BY */
int iBMem; /* First Mem address for previous GROUP BY */
@@ -97823,14 +100522,13 @@ SQLITE_PRIVATE int sqlite3Select(
** in the right order to begin with.
*/
sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pGroupBy, 0, 0, 0);
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0, 0, 0);
if( pWInfo==0 ) goto select_end;
- if( pGroupBy==0 ){
+ if( pWInfo->nOBSat==pGroupBy->nExpr ){
/* The optimizer is able to deliver rows in group by order so
** we do not have to sort. The OP_OpenEphemeral table will be
** cancelled later because we still need to use the pKeyInfo
*/
- pGroupBy = p->pGroupBy;
groupBySort = 0;
}else{
/* Rows are coming out in undetermined order. We have to push
@@ -97844,7 +100542,8 @@ SQLITE_PRIVATE int sqlite3Select(
int nGroupBy;
explainTempTable(pParse,
- isDistinct && !(p->selFlags&SF_Distinct)?"DISTINCT":"GROUP BY");
+ (sDistinct.isTnct && (p->selFlags&SF_Distinct)==0) ?
+ "DISTINCT" : "GROUP BY");
groupBySort = 1;
nGroupBy = pGroupBy->nExpr;
@@ -97976,7 +100675,7 @@ SQLITE_PRIVATE int sqlite3Select(
finalizeAggFunctions(pParse, &sAggInfo);
sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL);
selectInnerLoop(pParse, p, p->pEList, 0, 0, pOrderBy,
- distinct, pDest,
+ &sDistinct, pDest,
addrOutputRow+1, addrSetAbort);
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
VdbeComment((v, "end groupby result generator"));
@@ -98064,7 +100763,7 @@ SQLITE_PRIVATE int sqlite3Select(
** value of x, the only row required).
**
** A special flag must be passed to sqlite3WhereBegin() to slightly
- ** modify behaviour as follows:
+ ** modify behavior as follows:
**
** + If the query is a "SELECT min(x)", then the loop coded by
** where.c should not iterate over any values with a NULL value
@@ -98076,10 +100775,17 @@ SQLITE_PRIVATE int sqlite3Select(
** Refer to code and comments in where.c for details.
*/
ExprList *pMinMax = 0;
- u8 flag = minMaxQuery(p);
+ u8 flag = WHERE_ORDERBY_NORMAL;
+
+ assert( p->pGroupBy==0 );
+ assert( flag==0 );
+ if( p->pHaving==0 ){
+ flag = minMaxQuery(&sAggInfo, &pMinMax);
+ }
+ assert( flag==0 || (pMinMax!=0 && pMinMax->nExpr==1) );
+
if( flag ){
- assert( !ExprHasProperty(p->pEList->a[0].pExpr, EP_xIsSelect) );
- pMinMax = sqlite3ExprListDup(db, p->pEList->a[0].pExpr->x.pList,0);
+ pMinMax = sqlite3ExprListDup(db, pMinMax, 0);
pDel = pMinMax;
if( pMinMax && !db->mallocFailed ){
pMinMax->a[0].sortOrder = flag!=WHERE_ORDERBY_MIN ?1:0;
@@ -98092,13 +100798,14 @@ SQLITE_PRIVATE int sqlite3Select(
** of output.
*/
resetAccumulator(pParse, &sAggInfo);
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pMinMax,0,flag,0);
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMax,0,flag,0);
if( pWInfo==0 ){
sqlite3ExprListDelete(db, pDel);
goto select_end;
}
updateAccumulator(pParse, &sAggInfo);
- if( !pMinMax && flag ){
+ assert( pMinMax==0 || pMinMax->nExpr==1 );
+ if( pWInfo->nOBSat>0 ){
sqlite3VdbeAddOp2(v, OP_Goto, 0, pWInfo->iBreak);
VdbeComment((v, "%s() by index",
(flag==WHERE_ORDERBY_MIN?"min":"max")));
@@ -98109,7 +100816,7 @@ SQLITE_PRIVATE int sqlite3Select(
pOrderBy = 0;
sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL);
- selectInnerLoop(pParse, p, p->pEList, 0, 0, 0, -1,
+ selectInnerLoop(pParse, p, p->pEList, 0, 0, 0, 0,
pDest, addrEnd, addrEnd);
sqlite3ExprListDelete(db, pDel);
}
@@ -98117,7 +100824,7 @@ SQLITE_PRIVATE int sqlite3Select(
} /* endif aggregate query */
- if( distinct>=0 ){
+ if( sDistinct.eTnctType==WHERE_DISTINCT_UNORDERED ){
explainTempTable(pParse, "DISTINCT");
}
@@ -98234,7 +100941,10 @@ SQLITE_PRIVATE void sqlite3ExplainSelect(Vdbe *pVdbe, Select *p){
sqlite3ExplainPrintf(pVdbe, "(null-select)");
return;
}
- while( p->pPrior ) p = p->pPrior;
+ while( p->pPrior ){
+ p->pPrior->pNext = p;
+ p = p->pPrior;
+ }
sqlite3ExplainPush(pVdbe);
while( p ){
explainOneSelect(pVdbe, p);
@@ -99182,6 +101892,15 @@ static int codeTriggerProgram(
*/
pParse->eOrconf = (orconf==OE_Default)?pStep->orconf:(u8)orconf;
+ /* Clear the cookieGoto flag. When coding triggers, the cookieGoto
+ ** variable is used as a flag to indicate to sqlite3ExprCodeConstants()
+ ** that it is not safe to refactor constants (this happens after the
+ ** start of the first loop in the SQL statement is coded - at that
+ ** point code may be conditionally executed, so it is no longer safe to
+ ** initialize constant register values). */
+ assert( pParse->cookieGoto==0 || pParse->cookieGoto==-1 );
+ pParse->cookieGoto = 0;
+
switch( pStep->op ){
case TK_UPDATE: {
sqlite3Update(pParse,
@@ -99787,6 +102506,7 @@ SQLITE_PRIVATE void sqlite3Update(
}
if( j>=pTab->nCol ){
if( sqlite3IsRowid(pChanges->a[i].zName) ){
+ j = -1;
chngRowid = 1;
pRowidExpr = pChanges->a[i].pExpr;
}else{
@@ -99799,7 +102519,8 @@ SQLITE_PRIVATE void sqlite3Update(
{
int rc;
rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab->zName,
- pTab->aCol[j].zName, db->aDb[iDb].zName);
+ j<0 ? "ROWID" : pTab->aCol[j].zName,
+ db->aDb[iDb].zName);
if( rc==SQLITE_DENY ){
goto update_cleanup;
}else if( rc==SQLITE_IGNORE ){
@@ -100037,7 +102758,7 @@ SQLITE_PRIVATE void sqlite3Update(
/* The row-trigger may have deleted the row being updated. In this
** case, jump to the next row. No updates or AFTER triggers are
- ** required. This behaviour - what happens when the row being updated
+ ** required. This behavior - what happens when the row being updated
** is deleted or renamed by a BEFORE trigger - is left undefined in the
** documentation.
*/
@@ -100338,6 +103059,7 @@ SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse){
Vdbe *v = sqlite3GetVdbe(pParse);
if( v ){
sqlite3VdbeAddOp2(v, OP_Vacuum, 0, 0);
+ sqlite3VdbeUsesBtree(v, 0);
}
return;
}
@@ -100541,6 +103263,7 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
BTREE_DEFAULT_CACHE_SIZE, 0, /* Preserve the default page cache size */
BTREE_TEXT_ENCODING, 0, /* Preserve the text encoding */
BTREE_USER_VERSION, 0, /* Preserve the user version */
+ BTREE_APPLICATION_ID, 0, /* Preserve the application id */
};
assert( 1==sqlite3BtreeIsInTrans(pTemp) );
@@ -100866,7 +103589,7 @@ SQLITE_PRIVATE void sqlite3VtabClear(sqlite3 *db, Table *p){
if( p->azModuleArg ){
int i;
for(i=0; i<p->nModuleArg; i++){
- sqlite3DbFree(db, p->azModuleArg[i]);
+ if( i!=1 ) sqlite3DbFree(db, p->azModuleArg[i]);
}
sqlite3DbFree(db, p->azModuleArg);
}
@@ -100926,7 +103649,7 @@ SQLITE_PRIVATE void sqlite3VtabBeginParse(
pTable->tabFlags |= TF_Virtual;
pTable->nModuleArg = 0;
addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName));
- addModuleArgument(db, pTable, sqlite3DbStrDup(db, db->aDb[iDb].zName));
+ addModuleArgument(db, pTable, 0);
addModuleArgument(db, pTable, sqlite3DbStrDup(db, pTable->zName));
pParse->sNameToken.n = (int)(&pModuleName->z[pModuleName->n] - pName1->z);
@@ -101083,6 +103806,7 @@ static int vtabCallConstructor(
int nArg = pTab->nModuleArg;
char *zErr = 0;
char *zModuleName = sqlite3MPrintf(db, "%s", pTab->zName);
+ int iDb;
if( !zModuleName ){
return SQLITE_NOMEM;
@@ -101096,6 +103820,9 @@ static int vtabCallConstructor(
pVTable->db = db;
pVTable->pMod = pMod;
+ iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
+ pTab->azModuleArg[1] = db->aDb[iDb].zName;
+
/* Invoke the virtual table constructor */
assert( &db->pVtabCtx );
assert( xConstruct );
@@ -101130,7 +103857,7 @@ static int vtabCallConstructor(
/* 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".
- ** If so, set the Column.isHidden flag and remove the token from
+ ** If so, set the Column COLFLAG_HIDDEN flag and remove the token from
** the type string. */
pVTable->pNext = pTab->pVTable;
pTab->pVTable = pVTable;
@@ -101161,7 +103888,7 @@ static int vtabCallConstructor(
assert(zType[i-1]==' ');
zType[i-1] = '\0';
}
- pTab->aCol[iCol].isHidden = 1;
+ pTab->aCol[iCol].colFlags |= COLFLAG_HIDDEN;
}
}
}
@@ -101722,9 +104449,10 @@ SQLITE_API int sqlite3_vtab_config(sqlite3 *db, int op, ...){
** Trace output macros
*/
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
-SQLITE_PRIVATE int sqlite3WhereTrace = 0;
+/***/ int sqlite3WhereTrace = 0;
#endif
-#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
+#if defined(SQLITE_DEBUG) \
+ && (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_WHERETRACE))
# define WHERETRACE(X) if(sqlite3WhereTrace) sqlite3DebugPrintf X
#else
# define WHERETRACE(X)
@@ -101796,8 +104524,8 @@ struct WhereTerm {
int leftCursor; /* Cursor number of X in "X <op> <expr>" */
union {
int leftColumn; /* Column number of X in "X <op> <expr>" */
- WhereOrInfo *pOrInfo; /* Extra information if eOperator==WO_OR */
- WhereAndInfo *pAndInfo; /* Extra information if eOperator==WO_AND */
+ WhereOrInfo *pOrInfo; /* Extra information if (eOperator & WO_OR)!=0 */
+ WhereAndInfo *pAndInfo; /* Extra information if (eOperator& WO_AND)!=0 */
} u;
u16 eOperator; /* A WO_xx value describing <op> */
u8 wtFlags; /* TERM_xxx bit flags. See below */
@@ -101838,7 +104566,6 @@ struct WhereTerm {
struct WhereClause {
Parse *pParse; /* The parser context */
WhereMaskSet *pMaskSet; /* Mapping of table cursor numbers to bitmasks */
- Bitmask vmask; /* Bitmask identifying virtual table cursors */
WhereClause *pOuter; /* Outer conjunction */
u8 op; /* Split operator. TK_AND or TK_OR */
u16 wctrlFlags; /* Might include WHERE_AND_ONLY */
@@ -101925,6 +104652,7 @@ struct WhereCost {
#define WO_ISNULL 0x080
#define WO_OR 0x100 /* Two or more OR-connected terms */
#define WO_AND 0x200 /* Two or more AND-connected terms */
+#define WO_EQUIV 0x400 /* Of the form A==B, both columns */
#define WO_NOOP 0x800 /* This term does not restrict search space */
#define WO_ALL 0xfff /* Mask of all possible WO_* values */
@@ -101951,18 +104679,55 @@ struct WhereCost {
#define WHERE_COLUMN_NULL 0x00080000 /* x IS NULL */
#define WHERE_INDEXED 0x000f0000 /* Anything that uses an index */
#define WHERE_NOT_FULLSCAN 0x100f3000 /* Does not do a full table scan */
-#define WHERE_IN_ABLE 0x000f1000 /* Able to support an IN operator */
+#define WHERE_IN_ABLE 0x080f1000 /* Able to support an IN operator */
#define WHERE_TOP_LIMIT 0x00100000 /* x<EXPR or x<=EXPR constraint */
#define WHERE_BTM_LIMIT 0x00200000 /* x>EXPR or x>=EXPR constraint */
#define WHERE_BOTH_LIMIT 0x00300000 /* Both x>EXPR and x<EXPR */
-#define WHERE_IDX_ONLY 0x00800000 /* Use index only - omit table */
-#define WHERE_ORDERBY 0x01000000 /* Output will appear in correct order */
-#define WHERE_REVERSE 0x02000000 /* Scan in reverse order */
-#define WHERE_UNIQUE 0x04000000 /* Selects no more than one row */
+#define WHERE_IDX_ONLY 0x00400000 /* Use index only - omit table */
+#define WHERE_ORDERED 0x00800000 /* Output will appear in correct order */
+#define WHERE_REVERSE 0x01000000 /* Scan in reverse order */
+#define WHERE_UNIQUE 0x02000000 /* Selects no more than one row */
+#define WHERE_ALL_UNIQUE 0x04000000 /* This and all prior have one row */
+#define WHERE_OB_UNIQUE 0x00004000 /* Values in ORDER BY columns are
+ ** different for every output row */
#define WHERE_VIRTUALTABLE 0x08000000 /* Use virtual-table processing */
#define WHERE_MULTI_OR 0x10000000 /* OR using multiple indices */
#define WHERE_TEMP_INDEX 0x20000000 /* Uses an ephemeral index */
#define WHERE_DISTINCT 0x40000000 /* Correct order for DISTINCT */
+#define WHERE_COVER_SCAN 0x80000000 /* Full scan of a covering index */
+
+/*
+** This module contains many separate subroutines that work together to
+** find the best indices to use for accessing a particular table in a query.
+** An instance of the following structure holds context information about the
+** index search so that it can be more easily passed between the various
+** routines.
+*/
+typedef struct WhereBestIdx WhereBestIdx;
+struct WhereBestIdx {
+ Parse *pParse; /* Parser context */
+ WhereClause *pWC; /* The WHERE clause */
+ struct SrcList_item *pSrc; /* The FROM clause term to search */
+ Bitmask notReady; /* Mask of cursors not available */
+ Bitmask notValid; /* Cursors not available for any purpose */
+ ExprList *pOrderBy; /* The ORDER BY clause */
+ ExprList *pDistinct; /* The select-list if query is DISTINCT */
+ sqlite3_index_info **ppIdxInfo; /* Index information passed to xBestIndex */
+ int i, n; /* Which loop is being coded; # of loops */
+ WhereLevel *aLevel; /* Info about outer loops */
+ WhereCost cost; /* Lowest cost query plan */
+};
+
+/*
+** Return TRUE if the probe cost is less than the baseline cost
+*/
+static int compareCost(const WhereCost *pProbe, const WhereCost *pBaseline){
+ if( pProbe->rCost<pBaseline->rCost ) return 1;
+ if( pProbe->rCost>pBaseline->rCost ) return 0;
+ if( pProbe->plan.nOBSat>pBaseline->plan.nOBSat ) return 1;
+ if( pProbe->plan.nRow<pBaseline->plan.nRow ) return 1;
+ return 0;
+}
/*
** Initialize a preallocated WhereClause structure.
@@ -101979,7 +104744,6 @@ static void whereClauseInit(
pWC->nTerm = 0;
pWC->nSlot = ArraySize(pWC->aStatic);
pWC->a = pWC->aStatic;
- pWC->vmask = 0;
pWC->wctrlFlags = wctrlFlags;
}
@@ -102066,7 +104830,7 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u8 wtFlags){
pWC->nSlot = sqlite3DbMallocSize(db, pWC->a)/sizeof(pWC->a[0]);
}
pTerm = &pWC->a[idx = pWC->nTerm++];
- pTerm->pExpr = p;
+ pTerm->pExpr = sqlite3ExprSkipCollate(p);
pTerm->wtFlags = wtFlags;
pTerm->pWC = pWC;
pTerm->iParent = -1;
@@ -102226,23 +104990,32 @@ static int allowedOp(int op){
** Commute a comparison operator. Expressions of the form "X op Y"
** are converted into "Y op X".
**
-** If a collation sequence is associated with either the left or right
+** If left/right precedence rules come into play when determining the
+** collating
** side of the comparison, it remains associated with the same side after
** the commutation. So "Y collate NOCASE op X" becomes
-** "X collate NOCASE op Y". This is because any collation sequence on
+** "X op Y". This is because any collation sequence on
** the left hand side of a comparison overrides any collation sequence
-** attached to the right. For the same reason the EP_ExpCollate flag
+** attached to the right. For the same reason the EP_Collate flag
** is not commuted.
*/
static void exprCommute(Parse *pParse, Expr *pExpr){
- u16 expRight = (pExpr->pRight->flags & EP_ExpCollate);
- u16 expLeft = (pExpr->pLeft->flags & EP_ExpCollate);
+ u16 expRight = (pExpr->pRight->flags & EP_Collate);
+ u16 expLeft = (pExpr->pLeft->flags & EP_Collate);
assert( allowedOp(pExpr->op) && pExpr->op!=TK_IN );
- pExpr->pRight->pColl = sqlite3ExprCollSeq(pParse, pExpr->pRight);
- pExpr->pLeft->pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
- SWAP(CollSeq*,pExpr->pRight->pColl,pExpr->pLeft->pColl);
- pExpr->pRight->flags = (pExpr->pRight->flags & ~EP_ExpCollate) | expLeft;
- pExpr->pLeft->flags = (pExpr->pLeft->flags & ~EP_ExpCollate) | expRight;
+ if( expRight==expLeft ){
+ /* Either X and Y both have COLLATE operator or neither do */
+ if( expRight ){
+ /* Both X and Y have COLLATE operators. Make sure X is always
+ ** used by clearing the EP_Collate flag from Y. */
+ pExpr->pRight->flags &= ~EP_Collate;
+ }else if( sqlite3ExprCollSeq(pParse, pExpr->pLeft)!=0 ){
+ /* Neither X nor Y have COLLATE operators, but X has a non-default
+ ** collating sequence. So add the EP_Collate marker on X to cause
+ ** it to be searched first. */
+ pExpr->pLeft->flags |= EP_Collate;
+ }
+ }
SWAP(Expr*,pExpr->pRight,pExpr->pLeft);
if( pExpr->op>=TK_GT ){
assert( TK_LT==TK_GT+2 );
@@ -102283,6 +105056,23 @@ static u16 operatorMask(int op){
** where X is a reference to the iColumn of table iCur and <op> is one of
** the WO_xx operator codes specified by the op parameter.
** Return a pointer to the term. Return 0 if not found.
+**
+** The term returned might by Y=<expr> if there is another constraint in
+** the WHERE clause that specifies that X=Y. Any such constraints will be
+** identified by the WO_EQUIV bit in the pTerm->eOperator field. The
+** aEquiv[] array holds X and all its equivalents, with each SQL variable
+** taking up two slots in aEquiv[]. The first slot is for the cursor number
+** and the second is for the column number. There are 22 slots in aEquiv[]
+** so that means we can look for X plus up to 10 other equivalent values.
+** Hence a search for X will return <expr> if X=A1 and A1=A2 and A2=A3
+** and ... and A9=A10 and A10=<expr>.
+**
+** If there are multiple terms in the WHERE clause of the form "X <op> <expr>"
+** then try for the one with no dependencies on <expr> - in other words where
+** <expr> is a constant expression of some kind. Only return entries of
+** the form "X <op> Y" where Y is a column in another table if no terms of
+** the form "X <op> <const-expr>" exist. If no terms with a constant RHS
+** exist, try to return a term that does not use WO_EQUIV.
*/
static WhereTerm *findTerm(
WhereClause *pWC, /* The WHERE clause to be searched */
@@ -102292,45 +105082,85 @@ static WhereTerm *findTerm(
u32 op, /* Mask of WO_xx values describing operator */
Index *pIdx /* Must be compatible with this index, if not NULL */
){
- WhereTerm *pTerm;
- int k;
+ WhereTerm *pTerm; /* Term being examined as possible result */
+ WhereTerm *pResult = 0; /* The answer to return */
+ WhereClause *pWCOrig = pWC; /* Original pWC value */
+ int j, k; /* Loop counters */
+ Expr *pX; /* Pointer to an expression */
+ Parse *pParse; /* Parsing context */
+ int iOrigCol = iColumn; /* Original value of iColumn */
+ int nEquiv = 2; /* Number of entires in aEquiv[] */
+ int iEquiv = 2; /* Number of entries of aEquiv[] processed so far */
+ int aEquiv[22]; /* iCur,iColumn and up to 10 other equivalents */
+
assert( iCur>=0 );
- op &= WO_ALL;
- for(; pWC; pWC=pWC->pOuter){
- for(pTerm=pWC->a, k=pWC->nTerm; k; k--, pTerm++){
- if( pTerm->leftCursor==iCur
- && (pTerm->prereqRight & notReady)==0
- && pTerm->u.leftColumn==iColumn
- && (pTerm->eOperator & op)!=0
- ){
- if( iColumn>=0 && pIdx && pTerm->eOperator!=WO_ISNULL ){
- Expr *pX = pTerm->pExpr;
- CollSeq *pColl;
- char idxaff;
- int j;
- Parse *pParse = pWC->pParse;
-
- idxaff = pIdx->pTable->aCol[iColumn].affinity;
- if( !sqlite3IndexAffinityOk(pX, idxaff) ) continue;
-
- /* Figure out the collation sequence required from an index for
- ** it to be useful for optimising expression pX. Store this
- ** value in variable pColl.
- */
- assert(pX->pLeft);
- pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight);
- assert(pColl || pParse->nErr);
-
- for(j=0; pIdx->aiColumn[j]!=iColumn; j++){
- if( NEVER(j>=pIdx->nColumn) ) return 0;
+ aEquiv[0] = iCur;
+ aEquiv[1] = iColumn;
+ for(;;){
+ for(pWC=pWCOrig; pWC; pWC=pWC->pOuter){
+ for(pTerm=pWC->a, k=pWC->nTerm; k; k--, pTerm++){
+ if( pTerm->leftCursor==iCur
+ && pTerm->u.leftColumn==iColumn
+ ){
+ if( (pTerm->prereqRight & notReady)==0
+ && (pTerm->eOperator & op & WO_ALL)!=0
+ ){
+ if( iOrigCol>=0 && pIdx && (pTerm->eOperator & WO_ISNULL)==0 ){
+ CollSeq *pColl;
+ char idxaff;
+
+ pX = pTerm->pExpr;
+ pParse = pWC->pParse;
+ idxaff = pIdx->pTable->aCol[iOrigCol].affinity;
+ if( !sqlite3IndexAffinityOk(pX, idxaff) ){
+ continue;
+ }
+
+ /* Figure out the collation sequence required from an index for
+ ** it to be useful for optimising expression pX. Store this
+ ** value in variable pColl.
+ */
+ assert(pX->pLeft);
+ pColl = sqlite3BinaryCompareCollSeq(pParse,pX->pLeft,pX->pRight);
+ if( pColl==0 ) pColl = pParse->db->pDfltColl;
+
+ for(j=0; pIdx->aiColumn[j]!=iOrigCol; j++){
+ if( NEVER(j>=pIdx->nColumn) ) return 0;
+ }
+ if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ){
+ continue;
+ }
+ }
+ if( pTerm->prereqRight==0 && (pTerm->eOperator&WO_EQ)!=0 ){
+ pResult = pTerm;
+ goto findTerm_success;
+ }else if( pResult==0 ){
+ pResult = pTerm;
+ }
+ }
+ if( (pTerm->eOperator & WO_EQUIV)!=0
+ && nEquiv<ArraySize(aEquiv)
+ ){
+ pX = sqlite3ExprSkipCollate(pTerm->pExpr->pRight);
+ assert( pX->op==TK_COLUMN );
+ for(j=0; j<nEquiv; j+=2){
+ if( aEquiv[j]==pX->iTable && aEquiv[j+1]==pX->iColumn ) break;
+ }
+ if( j==nEquiv ){
+ aEquiv[j] = pX->iTable;
+ aEquiv[j+1] = pX->iColumn;
+ nEquiv += 2;
+ }
}
- if( pColl && sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ) continue;
}
- return pTerm;
}
}
+ if( iEquiv>=nEquiv ) break;
+ iCur = aEquiv[iEquiv++];
+ iColumn = aEquiv[iEquiv++];
}
- return 0;
+findTerm_success:
+ return pResult;
}
/* Forward reference */
@@ -102516,7 +105346,7 @@ static void transferJoinMarkings(Expr *pDerived, Expr *pBase){
**
** CASE 1:
**
-** If all subterms are of the form T.C=expr for some single column of C
+** If all subterms are of the form T.C=expr for some single column of C and
** a single table T (as shown in example B above) then create a new virtual
** term that is an equivalent IN expression. In other words, if the term
** being analyzed is:
@@ -102604,11 +105434,10 @@ static void exprAnalyzeOrTerm(
** Compute the set of tables that might satisfy cases 1 or 2.
*/
indexable = ~(Bitmask)0;
- chngToIN = ~(pWC->vmask);
+ chngToIN = ~(Bitmask)0;
for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0 && indexable; i--, pOrTerm++){
if( (pOrTerm->eOperator & WO_SINGLE)==0 ){
WhereAndInfo *pAndInfo;
- assert( pOrTerm->eOperator==0 );
assert( (pOrTerm->wtFlags & (TERM_ANDINFO|TERM_ORINFO))==0 );
chngToIN = 0;
pAndInfo = sqlite3DbMallocRaw(db, sizeof(*pAndInfo));
@@ -102647,7 +105476,7 @@ static void exprAnalyzeOrTerm(
b |= getMask(pMaskSet, pOther->leftCursor);
}
indexable &= b;
- if( pOrTerm->eOperator!=WO_EQ ){
+ if( (pOrTerm->eOperator & WO_EQ)==0 ){
chngToIN = 0;
}else{
chngToIN &= b;
@@ -102698,7 +105527,7 @@ static void exprAnalyzeOrTerm(
for(j=0; j<2 && !okToChngToIN; j++){
pOrTerm = pOrWc->a;
for(i=pOrWc->nTerm-1; i>=0; i--, pOrTerm++){
- assert( pOrTerm->eOperator==WO_EQ );
+ assert( pOrTerm->eOperator & WO_EQ );
pOrTerm->wtFlags &= ~TERM_OR_OK;
if( pOrTerm->leftCursor==iCursor ){
/* This is the 2-bit case and we are on the second iteration and
@@ -102724,7 +105553,7 @@ static void exprAnalyzeOrTerm(
/* No candidate table+column was found. This can only occur
** on the second iteration */
assert( j==1 );
- assert( (chngToIN&(chngToIN-1))==0 );
+ assert( IsPowerOfTwo(chngToIN) );
assert( chngToIN==getMask(pMaskSet, iCursor) );
break;
}
@@ -102734,7 +105563,7 @@ static void exprAnalyzeOrTerm(
** table and column is common to every term in the OR clause */
okToChngToIN = 1;
for(; i>=0 && okToChngToIN; i--, pOrTerm++){
- assert( pOrTerm->eOperator==WO_EQ );
+ assert( pOrTerm->eOperator & WO_EQ );
if( pOrTerm->leftCursor!=iCursor ){
pOrTerm->wtFlags &= ~TERM_OR_OK;
}else if( pOrTerm->u.leftColumn!=iColumn ){
@@ -102770,7 +105599,7 @@ static void exprAnalyzeOrTerm(
for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0; i--, pOrTerm++){
if( (pOrTerm->wtFlags & TERM_OR_OK)==0 ) continue;
- assert( pOrTerm->eOperator==WO_EQ );
+ assert( pOrTerm->eOperator & WO_EQ );
assert( pOrTerm->leftCursor==iCursor );
assert( pOrTerm->u.leftColumn==iColumn );
pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight, 0);
@@ -102800,7 +105629,6 @@ static void exprAnalyzeOrTerm(
}
#endif /* !SQLITE_OMIT_OR_OPTIMIZATION && !SQLITE_OMIT_SUBQUERY */
-
/*
** The input to this routine is an WhereTerm structure with only the
** "pExpr" field filled in. The job of this routine is to analyze the
@@ -102843,6 +105671,7 @@ static void exprAnalyze(
pTerm = &pWC->a[idxTerm];
pMaskSet = pWC->pMaskSet;
pExpr = pTerm->pExpr;
+ assert( pExpr->op!=TK_AS && pExpr->op!=TK_COLLATE );
prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft);
op = pExpr->op;
if( op==TK_IN ){
@@ -102868,17 +105697,19 @@ static void exprAnalyze(
pTerm->leftCursor = -1;
pTerm->iParent = -1;
pTerm->eOperator = 0;
- if( allowedOp(op) && (pTerm->prereqRight & prereqLeft)==0 ){
- Expr *pLeft = pExpr->pLeft;
- Expr *pRight = pExpr->pRight;
+ if( allowedOp(op) ){
+ Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft);
+ Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight);
+ u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV;
if( pLeft->op==TK_COLUMN ){
pTerm->leftCursor = pLeft->iTable;
pTerm->u.leftColumn = pLeft->iColumn;
- pTerm->eOperator = operatorMask(op);
+ pTerm->eOperator = operatorMask(op) & opMask;
}
if( pRight && pRight->op==TK_COLUMN ){
WhereTerm *pNew;
Expr *pDup;
+ u16 eExtraOp = 0; /* Extra bits for pNew->eOperator */
if( pTerm->leftCursor>=0 ){
int idxNew;
pDup = sqlite3ExprDup(db, pExpr, 0);
@@ -102893,18 +105724,25 @@ static void exprAnalyze(
pTerm = &pWC->a[idxTerm];
pTerm->nChild = 1;
pTerm->wtFlags |= TERM_COPIED;
+ if( pExpr->op==TK_EQ
+ && !ExprHasProperty(pExpr, EP_FromJoin)
+ && OptimizationEnabled(db, SQLITE_Transitive)
+ ){
+ pTerm->eOperator |= WO_EQUIV;
+ eExtraOp = WO_EQUIV;
+ }
}else{
pDup = pExpr;
pNew = pTerm;
}
exprCommute(pParse, pDup);
- pLeft = pDup->pLeft;
+ pLeft = sqlite3ExprSkipCollate(pDup->pLeft);
pNew->leftCursor = pLeft->iTable;
pNew->u.leftColumn = pLeft->iColumn;
testcase( (prereqLeft | extraRight) != prereqLeft );
pNew->prereqRight = prereqLeft | extraRight;
pNew->prereqAll = prereqAll;
- pNew->eOperator = operatorMask(pDup->op);
+ pNew->eOperator = (operatorMask(pDup->op) + eExtraOp) & opMask;
}
}
@@ -102977,7 +105815,7 @@ static void exprAnalyze(
Expr *pNewExpr2;
int idxNew1;
int idxNew2;
- CollSeq *pColl; /* Collating sequence to use */
+ Token sCollSeqName; /* Name of collating sequence */
pLeft = pExpr->x.pList->a[1].pExpr;
pStr2 = sqlite3ExprDup(db, pStr1, 0);
@@ -102999,16 +105837,19 @@ static void exprAnalyze(
}
*pC = c + 1;
}
- pColl = sqlite3FindCollSeq(db, SQLITE_UTF8, noCase ? "NOCASE" : "BINARY",0);
+ sCollSeqName.z = noCase ? "NOCASE" : "BINARY";
+ sCollSeqName.n = 6;
+ pNewExpr1 = sqlite3ExprDup(db, pLeft, 0);
pNewExpr1 = sqlite3PExpr(pParse, TK_GE,
- sqlite3ExprSetColl(sqlite3ExprDup(db,pLeft,0), pColl),
- pStr1, 0);
+ sqlite3ExprAddCollateToken(pParse,pNewExpr1,&sCollSeqName),
+ pStr1, 0);
idxNew1 = whereClauseInsert(pWC, pNewExpr1, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew1==0 );
exprAnalyze(pSrc, pWC, idxNew1);
+ pNewExpr2 = sqlite3ExprDup(db, pLeft, 0);
pNewExpr2 = sqlite3PExpr(pParse, TK_LT,
- sqlite3ExprSetColl(sqlite3ExprDup(db,pLeft,0), pColl),
- pStr2, 0);
+ sqlite3ExprAddCollateToken(pParse,pNewExpr2,&sCollSeqName),
+ pStr2, 0);
idxNew2 = whereClauseInsert(pWC, pNewExpr2, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew2==0 );
exprAnalyze(pSrc, pWC, idxNew2);
@@ -103106,25 +105947,6 @@ static void exprAnalyze(
}
/*
-** Return TRUE if any of the expressions in pList->a[iFirst...] contain
-** a reference to any table other than the iBase table.
-*/
-static int referencesOtherTables(
- ExprList *pList, /* Search expressions in ths list */
- WhereMaskSet *pMaskSet, /* Mapping from tables to bitmaps */
- int iFirst, /* Be searching with the iFirst-th expression */
- int iBase /* Ignore references to this table */
-){
- Bitmask allowed = ~getMask(pMaskSet, iBase);
- while( iFirst<pList->nExpr ){
- if( (exprTableUsage(pMaskSet, pList->a[iFirst++].pExpr)&allowed)!=0 ){
- return 1;
- }
- }
- return 0;
-}
-
-/*
** This function searches the expression list passed as the second argument
** for an expression of type TK_COLUMN that refers to the same column and
** uses the same collation sequence as the iCol'th column of index pIdx.
@@ -103145,12 +105967,12 @@ static int findIndexCol(
const char *zColl = pIdx->azColl[iCol];
for(i=0; i<pList->nExpr; i++){
- Expr *p = pList->a[i].pExpr;
+ Expr *p = sqlite3ExprSkipCollate(pList->a[i].pExpr);
if( p->op==TK_COLUMN
&& p->iColumn==pIdx->aiColumn[iCol]
&& p->iTable==iBase
){
- CollSeq *pColl = sqlite3ExprCollSeq(pParse, p);
+ CollSeq *pColl = sqlite3ExprCollSeq(pParse, pList->a[i].pExpr);
if( ALWAYS(pColl) && 0==sqlite3StrICmp(pColl->zName, zColl) ){
return i;
}
@@ -103183,7 +106005,8 @@ static int isDistinctIndex(
Bitmask mask = 0; /* Mask of unaccounted for pDistinct exprs */
int i; /* Iterator variable */
- if( pIdx->zName==0 || pDistinct==0 || pDistinct->nExpr>=BMS ) return 0;
+ assert( pDistinct!=0 );
+ if( pIdx->zName==0 || pDistinct->nExpr>=BMS ) return 0;
testcase( pDistinct->nExpr==BMS-1 );
/* Loop through all the expressions in the distinct list. If any of them
@@ -103196,7 +106019,7 @@ static int isDistinctIndex(
*/
for(i=0; i<pDistinct->nExpr; i++){
WhereTerm *pTerm;
- Expr *p = pDistinct->a[i].pExpr;
+ Expr *p = sqlite3ExprSkipCollate(pDistinct->a[i].pExpr);
if( p->op!=TK_COLUMN ) return 0;
pTerm = findTerm(pWC, p->iTable, p->iColumn, ~(Bitmask)0, WO_EQ, 0);
if( pTerm ){
@@ -103248,7 +106071,7 @@ static int isDistinctRedundant(
** current SELECT is a correlated sub-query.
*/
for(i=0; i<pDistinct->nExpr; i++){
- Expr *p = pDistinct->a[i].pExpr;
+ Expr *p = sqlite3ExprSkipCollate(pDistinct->a[i].pExpr);
if( p->op==TK_COLUMN && p->iTable==iBase && p->iColumn<0 ) return 1;
}
@@ -103286,165 +106109,6 @@ static int isDistinctRedundant(
}
/*
-** This routine decides if pIdx can be used to satisfy the ORDER BY
-** clause. If it can, it returns 1. If pIdx cannot satisfy the
-** ORDER BY clause, this routine returns 0.
-**
-** pOrderBy is an ORDER BY clause from a SELECT statement. pTab is the
-** left-most table in the FROM clause of that same SELECT statement and
-** the table has a cursor number of "base". pIdx is an index on pTab.
-**
-** nEqCol is the number of columns of pIdx that are used as equality
-** constraints. Any of these columns may be missing from the ORDER BY
-** clause and the match can still be a success.
-**
-** All terms of the ORDER BY that match against the index must be either
-** ASC or DESC. (Terms of the ORDER BY clause past the end of a UNIQUE
-** index do not need to satisfy this constraint.) The *pbRev value is
-** set to 1 if the ORDER BY clause is all DESC and it is set to 0 if
-** the ORDER BY clause is all ASC.
-*/
-static int isSortingIndex(
- Parse *pParse, /* Parsing context */
- WhereMaskSet *pMaskSet, /* Mapping from table cursor numbers to bitmaps */
- Index *pIdx, /* The index we are testing */
- int base, /* Cursor number for the table to be sorted */
- ExprList *pOrderBy, /* The ORDER BY clause */
- int nEqCol, /* Number of index columns with == constraints */
- int wsFlags, /* Index usages flags */
- int *pbRev /* Set to 1 if ORDER BY is DESC */
-){
- int i, j; /* Loop counters */
- int sortOrder = 0; /* XOR of index and ORDER BY sort direction */
- int nTerm; /* Number of ORDER BY terms */
- struct ExprList_item *pTerm; /* A term of the ORDER BY clause */
- sqlite3 *db = pParse->db;
-
- if( !pOrderBy ) return 0;
- if( wsFlags & WHERE_COLUMN_IN ) return 0;
- if( pIdx->bUnordered ) return 0;
-
- nTerm = pOrderBy->nExpr;
- assert( nTerm>0 );
-
- /* Argument pIdx must either point to a 'real' named index structure,
- ** or an index structure allocated on the stack by bestBtreeIndex() to
- ** represent the rowid index that is part of every table. */
- assert( pIdx->zName || (pIdx->nColumn==1 && pIdx->aiColumn[0]==-1) );
-
- /* Match terms of the ORDER BY clause against columns of
- ** the index.
- **
- ** Note that indices have pIdx->nColumn regular columns plus
- ** one additional column containing the rowid. The rowid column
- ** of the index is also allowed to match against the ORDER BY
- ** clause.
- */
- for(i=j=0, pTerm=pOrderBy->a; j<nTerm && i<=pIdx->nColumn; i++){
- Expr *pExpr; /* The expression of the ORDER BY pTerm */
- CollSeq *pColl; /* The collating sequence of pExpr */
- int termSortOrder; /* Sort order for this term */
- int iColumn; /* The i-th column of the index. -1 for rowid */
- int iSortOrder; /* 1 for DESC, 0 for ASC on the i-th index term */
- const char *zColl; /* Name of the collating sequence for i-th index term */
-
- pExpr = pTerm->pExpr;
- if( pExpr->op!=TK_COLUMN || pExpr->iTable!=base ){
- /* Can not use an index sort on anything that is not a column in the
- ** left-most table of the FROM clause */
- break;
- }
- pColl = sqlite3ExprCollSeq(pParse, pExpr);
- if( !pColl ){
- pColl = db->pDfltColl;
- }
- if( pIdx->zName && i<pIdx->nColumn ){
- iColumn = pIdx->aiColumn[i];
- if( iColumn==pIdx->pTable->iPKey ){
- iColumn = -1;
- }
- iSortOrder = pIdx->aSortOrder[i];
- zColl = pIdx->azColl[i];
- }else{
- iColumn = -1;
- iSortOrder = 0;
- zColl = pColl->zName;
- }
- if( pExpr->iColumn!=iColumn || sqlite3StrICmp(pColl->zName, zColl) ){
- /* Term j of the ORDER BY clause does not match column i of the index */
- if( i<nEqCol ){
- /* If an index column that is constrained by == fails to match an
- ** ORDER BY term, that is OK. Just ignore that column of the index
- */
- continue;
- }else if( i==pIdx->nColumn ){
- /* Index column i is the rowid. All other terms match. */
- break;
- }else{
- /* If an index column fails to match and is not constrained by ==
- ** then the index cannot satisfy the ORDER BY constraint.
- */
- return 0;
- }
- }
- assert( pIdx->aSortOrder!=0 || iColumn==-1 );
- assert( pTerm->sortOrder==0 || pTerm->sortOrder==1 );
- assert( iSortOrder==0 || iSortOrder==1 );
- termSortOrder = iSortOrder ^ pTerm->sortOrder;
- if( i>nEqCol ){
- if( termSortOrder!=sortOrder ){
- /* Indices can only be used if all ORDER BY terms past the
- ** equality constraints are all either DESC or ASC. */
- return 0;
- }
- }else{
- sortOrder = termSortOrder;
- }
- j++;
- pTerm++;
- if( iColumn<0 && !referencesOtherTables(pOrderBy, pMaskSet, j, base) ){
- /* If the indexed column is the primary key and everything matches
- ** so far and none of the ORDER BY terms to the right reference other
- ** tables in the join, then we are assured that the index can be used
- ** to sort because the primary key is unique and so none of the other
- ** columns will make any difference
- */
- j = nTerm;
- }
- }
-
- *pbRev = sortOrder!=0;
- if( j>=nTerm ){
- /* All terms of the ORDER BY clause are covered by this index so
- ** this index can be used for sorting. */
- return 1;
- }
- if( pIdx->onError!=OE_None && i==pIdx->nColumn
- && (wsFlags & WHERE_COLUMN_NULL)==0
- && !referencesOtherTables(pOrderBy, pMaskSet, j, base)
- ){
- Column *aCol = pIdx->pTable->aCol;
-
- /* All terms of this index match some prefix of the ORDER BY clause,
- ** the index is UNIQUE, and no terms on the tail of the ORDER BY
- ** refer to other tables in a join. So, assuming that the index entries
- ** visited contain no NULL values, then this index delivers rows in
- ** the required order.
- **
- ** It is not possible for any of the first nEqCol index fields to be
- ** NULL (since the corresponding "=" operator in the WHERE clause would
- ** not be true). So if all remaining index columns have NOT NULL
- ** constaints attached to them, we can be confident that the visited
- ** index entries are free of NULLs. */
- for(i=nEqCol; i<pIdx->nColumn; i++){
- if( aCol[pIdx->aiColumn[i]].notNull==0 ) break;
- }
- return (i==pIdx->nColumn);
- }
- return 0;
-}
-
-/*
** Prepare a crude estimate of the logarithm of the input value.
** The results need not be exact. This is only used for estimating
** the total cost of performing operations with O(logN) or O(NlogN)
@@ -103508,9 +106172,7 @@ static void TRACE_IDX_OUTPUTS(sqlite3_index_info *p){
/*
** Required because bestIndex() is called by bestOrClauseIndex()
*/
-static void bestIndex(
- Parse*, WhereClause*, struct SrcList_item*,
- Bitmask, Bitmask, ExprList*, WhereCost*);
+static void bestIndex(WhereBestIdx*);
/*
** This routine attempts to find an scanning strategy that can be used
@@ -103519,20 +106181,14 @@ static void bestIndex(
** The table associated with FROM clause term pSrc may be either a
** regular B-Tree table or a virtual table.
*/
-static void bestOrClauseIndex(
- Parse *pParse, /* The parsing context */
- WhereClause *pWC, /* The WHERE clause */
- struct SrcList_item *pSrc, /* The FROM clause term to search */
- Bitmask notReady, /* Mask of cursors not available for indexing */
- Bitmask notValid, /* Cursors not available for any purpose */
- ExprList *pOrderBy, /* The ORDER BY clause */
- WhereCost *pCost /* Lowest cost query plan */
-){
+static void bestOrClauseIndex(WhereBestIdx *p){
#ifndef SQLITE_OMIT_OR_OPTIMIZATION
- const int iCur = pSrc->iCursor; /* The cursor of the table to be accessed */
+ WhereClause *pWC = p->pWC; /* The WHERE clause */
+ struct SrcList_item *pSrc = p->pSrc; /* The FROM clause term to search */
+ const int iCur = pSrc->iCursor; /* The cursor of the table */
const Bitmask maskSrc = getMask(pWC->pMaskSet, iCur); /* Bitmask for pSrc */
WhereTerm * const pWCEnd = &pWC->a[pWC->nTerm]; /* End of pWC->a[] */
- WhereTerm *pTerm; /* A single term of the WHERE clause */
+ WhereTerm *pTerm; /* A single term of the WHERE clause */
/* The OR-clause optimization is disallowed if the INDEXED BY or
** NOT INDEXED clauses are used or if the WHERE_AND_ONLY bit is set. */
@@ -103545,8 +106201,8 @@ static void bestOrClauseIndex(
/* Search the WHERE clause terms for a usable WO_OR term. */
for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
- if( pTerm->eOperator==WO_OR
- && ((pTerm->prereqAll & ~maskSrc) & notReady)==0
+ if( (pTerm->eOperator & WO_OR)!=0
+ && ((pTerm->prereqAll & ~maskSrc) & p->notReady)==0
&& (pTerm->u.pOrInfo->indexable & maskSrc)!=0
){
WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc;
@@ -103556,15 +106212,19 @@ static void bestOrClauseIndex(
double rTotal = 0;
double nRow = 0;
Bitmask used = 0;
+ WhereBestIdx sBOI;
+ sBOI = *p;
+ sBOI.pOrderBy = 0;
+ sBOI.pDistinct = 0;
+ sBOI.ppIdxInfo = 0;
for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){
- WhereCost sTermCost;
WHERETRACE(("... Multi-index OR testing for term %d of %d....\n",
(pOrTerm - pOrWC->a), (pTerm - pWC->a)
));
- if( pOrTerm->eOperator==WO_AND ){
- WhereClause *pAndWC = &pOrTerm->u.pAndInfo->wc;
- bestIndex(pParse, pAndWC, pSrc, notReady, notValid, 0, &sTermCost);
+ if( (pOrTerm->eOperator& WO_AND)!=0 ){
+ sBOI.pWC = &pOrTerm->u.pAndInfo->wc;
+ bestIndex(&sBOI);
}else if( pOrTerm->leftCursor==iCur ){
WhereClause tempWC;
tempWC.pParse = pWC->pParse;
@@ -103574,19 +106234,20 @@ static void bestOrClauseIndex(
tempWC.a = pOrTerm;
tempWC.wctrlFlags = 0;
tempWC.nTerm = 1;
- bestIndex(pParse, &tempWC, pSrc, notReady, notValid, 0, &sTermCost);
+ sBOI.pWC = &tempWC;
+ bestIndex(&sBOI);
}else{
continue;
}
- rTotal += sTermCost.rCost;
- nRow += sTermCost.plan.nRow;
- used |= sTermCost.used;
- if( rTotal>=pCost->rCost ) break;
+ rTotal += sBOI.cost.rCost;
+ nRow += sBOI.cost.plan.nRow;
+ used |= sBOI.cost.used;
+ if( rTotal>=p->cost.rCost ) break;
}
/* If there is an ORDER BY clause, increase the scan cost to account
** for the cost of the sort. */
- if( pOrderBy!=0 ){
+ if( p->pOrderBy!=0 ){
WHERETRACE(("... sorting increases OR cost %.9g to %.9g\n",
rTotal, rTotal+nRow*estLog(nRow)));
rTotal += nRow*estLog(nRow);
@@ -103596,12 +106257,13 @@ static void bestOrClauseIndex(
** less than the current cost stored in pCost, replace the contents
** of pCost. */
WHERETRACE(("... multi-index OR cost=%.9g nrow=%.9g\n", rTotal, nRow));
- if( rTotal<pCost->rCost ){
- pCost->rCost = rTotal;
- pCost->used = used;
- pCost->plan.nRow = nRow;
- pCost->plan.wsFlags = flags;
- pCost->plan.u.pTerm = pTerm;
+ if( rTotal<p->cost.rCost ){
+ p->cost.rCost = rTotal;
+ p->cost.used = used;
+ p->cost.plan.nRow = nRow;
+ p->cost.plan.nOBSat = p->i ? p->aLevel[p->i-1].plan.nOBSat : 0;
+ p->cost.plan.wsFlags = flags;
+ p->cost.plan.u.pTerm = pTerm;
}
}
}
@@ -103621,7 +106283,7 @@ static int termCanDriveIndex(
){
char aff;
if( pTerm->leftCursor!=pSrc->iCursor ) return 0;
- if( pTerm->eOperator!=WO_EQ ) return 0;
+ if( (pTerm->eOperator & WO_EQ)==0 ) return 0;
if( (pTerm->prereqRight & notReady)!=0 ) return 0;
aff = pSrc->pTab->aCol[pTerm->u.leftColumn].affinity;
if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0;
@@ -103638,15 +106300,12 @@ static int termCanDriveIndex(
** is taken into account, then alter the query plan to use the
** transient index.
*/
-static void bestAutomaticIndex(
- Parse *pParse, /* The parsing context */
- WhereClause *pWC, /* The WHERE clause */
- struct SrcList_item *pSrc, /* The FROM clause term to search */
- Bitmask notReady, /* Mask of cursors that are not available */
- WhereCost *pCost /* Lowest cost query plan */
-){
- double nTableRow; /* Rows in the input table */
- double logN; /* log(nTableRow) */
+static void bestAutomaticIndex(WhereBestIdx *p){
+ Parse *pParse = p->pParse; /* The parsing context */
+ WhereClause *pWC = p->pWC; /* The WHERE clause */
+ struct SrcList_item *pSrc = p->pSrc; /* The FROM clause term to search */
+ double nTableRow; /* Rows in the input table */
+ double logN; /* log(nTableRow) */
double costTempIdx; /* per-query cost of the transient index */
WhereTerm *pTerm; /* A single term of the WHERE clause */
WhereTerm *pWCEnd; /* End of pWC->a[] */
@@ -103660,10 +106319,16 @@ static void bestAutomaticIndex(
/* Automatic indices are disabled at run-time */
return;
}
- if( (pCost->plan.wsFlags & WHERE_NOT_FULLSCAN)!=0 ){
+ if( (p->cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0
+ && (p->cost.plan.wsFlags & WHERE_COVER_SCAN)==0
+ ){
/* We already have some kind of index in use for this query. */
return;
}
+ if( pSrc->viaCoroutine ){
+ /* Cannot index a co-routine */
+ return;
+ }
if( pSrc->notIndexed ){
/* The NOT INDEXED clause appears in the SQL. */
return;
@@ -103678,7 +106343,7 @@ static void bestAutomaticIndex(
nTableRow = pTable->nRowEst;
logN = estLog(nTableRow);
costTempIdx = 2*logN*(nTableRow/pParse->nQueryLoop + 1);
- if( costTempIdx>=pCost->rCost ){
+ if( costTempIdx>=p->cost.rCost ){
/* The cost of creating the transient table would be greater than
** doing the full table scan */
return;
@@ -103687,19 +106352,19 @@ static void bestAutomaticIndex(
/* Search for any equality comparison term */
pWCEnd = &pWC->a[pWC->nTerm];
for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
- if( termCanDriveIndex(pTerm, pSrc, notReady) ){
+ if( termCanDriveIndex(pTerm, pSrc, p->notReady) ){
WHERETRACE(("auto-index reduces cost from %.1f to %.1f\n",
- pCost->rCost, costTempIdx));
- pCost->rCost = costTempIdx;
- pCost->plan.nRow = logN + 1;
- pCost->plan.wsFlags = WHERE_TEMP_INDEX;
- pCost->used = pTerm->prereqRight;
+ p->cost.rCost, costTempIdx));
+ p->cost.rCost = costTempIdx;
+ p->cost.plan.nRow = logN + 1;
+ p->cost.plan.wsFlags = WHERE_TEMP_INDEX;
+ p->cost.used = pTerm->prereqRight;
break;
}
}
}
#else
-# define bestAutomaticIndex(A,B,C,D,E) /* no-op */
+# define bestAutomaticIndex(A) /* no-op */
#endif /* SQLITE_OMIT_AUTOMATIC_INDEX */
@@ -103860,12 +106525,11 @@ static void constructAutomaticIndex(
** responsibility of the caller to eventually release the structure
** by passing the pointer returned by this function to sqlite3_free().
*/
-static sqlite3_index_info *allocateIndexInfo(
- Parse *pParse,
- WhereClause *pWC,
- struct SrcList_item *pSrc,
- ExprList *pOrderBy
-){
+static sqlite3_index_info *allocateIndexInfo(WhereBestIdx *p){
+ Parse *pParse = p->pParse;
+ WhereClause *pWC = p->pWC;
+ struct SrcList_item *pSrc = p->pSrc;
+ ExprList *pOrderBy = p->pOrderBy;
int i, j;
int nTerm;
struct sqlite3_index_constraint *pIdxCons;
@@ -103881,10 +106545,10 @@ static sqlite3_index_info *allocateIndexInfo(
** to this virtual table */
for(i=nTerm=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
if( pTerm->leftCursor != pSrc->iCursor ) continue;
- assert( (pTerm->eOperator&(pTerm->eOperator-1))==0 );
- testcase( pTerm->eOperator==WO_IN );
- testcase( pTerm->eOperator==WO_ISNULL );
- if( pTerm->eOperator & (WO_IN|WO_ISNULL) ) continue;
+ assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) );
+ testcase( pTerm->eOperator & WO_IN );
+ testcase( pTerm->eOperator & WO_ISNULL );
+ if( pTerm->eOperator & (WO_ISNULL) ) continue;
if( pTerm->wtFlags & TERM_VNULL ) continue;
nTerm++;
}
@@ -103895,12 +106559,13 @@ static sqlite3_index_info *allocateIndexInfo(
*/
nOrderBy = 0;
if( pOrderBy ){
- for(i=0; i<pOrderBy->nExpr; i++){
+ int n = pOrderBy->nExpr;
+ for(i=0; i<n; i++){
Expr *pExpr = pOrderBy->a[i].pExpr;
if( pExpr->op!=TK_COLUMN || pExpr->iTable!=pSrc->iCursor ) break;
}
- if( i==pOrderBy->nExpr ){
- nOrderBy = pOrderBy->nExpr;
+ if( i==n){
+ nOrderBy = n;
}
}
@@ -103931,15 +106596,18 @@ static sqlite3_index_info *allocateIndexInfo(
pUsage;
for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
+ u8 op;
if( pTerm->leftCursor != pSrc->iCursor ) continue;
- assert( (pTerm->eOperator&(pTerm->eOperator-1))==0 );
- testcase( pTerm->eOperator==WO_IN );
- testcase( pTerm->eOperator==WO_ISNULL );
- if( pTerm->eOperator & (WO_IN|WO_ISNULL) ) continue;
+ assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) );
+ testcase( pTerm->eOperator & WO_IN );
+ testcase( pTerm->eOperator & WO_ISNULL );
+ if( pTerm->eOperator & (WO_ISNULL) ) continue;
if( pTerm->wtFlags & TERM_VNULL ) continue;
pIdxCons[j].iColumn = pTerm->u.leftColumn;
pIdxCons[j].iTermOffset = i;
- pIdxCons[j].op = (u8)pTerm->eOperator;
+ op = (u8)pTerm->eOperator & WO_ALL;
+ if( op==WO_IN ) op = WO_EQ;
+ pIdxCons[j].op = op;
/* The direct assignment in the previous line is possible only because
** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The
** following asserts verify this fact. */
@@ -103949,7 +106617,7 @@ static sqlite3_index_info *allocateIndexInfo(
assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT );
assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE );
assert( WO_MATCH==SQLITE_INDEX_CONSTRAINT_MATCH );
- assert( pTerm->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_MATCH) );
+ assert( pTerm->eOperator & (WO_IN|WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_MATCH) );
j++;
}
for(i=0; i<nOrderBy; i++){
@@ -104024,16 +106692,10 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
** routine takes care of freeing the sqlite3_index_info structure after
** everybody has finished with it.
*/
-static void bestVirtualIndex(
- Parse *pParse, /* The parsing context */
- WhereClause *pWC, /* The WHERE clause */
- struct SrcList_item *pSrc, /* The FROM clause term to search */
- Bitmask notReady, /* Mask of cursors not available for index */
- Bitmask notValid, /* Cursors not valid for any purpose */
- ExprList *pOrderBy, /* The order by clause */
- WhereCost *pCost, /* Lowest cost query plan */
- sqlite3_index_info **ppIdxInfo /* Index information passed to xBestIndex */
-){
+static void bestVirtualIndex(WhereBestIdx *p){
+ Parse *pParse = p->pParse; /* The parsing context */
+ WhereClause *pWC = p->pWC; /* The WHERE clause */
+ struct SrcList_item *pSrc = p->pSrc; /* The FROM clause term to search */
Table *pTab = pSrc->pTab;
sqlite3_index_info *pIdxInfo;
struct sqlite3_index_constraint *pIdxCons;
@@ -104041,21 +106703,22 @@ static void bestVirtualIndex(
WhereTerm *pTerm;
int i, j;
int nOrderBy;
+ int bAllowIN; /* Allow IN optimizations */
double rCost;
/* Make sure wsFlags is initialized to some sane value. Otherwise, if the
** malloc in allocateIndexInfo() fails and this function returns leaving
** wsFlags in an uninitialized state, the caller may behave unpredictably.
*/
- memset(pCost, 0, sizeof(*pCost));
- pCost->plan.wsFlags = WHERE_VIRTUALTABLE;
+ memset(&p->cost, 0, sizeof(p->cost));
+ p->cost.plan.wsFlags = WHERE_VIRTUALTABLE;
/* If the sqlite3_index_info structure has not been previously
** allocated and initialized, then allocate and initialize it now.
*/
- pIdxInfo = *ppIdxInfo;
+ pIdxInfo = *p->ppIdxInfo;
if( pIdxInfo==0 ){
- *ppIdxInfo = pIdxInfo = allocateIndexInfo(pParse, pWC, pSrc, pOrderBy);
+ *p->ppIdxInfo = pIdxInfo = allocateIndexInfo(p);
}
if( pIdxInfo==0 ){
return;
@@ -104075,65 +106738,112 @@ static void bestVirtualIndex(
assert( pTab->azModuleArg && pTab->azModuleArg[0] );
assert( sqlite3GetVTable(pParse->db, pTab) );
- /* Set the aConstraint[].usable fields and initialize all
- ** output variables to zero.
- **
- ** aConstraint[].usable is true for constraints where the right-hand
- ** side contains only references to tables to the left of the current
- ** table. In other words, if the constraint is of the form:
- **
- ** column = expr
- **
- ** and we are evaluating a join, then the constraint on column is
- ** only valid if all tables referenced in expr occur to the left
- ** of the table containing column.
- **
- ** The aConstraints[] array contains entries for all constraints
- ** on the current table. That way we only have to compute it once
- ** even though we might try to pick the best index multiple times.
- ** For each attempt at picking an index, the order of tables in the
- ** join might be different so we have to recompute the usable flag
- ** each time.
- */
- pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
- pUsage = pIdxInfo->aConstraintUsage;
- for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
- j = pIdxCons->iTermOffset;
- pTerm = &pWC->a[j];
- pIdxCons->usable = (pTerm->prereqRight¬Ready) ? 0 : 1;
- }
- memset(pUsage, 0, sizeof(pUsage[0])*pIdxInfo->nConstraint);
- if( pIdxInfo->needToFreeIdxStr ){
- sqlite3_free(pIdxInfo->idxStr);
- }
- pIdxInfo->idxStr = 0;
- pIdxInfo->idxNum = 0;
- pIdxInfo->needToFreeIdxStr = 0;
- pIdxInfo->orderByConsumed = 0;
- /* ((double)2) In case of SQLITE_OMIT_FLOATING_POINT... */
- pIdxInfo->estimatedCost = SQLITE_BIG_DBL / ((double)2);
- nOrderBy = pIdxInfo->nOrderBy;
- if( !pOrderBy ){
- pIdxInfo->nOrderBy = 0;
- }
-
- if( vtabBestIndex(pParse, pTab, pIdxInfo) ){
- return;
- }
+ /* Try once or twice. On the first attempt, allow IN optimizations.
+ ** If an IN optimization is accepted by the virtual table xBestIndex
+ ** method, but the pInfo->aConstrainUsage.omit flag is not set, then
+ ** the query will not work because it might allow duplicate rows in
+ ** output. In that case, run the xBestIndex method a second time
+ ** without the IN constraints. Usually this loop only runs once.
+ ** The loop will exit using a "break" statement.
+ */
+ for(bAllowIN=1; 1; bAllowIN--){
+ assert( bAllowIN==0 || bAllowIN==1 );
- pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
- for(i=0; i<pIdxInfo->nConstraint; i++){
- if( pUsage[i].argvIndex>0 ){
- pCost->used |= pWC->a[pIdxCons[i].iTermOffset].prereqRight;
+ /* Set the aConstraint[].usable fields and initialize all
+ ** output variables to zero.
+ **
+ ** aConstraint[].usable is true for constraints where the right-hand
+ ** side contains only references to tables to the left of the current
+ ** table. In other words, if the constraint is of the form:
+ **
+ ** column = expr
+ **
+ ** and we are evaluating a join, then the constraint on column is
+ ** only valid if all tables referenced in expr occur to the left
+ ** of the table containing column.
+ **
+ ** The aConstraints[] array contains entries for all constraints
+ ** on the current table. That way we only have to compute it once
+ ** even though we might try to pick the best index multiple times.
+ ** For each attempt at picking an index, the order of tables in the
+ ** join might be different so we have to recompute the usable flag
+ ** each time.
+ */
+ pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
+ pUsage = pIdxInfo->aConstraintUsage;
+ for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
+ j = pIdxCons->iTermOffset;
+ pTerm = &pWC->a[j];
+ if( (pTerm->prereqRight&p->notReady)==0
+ && (bAllowIN || (pTerm->eOperator & WO_IN)==0)
+ ){
+ pIdxCons->usable = 1;
+ }else{
+ pIdxCons->usable = 0;
+ }
+ }
+ memset(pUsage, 0, sizeof(pUsage[0])*pIdxInfo->nConstraint);
+ if( pIdxInfo->needToFreeIdxStr ){
+ sqlite3_free(pIdxInfo->idxStr);
+ }
+ pIdxInfo->idxStr = 0;
+ pIdxInfo->idxNum = 0;
+ pIdxInfo->needToFreeIdxStr = 0;
+ pIdxInfo->orderByConsumed = 0;
+ /* ((double)2) In case of SQLITE_OMIT_FLOATING_POINT... */
+ pIdxInfo->estimatedCost = SQLITE_BIG_DBL / ((double)2);
+ nOrderBy = pIdxInfo->nOrderBy;
+ if( !p->pOrderBy ){
+ pIdxInfo->nOrderBy = 0;
+ }
+
+ if( vtabBestIndex(pParse, pTab, pIdxInfo) ){
+ return;
+ }
+
+ pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
+ for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
+ if( pUsage[i].argvIndex>0 ){
+ j = pIdxCons->iTermOffset;
+ pTerm = &pWC->a[j];
+ p->cost.used |= pTerm->prereqRight;
+ if( (pTerm->eOperator & WO_IN)!=0 ){
+ if( pUsage[i].omit==0 ){
+ /* Do not attempt to use an IN constraint if the virtual table
+ ** says that the equivalent EQ constraint cannot be safely omitted.
+ ** If we do attempt to use such a constraint, some rows might be
+ ** repeated in the output. */
+ break;
+ }
+ /* A virtual table that is constrained by an IN clause may not
+ ** consume the ORDER BY clause because (1) the order of IN terms
+ ** is not necessarily related to the order of output terms and
+ ** (2) Multiple outputs from a single IN value will not merge
+ ** together. */
+ pIdxInfo->orderByConsumed = 0;
+ }
+ }
}
+ if( i>=pIdxInfo->nConstraint ) break;
}
+ /* The orderByConsumed signal is only valid if all outer loops collectively
+ ** generate just a single row of output.
+ */
+ if( pIdxInfo->orderByConsumed ){
+ for(i=0; i<p->i; i++){
+ if( (p->aLevel[i].plan.wsFlags & WHERE_UNIQUE)==0 ){
+ pIdxInfo->orderByConsumed = 0;
+ }
+ }
+ }
+
/* If there is an ORDER BY clause, and the selected virtual table index
** does not satisfy it, increase the cost of the scan accordingly. This
** matches the processing for non-virtual tables in bestBtreeIndex().
*/
rCost = pIdxInfo->estimatedCost;
- if( pOrderBy && pIdxInfo->orderByConsumed==0 ){
+ if( p->pOrderBy && pIdxInfo->orderByConsumed==0 ){
rCost += estLog(rCost)*rCost;
}
@@ -104145,21 +106855,24 @@ static void bestVirtualIndex(
** is defined.
*/
if( (SQLITE_BIG_DBL/((double)2))<rCost ){
- pCost->rCost = (SQLITE_BIG_DBL/((double)2));
+ p->cost.rCost = (SQLITE_BIG_DBL/((double)2));
}else{
- pCost->rCost = rCost;
+ p->cost.rCost = rCost;
}
- pCost->plan.u.pVtabIdx = pIdxInfo;
+ p->cost.plan.u.pVtabIdx = pIdxInfo;
if( pIdxInfo->orderByConsumed ){
- pCost->plan.wsFlags |= WHERE_ORDERBY;
+ p->cost.plan.wsFlags |= WHERE_ORDERED;
+ p->cost.plan.nOBSat = nOrderBy;
+ }else{
+ p->cost.plan.nOBSat = p->i ? p->aLevel[p->i-1].plan.nOBSat : 0;
}
- pCost->plan.nEq = 0;
+ p->cost.plan.nEq = 0;
pIdxInfo->nOrderBy = nOrderBy;
/* Try to find a more efficient access pattern by using multiple indexes
** to optimize an OR expression within the WHERE clause.
*/
- bestOrClauseIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost);
+ bestOrClauseIndex(p);
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -104247,10 +106960,8 @@ static int whereKeyStats(
pColl = db->pDfltColl;
assert( pColl->enc==SQLITE_UTF8 );
}else{
- pColl = sqlite3GetCollSeq(db, SQLITE_UTF8, 0, *pIdx->azColl);
+ pColl = sqlite3GetCollSeq(pParse, SQLITE_UTF8, 0, *pIdx->azColl);
if( pColl==0 ){
- sqlite3ErrorMsg(pParse, "no such collation sequence: %s",
- *pIdx->azColl);
return SQLITE_ERROR;
}
z = (const u8 *)sqlite3ValueText(pVal, pColl->enc);
@@ -104421,24 +107132,24 @@ static int whereRangeScanEst(
if( pLower ){
Expr *pExpr = pLower->pExpr->pRight;
rc = valueFromExpr(pParse, pExpr, aff, &pRangeVal);
- assert( pLower->eOperator==WO_GT || pLower->eOperator==WO_GE );
+ assert( (pLower->eOperator & (WO_GT|WO_GE))!=0 );
if( rc==SQLITE_OK
&& whereKeyStats(pParse, p, pRangeVal, 0, a)==SQLITE_OK
){
iLower = a[0];
- if( pLower->eOperator==WO_GT ) iLower += a[1];
+ if( (pLower->eOperator & WO_GT)!=0 ) iLower += a[1];
}
sqlite3ValueFree(pRangeVal);
}
if( rc==SQLITE_OK && pUpper ){
Expr *pExpr = pUpper->pExpr->pRight;
rc = valueFromExpr(pParse, pExpr, aff, &pRangeVal);
- assert( pUpper->eOperator==WO_LT || pUpper->eOperator==WO_LE );
+ assert( (pUpper->eOperator & (WO_LT|WO_LE))!=0 );
if( rc==SQLITE_OK
&& whereKeyStats(pParse, p, pRangeVal, 1, a)==SQLITE_OK
){
iUpper = a[0];
- if( pUpper->eOperator==WO_LE ) iUpper += a[1];
+ if( (pUpper->eOperator & WO_LE)!=0 ) iUpper += a[1];
}
sqlite3ValueFree(pRangeVal);
}
@@ -104558,11 +107269,295 @@ static int whereInScanEst(
}
#endif /* defined(SQLITE_ENABLE_STAT3) */
+/*
+** Check to see if column iCol of the table with cursor iTab will appear
+** in sorted order according to the current query plan.
+**
+** Return values:
+**
+** 0 iCol is not ordered
+** 1 iCol has only a single value
+** 2 iCol is in ASC order
+** 3 iCol is in DESC order
+*/
+static int isOrderedColumn(
+ WhereBestIdx *p,
+ int iTab,
+ int iCol
+){
+ int i, j;
+ WhereLevel *pLevel = &p->aLevel[p->i-1];
+ Index *pIdx;
+ u8 sortOrder;
+ for(i=p->i-1; i>=0; i--, pLevel--){
+ if( pLevel->iTabCur!=iTab ) continue;
+ if( (pLevel->plan.wsFlags & WHERE_ALL_UNIQUE)!=0 ){
+ return 1;
+ }
+ assert( (pLevel->plan.wsFlags & WHERE_ORDERED)!=0 );
+ if( (pIdx = pLevel->plan.u.pIdx)!=0 ){
+ if( iCol<0 ){
+ sortOrder = 0;
+ testcase( (pLevel->plan.wsFlags & WHERE_REVERSE)!=0 );
+ }else{
+ int n = pIdx->nColumn;
+ for(j=0; j<n; j++){
+ if( iCol==pIdx->aiColumn[j] ) break;
+ }
+ if( j>=n ) return 0;
+ sortOrder = pIdx->aSortOrder[j];
+ testcase( (pLevel->plan.wsFlags & WHERE_REVERSE)!=0 );
+ }
+ }else{
+ if( iCol!=(-1) ) return 0;
+ sortOrder = 0;
+ testcase( (pLevel->plan.wsFlags & WHERE_REVERSE)!=0 );
+ }
+ if( (pLevel->plan.wsFlags & WHERE_REVERSE)!=0 ){
+ assert( sortOrder==0 || sortOrder==1 );
+ testcase( sortOrder==1 );
+ sortOrder = 1 - sortOrder;
+ }
+ return sortOrder+2;
+ }
+ return 0;
+}
+
+/*
+** This routine decides if pIdx can be used to satisfy the ORDER BY
+** clause, either in whole or in part. The return value is the
+** cumulative number of terms in the ORDER BY clause that are satisfied
+** by the index pIdx and other indices in outer loops.
+**
+** The table being queried has a cursor number of "base". pIdx is the
+** index that is postulated for use to access the table.
+**
+** The *pbRev value is set to 0 order 1 depending on whether or not
+** pIdx should be run in the forward order or in reverse order.
+*/
+static int isSortingIndex(
+ WhereBestIdx *p, /* Best index search context */
+ Index *pIdx, /* The index we are testing */
+ int base, /* Cursor number for the table to be sorted */
+ int *pbRev, /* Set to 1 for reverse-order scan of pIdx */
+ int *pbObUnique /* ORDER BY column values will different in every row */
+){
+ int i; /* Number of pIdx terms used */
+ int j; /* Number of ORDER BY terms satisfied */
+ int sortOrder = 2; /* 0: forward. 1: backward. 2: unknown */
+ int nTerm; /* Number of ORDER BY terms */
+ struct ExprList_item *pOBItem;/* A term of the ORDER BY clause */
+ Table *pTab = pIdx->pTable; /* Table that owns index pIdx */
+ ExprList *pOrderBy; /* The ORDER BY clause */
+ Parse *pParse = p->pParse; /* Parser context */
+ sqlite3 *db = pParse->db; /* Database connection */
+ int nPriorSat; /* ORDER BY terms satisfied by outer loops */
+ int seenRowid = 0; /* True if an ORDER BY rowid term is seen */
+ int uniqueNotNull; /* pIdx is UNIQUE with all terms are NOT NULL */
+ int outerObUnique; /* Outer loops generate different values in
+ ** every row for the ORDER BY columns */
+
+ if( p->i==0 ){
+ nPriorSat = 0;
+ outerObUnique = 1;
+ }else{
+ u32 wsFlags = p->aLevel[p->i-1].plan.wsFlags;
+ nPriorSat = p->aLevel[p->i-1].plan.nOBSat;
+ if( (wsFlags & WHERE_ORDERED)==0 ){
+ /* This loop cannot be ordered unless the next outer loop is
+ ** also ordered */
+ return nPriorSat;
+ }
+ if( OptimizationDisabled(db, SQLITE_OrderByIdxJoin) ){
+ /* Only look at the outer-most loop if the OrderByIdxJoin
+ ** optimization is disabled */
+ return nPriorSat;
+ }
+ testcase( wsFlags & WHERE_OB_UNIQUE );
+ testcase( wsFlags & WHERE_ALL_UNIQUE );
+ outerObUnique = (wsFlags & (WHERE_OB_UNIQUE|WHERE_ALL_UNIQUE))!=0;
+ }
+ pOrderBy = p->pOrderBy;
+ assert( pOrderBy!=0 );
+ if( pIdx->bUnordered ){
+ /* Hash indices (indicated by the "unordered" tag on sqlite_stat1) cannot
+ ** be used for sorting */
+ return nPriorSat;
+ }
+ nTerm = pOrderBy->nExpr;
+ uniqueNotNull = pIdx->onError!=OE_None;
+ assert( nTerm>0 );
+
+ /* Argument pIdx must either point to a 'real' named index structure,
+ ** or an index structure allocated on the stack by bestBtreeIndex() to
+ ** represent the rowid index that is part of every table. */
+ assert( pIdx->zName || (pIdx->nColumn==1 && pIdx->aiColumn[0]==-1) );
+
+ /* Match terms of the ORDER BY clause against columns of
+ ** the index.
+ **
+ ** Note that indices have pIdx->nColumn regular columns plus
+ ** one additional column containing the rowid. The rowid column
+ ** of the index is also allowed to match against the ORDER BY
+ ** clause.
+ */
+ j = nPriorSat;
+ for(i=0,pOBItem=&pOrderBy->a[j]; j<nTerm && i<=pIdx->nColumn; i++){
+ Expr *pOBExpr; /* The expression of the ORDER BY pOBItem */
+ CollSeq *pColl; /* The collating sequence of pOBExpr */
+ int termSortOrder; /* Sort order for this term */
+ int iColumn; /* The i-th column of the index. -1 for rowid */
+ int iSortOrder; /* 1 for DESC, 0 for ASC on the i-th index term */
+ int isEq; /* Subject to an == or IS NULL constraint */
+ int isMatch; /* ORDER BY term matches the index term */
+ const char *zColl; /* Name of collating sequence for i-th index term */
+ WhereTerm *pConstraint; /* A constraint in the WHERE clause */
+
+ /* If the next term of the ORDER BY clause refers to anything other than
+ ** a column in the "base" table, then this index will not be of any
+ ** further use in handling the ORDER BY. */
+ pOBExpr = sqlite3ExprSkipCollate(pOBItem->pExpr);
+ if( pOBExpr->op!=TK_COLUMN || pOBExpr->iTable!=base ){
+ break;
+ }
+
+ /* Find column number and collating sequence for the next entry
+ ** in the index */
+ if( pIdx->zName && i<pIdx->nColumn ){
+ iColumn = pIdx->aiColumn[i];
+ if( iColumn==pIdx->pTable->iPKey ){
+ iColumn = -1;
+ }
+ iSortOrder = pIdx->aSortOrder[i];
+ zColl = pIdx->azColl[i];
+ assert( zColl!=0 );
+ }else{
+ iColumn = -1;
+ iSortOrder = 0;
+ zColl = 0;
+ }
+
+ /* Check to see if the column number and collating sequence of the
+ ** index match the column number and collating sequence of the ORDER BY
+ ** clause entry. Set isMatch to 1 if they both match. */
+ if( pOBExpr->iColumn==iColumn ){
+ if( zColl ){
+ pColl = sqlite3ExprCollSeq(pParse, pOBItem->pExpr);
+ if( !pColl ) pColl = db->pDfltColl;
+ isMatch = sqlite3StrICmp(pColl->zName, zColl)==0;
+ }else{
+ isMatch = 1;
+ }
+ }else{
+ isMatch = 0;
+ }
+
+ /* termSortOrder is 0 or 1 for whether or not the access loop should
+ ** run forward or backwards (respectively) in order to satisfy this
+ ** term of the ORDER BY clause. */
+ assert( pOBItem->sortOrder==0 || pOBItem->sortOrder==1 );
+ assert( iSortOrder==0 || iSortOrder==1 );
+ termSortOrder = iSortOrder ^ pOBItem->sortOrder;
+
+ /* If X is the column in the index and ORDER BY clause, check to see
+ ** if there are any X= or X IS NULL constraints in the WHERE clause. */
+ pConstraint = findTerm(p->pWC, base, iColumn, p->notReady,
+ WO_EQ|WO_ISNULL|WO_IN, pIdx);
+ if( pConstraint==0 ){
+ isEq = 0;
+ }else if( (pConstraint->eOperator & WO_IN)!=0 ){
+ isEq = 0;
+ }else if( (pConstraint->eOperator & WO_ISNULL)!=0 ){
+ uniqueNotNull = 0;
+ isEq = 1; /* "X IS NULL" means X has only a single value */
+ }else if( pConstraint->prereqRight==0 ){
+ isEq = 1; /* Constraint "X=constant" means X has only a single value */
+ }else{
+ Expr *pRight = pConstraint->pExpr->pRight;
+ if( pRight->op==TK_COLUMN ){
+ WHERETRACE((" .. isOrderedColumn(tab=%d,col=%d)",
+ pRight->iTable, pRight->iColumn));
+ isEq = isOrderedColumn(p, pRight->iTable, pRight->iColumn);
+ WHERETRACE((" -> isEq=%d\n", isEq));
+
+ /* If the constraint is of the form X=Y where Y is an ordered value
+ ** in an outer loop, then make sure the sort order of Y matches the
+ ** sort order required for X. */
+ if( isMatch && isEq>=2 && isEq!=pOBItem->sortOrder+2 ){
+ testcase( isEq==2 );
+ testcase( isEq==3 );
+ break;
+ }
+ }else{
+ isEq = 0; /* "X=expr" places no ordering constraints on X */
+ }
+ }
+ if( !isMatch ){
+ if( isEq==0 ){
+ break;
+ }else{
+ continue;
+ }
+ }else if( isEq!=1 ){
+ if( sortOrder==2 ){
+ sortOrder = termSortOrder;
+ }else if( termSortOrder!=sortOrder ){
+ break;
+ }
+ }
+ j++;
+ pOBItem++;
+ if( iColumn<0 ){
+ seenRowid = 1;
+ break;
+ }else if( pTab->aCol[iColumn].notNull==0 && isEq!=1 ){
+ testcase( isEq==0 );
+ testcase( isEq==2 );
+ testcase( isEq==3 );
+ uniqueNotNull = 0;
+ }
+ }
+ if( seenRowid ){
+ uniqueNotNull = 1;
+ }else if( uniqueNotNull==0 || i<pIdx->nColumn ){
+ uniqueNotNull = 0;
+ }
+
+ /* If we have not found at least one ORDER BY term that matches the
+ ** index, then show no progress. */
+ if( pOBItem==&pOrderBy->a[nPriorSat] ) return nPriorSat;
+
+ /* Either the outer queries must generate rows where there are no two
+ ** rows with the same values in all ORDER BY columns, or else this
+ ** loop must generate just a single row of output. Example: Suppose
+ ** the outer loops generate A=1 and A=1, and this loop generates B=3
+ ** and B=4. Then without the following test, ORDER BY A,B would
+ ** generate the wrong order output: 1,3 1,4 1,3 1,4
+ */
+ if( outerObUnique==0 && uniqueNotNull==0 ) return nPriorSat;
+ *pbObUnique = uniqueNotNull;
+
+ /* Return the necessary scan order back to the caller */
+ *pbRev = sortOrder & 1;
+
+ /* If there was an "ORDER BY rowid" term that matched, or it is only
+ ** possible for a single row from this table to match, then skip over
+ ** any additional ORDER BY terms dealing with this table.
+ */
+ if( uniqueNotNull ){
+ /* Advance j over additional ORDER BY terms associated with base */
+ WhereMaskSet *pMS = p->pWC->pMaskSet;
+ Bitmask m = ~getMask(pMS, base);
+ while( j<nTerm && (exprTableUsage(pMS, pOrderBy->a[j].pExpr)&m)==0 ){
+ j++;
+ }
+ }
+ return j;
+}
/*
** Find the best query plan for accessing a particular table. Write the
-** best query plan and its cost into the WhereCost object supplied as the
-** last parameter.
+** best query plan and its cost into the p->cost.
**
** The lowest cost plan wins. The cost is an estimate of the amount of
** CPU and disk I/O needed to process the requested result.
@@ -104582,21 +107577,15 @@ static int whereInScanEst(
** SQLITE_BIG_DBL. If a plan is found that uses the named index,
** then the cost is calculated in the usual way.
**
-** If a NOT INDEXED clause (pSrc->notIndexed!=0) was attached to the table
+** If a NOT INDEXED clause was attached to the table
** in the SELECT statement, then no indexes are considered. However, the
** selected plan may still take advantage of the built-in rowid primary key
** index.
*/
-static void bestBtreeIndex(
- Parse *pParse, /* The parsing context */
- WhereClause *pWC, /* The WHERE clause */
- struct SrcList_item *pSrc, /* The FROM clause term to search */
- Bitmask notReady, /* Mask of cursors not available for indexing */
- Bitmask notValid, /* Cursors not available for any purpose */
- ExprList *pOrderBy, /* The ORDER BY clause */
- ExprList *pDistinct, /* The select-list if query is DISTINCT */
- WhereCost *pCost /* Lowest cost query plan */
-){
+static void bestBtreeIndex(WhereBestIdx *p){
+ Parse *pParse = p->pParse; /* The parsing context */
+ WhereClause *pWC = p->pWC; /* The WHERE clause */
+ struct SrcList_item *pSrc = p->pSrc; /* The FROM clause term to search */
int iCur = pSrc->iCursor; /* The cursor of the table to be accessed */
Index *pProbe; /* An index we are evaluating */
Index *pIdx; /* Copy of pProbe, or zero for IPK index */
@@ -104605,11 +107594,16 @@ static void bestBtreeIndex(
Index sPk; /* A fake index object for the primary key */
tRowcnt aiRowEstPk[2]; /* The aiRowEst[] value for the sPk index */
int aiColumnPk = -1; /* The aColumn[] value for the sPk index */
- int wsFlagMask; /* Allowed flags in pCost->plan.wsFlag */
+ int wsFlagMask; /* Allowed flags in p->cost.plan.wsFlag */
+ int nPriorSat; /* ORDER BY terms satisfied by outer loops */
+ int nOrderBy; /* Number of ORDER BY terms */
+ char bSortInit; /* Initializer for bSort in inner loop */
+ char bDistInit; /* Initializer for bDist in inner loop */
+
/* Initialize the cost to a worst-case value */
- memset(pCost, 0, sizeof(*pCost));
- pCost->rCost = SQLITE_BIG_DBL;
+ memset(&p->cost, 0, sizeof(p->cost));
+ p->cost.rCost = SQLITE_BIG_DBL;
/* If the pSrc table is the right table of a LEFT JOIN then we may not
** use an index to satisfy IS NULL constraints on that table. This is
@@ -104655,22 +107649,29 @@ static void bestBtreeIndex(
pIdx = 0;
}
+ nOrderBy = p->pOrderBy ? p->pOrderBy->nExpr : 0;
+ if( p->i ){
+ nPriorSat = p->aLevel[p->i-1].plan.nOBSat;
+ bSortInit = nPriorSat<nOrderBy;
+ bDistInit = 0;
+ }else{
+ nPriorSat = 0;
+ bSortInit = nOrderBy>0;
+ bDistInit = p->pDistinct!=0;
+ }
+
/* Loop over all indices looking for the best one to use
*/
for(; pProbe; pIdx=pProbe=pProbe->pNext){
const tRowcnt * const aiRowEst = pProbe->aiRowEst;
- double cost; /* Cost of using pProbe */
- double nRow; /* Estimated number of rows in result set */
+ WhereCost pc; /* Cost of using pProbe */
double log10N = (double)1; /* base-10 logarithm of nRow (inexact) */
- int rev; /* True to scan in reverse order */
- int wsFlags = 0;
- Bitmask used = 0;
/* The following variables are populated based on the properties of
** index being evaluated. They are then used to determine the expected
** cost and number of rows returned.
**
- ** nEq:
+ ** pc.plan.nEq:
** Number of equality terms that can be implemented using the index.
** In other words, the number of initial fields in the index that
** are used in == or IN or NOT NULL constraints of the WHERE clause.
@@ -104713,6 +107714,10 @@ static void bestBtreeIndex(
** external sort (i.e. scanning the index being evaluated will not
** correctly order records).
**
+ ** bDist:
+ ** Boolean. True if there is a DISTINCT clause that will require an
+ ** external btree.
+ **
** bLookup:
** Boolean. True if a table lookup is required for each index entry
** visited. In other words, true if this is not a covering index.
@@ -104728,29 +107733,35 @@ static void bestBtreeIndex(
** SELECT a, b FROM tbl WHERE a = 1;
** SELECT a, b, c FROM tbl WHERE a = 1;
*/
- int nEq; /* Number of == or IN terms matching index */
int bInEst = 0; /* True if "x IN (SELECT...)" seen */
int nInMul = 1; /* Number of distinct equalities to lookup */
double rangeDiv = (double)1; /* Estimated reduction in search space */
int nBound = 0; /* Number of range constraints seen */
- int bSort = !!pOrderBy; /* True if external sort required */
- int bDist = !!pDistinct; /* True if index cannot help with DISTINCT */
- int bLookup = 0; /* True if not a covering index */
+ char bSort = bSortInit; /* True if external sort required */
+ char bDist = bDistInit; /* True if index cannot help with DISTINCT */
+ char bLookup = 0; /* True if not a covering index */
WhereTerm *pTerm; /* A single term of the WHERE clause */
#ifdef SQLITE_ENABLE_STAT3
WhereTerm *pFirstTerm = 0; /* First term matching the index */
#endif
- /* Determine the values of nEq and nInMul */
- for(nEq=0; nEq<pProbe->nColumn; nEq++){
- int j = pProbe->aiColumn[nEq];
- pTerm = findTerm(pWC, iCur, j, notReady, eqTermMask, pIdx);
+ WHERETRACE((
+ " %s(%s):\n",
+ pSrc->pTab->zName, (pIdx ? pIdx->zName : "ipk")
+ ));
+ memset(&pc, 0, sizeof(pc));
+ pc.plan.nOBSat = nPriorSat;
+
+ /* Determine the values of pc.plan.nEq and nInMul */
+ for(pc.plan.nEq=0; pc.plan.nEq<pProbe->nColumn; pc.plan.nEq++){
+ int j = pProbe->aiColumn[pc.plan.nEq];
+ pTerm = findTerm(pWC, iCur, j, p->notReady, eqTermMask, pIdx);
if( pTerm==0 ) break;
- wsFlags |= (WHERE_COLUMN_EQ|WHERE_ROWID_EQ);
+ pc.plan.wsFlags |= (WHERE_COLUMN_EQ|WHERE_ROWID_EQ);
testcase( pTerm->pWC!=pWC );
if( pTerm->eOperator & WO_IN ){
Expr *pExpr = pTerm->pExpr;
- wsFlags |= WHERE_COLUMN_IN;
+ pc.plan.wsFlags |= WHERE_COLUMN_IN;
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
/* "x IN (SELECT ...)": Assume the SELECT returns 25 rows */
nInMul *= 25;
@@ -104760,12 +107771,12 @@ static void bestBtreeIndex(
nInMul *= pExpr->x.pList->nExpr;
}
}else if( pTerm->eOperator & WO_ISNULL ){
- wsFlags |= WHERE_COLUMN_NULL;
+ pc.plan.wsFlags |= WHERE_COLUMN_NULL;
}
#ifdef SQLITE_ENABLE_STAT3
- if( nEq==0 && pProbe->aSample ) pFirstTerm = pTerm;
+ if( pc.plan.nEq==0 && pProbe->aSample ) pFirstTerm = pTerm;
#endif
- used |= pTerm->prereqRight;
+ pc.used |= pTerm->prereqRight;
}
/* If the index being considered is UNIQUE, and there is an equality
@@ -104774,65 +107785,82 @@ static void bestBtreeIndex(
** indicate this to the caller.
**
** Otherwise, if the search may find more than one row, test to see if
- ** there is a range constraint on indexed column (nEq+1) that can be
- ** optimized using the index.
+ ** there is a range constraint on indexed column (pc.plan.nEq+1) that
+ ** can be optimized using the index.
*/
- if( nEq==pProbe->nColumn && pProbe->onError!=OE_None ){
- testcase( wsFlags & WHERE_COLUMN_IN );
- testcase( wsFlags & WHERE_COLUMN_NULL );
- if( (wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_NULL))==0 ){
- wsFlags |= WHERE_UNIQUE;
+ if( pc.plan.nEq==pProbe->nColumn && pProbe->onError!=OE_None ){
+ testcase( pc.plan.wsFlags & WHERE_COLUMN_IN );
+ testcase( pc.plan.wsFlags & WHERE_COLUMN_NULL );
+ if( (pc.plan.wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_NULL))==0 ){
+ pc.plan.wsFlags |= WHERE_UNIQUE;
+ if( p->i==0 || (p->aLevel[p->i-1].plan.wsFlags & WHERE_ALL_UNIQUE)!=0 ){
+ pc.plan.wsFlags |= WHERE_ALL_UNIQUE;
+ }
}
}else if( pProbe->bUnordered==0 ){
- int j = (nEq==pProbe->nColumn ? -1 : pProbe->aiColumn[nEq]);
- if( findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE|WO_GT|WO_GE, pIdx) ){
- WhereTerm *pTop = findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE, pIdx);
- WhereTerm *pBtm = findTerm(pWC, iCur, j, notReady, WO_GT|WO_GE, pIdx);
- whereRangeScanEst(pParse, pProbe, nEq, pBtm, pTop, &rangeDiv);
+ int j;
+ j = (pc.plan.nEq==pProbe->nColumn ? -1 : pProbe->aiColumn[pc.plan.nEq]);
+ if( findTerm(pWC, iCur, j, p->notReady, WO_LT|WO_LE|WO_GT|WO_GE, pIdx) ){
+ WhereTerm *pTop, *pBtm;
+ pTop = findTerm(pWC, iCur, j, p->notReady, WO_LT|WO_LE, pIdx);
+ pBtm = findTerm(pWC, iCur, j, p->notReady, WO_GT|WO_GE, pIdx);
+ whereRangeScanEst(pParse, pProbe, pc.plan.nEq, pBtm, pTop, &rangeDiv);
if( pTop ){
nBound = 1;
- wsFlags |= WHERE_TOP_LIMIT;
- used |= pTop->prereqRight;
+ pc.plan.wsFlags |= WHERE_TOP_LIMIT;
+ pc.used |= pTop->prereqRight;
testcase( pTop->pWC!=pWC );
}
if( pBtm ){
nBound++;
- wsFlags |= WHERE_BTM_LIMIT;
- used |= pBtm->prereqRight;
+ pc.plan.wsFlags |= WHERE_BTM_LIMIT;
+ pc.used |= pBtm->prereqRight;
testcase( pBtm->pWC!=pWC );
}
- wsFlags |= (WHERE_COLUMN_RANGE|WHERE_ROWID_RANGE);
+ pc.plan.wsFlags |= (WHERE_COLUMN_RANGE|WHERE_ROWID_RANGE);
}
}
/* If there is an ORDER BY clause and the index being considered will
** naturally scan rows in the required order, set the appropriate flags
- ** in wsFlags. Otherwise, if there is an ORDER BY clause but the index
- ** will scan rows in a different order, set the bSort variable. */
- if( isSortingIndex(
- pParse, pWC->pMaskSet, pProbe, iCur, pOrderBy, nEq, wsFlags, &rev)
- ){
- bSort = 0;
- wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE|WHERE_ORDERBY;
- wsFlags |= (rev ? WHERE_REVERSE : 0);
+ ** in pc.plan.wsFlags. Otherwise, if there is an ORDER BY clause but
+ ** the index will scan rows in a different order, set the bSort
+ ** variable. */
+ if( bSort && (pSrc->jointype & JT_LEFT)==0 ){
+ int bRev = 2;
+ int bObUnique = 0;
+ WHERETRACE((" --> before isSortIndex: nPriorSat=%d\n",nPriorSat));
+ pc.plan.nOBSat = isSortingIndex(p, pProbe, iCur, &bRev, &bObUnique);
+ WHERETRACE((" --> after isSortIndex: bRev=%d bObU=%d nOBSat=%d\n",
+ bRev, bObUnique, pc.plan.nOBSat));
+ if( nPriorSat<pc.plan.nOBSat || (pc.plan.wsFlags & WHERE_ALL_UNIQUE)!=0 ){
+ pc.plan.wsFlags |= WHERE_ORDERED;
+ if( bObUnique ) pc.plan.wsFlags |= WHERE_OB_UNIQUE;
+ }
+ if( nOrderBy==pc.plan.nOBSat ){
+ bSort = 0;
+ pc.plan.wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE;
+ }
+ if( bRev & 1 ) pc.plan.wsFlags |= WHERE_REVERSE;
}
/* If there is a DISTINCT qualifier and this index will scan rows in
** order of the DISTINCT expressions, clear bDist and set the appropriate
- ** flags in wsFlags. */
- if( isDistinctIndex(pParse, pWC, pProbe, iCur, pDistinct, nEq)
- && (wsFlags & WHERE_COLUMN_IN)==0
+ ** flags in pc.plan.wsFlags. */
+ if( bDist
+ && isDistinctIndex(pParse, pWC, pProbe, iCur, p->pDistinct, pc.plan.nEq)
+ && (pc.plan.wsFlags & WHERE_COLUMN_IN)==0
){
bDist = 0;
- wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE|WHERE_DISTINCT;
+ pc.plan.wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE|WHERE_DISTINCT;
}
/* If currently calculating the cost of using an index (not the IPK
** index), determine if all required column data may be obtained without
** using the main table (i.e. if the index is a covering
** index for this query). If it is, set the WHERE_IDX_ONLY flag in
- ** wsFlags. Otherwise, set the bLookup variable to true. */
- if( pIdx && wsFlags ){
+ ** pc.plan.wsFlags. Otherwise, set the bLookup variable to true. */
+ if( pIdx ){
Bitmask m = pSrc->colUsed;
int j;
for(j=0; j<pIdx->nColumn; j++){
@@ -104842,7 +107870,7 @@ static void bestBtreeIndex(
}
}
if( m==0 ){
- wsFlags |= WHERE_IDX_ONLY;
+ pc.plan.wsFlags |= WHERE_IDX_ONLY;
}else{
bLookup = 1;
}
@@ -104852,10 +107880,10 @@ static void bestBtreeIndex(
** Estimate the number of rows of output. For an "x IN (SELECT...)"
** constraint, do not let the estimate exceed half the rows in the table.
*/
- nRow = (double)(aiRowEst[nEq] * nInMul);
- if( bInEst && nRow*2>aiRowEst[0] ){
- nRow = aiRowEst[0]/2;
- nInMul = (int)(nRow / aiRowEst[nEq]);
+ pc.plan.nRow = (double)(aiRowEst[pc.plan.nEq] * nInMul);
+ if( bInEst && pc.plan.nRow*2>aiRowEst[0] ){
+ pc.plan.nRow = aiRowEst[0]/2;
+ nInMul = (int)(pc.plan.nRow / aiRowEst[pc.plan.nEq]);
}
#ifdef SQLITE_ENABLE_STAT3
@@ -104865,15 +107893,19 @@ static void bestBtreeIndex(
** to get a better estimate on the number of rows based on
** VALUE and how common that value is according to the histogram.
*/
- if( nRow>(double)1 && nEq==1 && pFirstTerm!=0 && aiRowEst[1]>1 ){
+ if( pc.plan.nRow>(double)1 && pc.plan.nEq==1
+ && pFirstTerm!=0 && aiRowEst[1]>1 ){
assert( (pFirstTerm->eOperator & (WO_EQ|WO_ISNULL|WO_IN))!=0 );
if( pFirstTerm->eOperator & (WO_EQ|WO_ISNULL) ){
- testcase( pFirstTerm->eOperator==WO_EQ );
- testcase( pFirstTerm->eOperator==WO_ISNULL );
- whereEqualScanEst(pParse, pProbe, pFirstTerm->pExpr->pRight, &nRow);
+ testcase( pFirstTerm->eOperator & WO_EQ );
+ testcase( pFirstTerm->eOperator & WO_EQUIV );
+ testcase( pFirstTerm->eOperator & WO_ISNULL );
+ whereEqualScanEst(pParse, pProbe, pFirstTerm->pExpr->pRight,
+ &pc.plan.nRow);
}else if( bInEst==0 ){
- assert( pFirstTerm->eOperator==WO_IN );
- whereInScanEst(pParse, pProbe, pFirstTerm->pExpr->x.pList, &nRow);
+ assert( pFirstTerm->eOperator & WO_IN );
+ whereInScanEst(pParse, pProbe, pFirstTerm->pExpr->x.pList,
+ &pc.plan.nRow);
}
}
#endif /* SQLITE_ENABLE_STAT3 */
@@ -104881,8 +107913,8 @@ static void bestBtreeIndex(
/* Adjust the number of output rows and downward to reflect rows
** that are excluded by range constraints.
*/
- nRow = nRow/rangeDiv;
- if( nRow<1 ) nRow = 1;
+ pc.plan.nRow = pc.plan.nRow/rangeDiv;
+ if( pc.plan.nRow<1 ) pc.plan.nRow = 1;
/* Experiments run on real SQLite databases show that the time needed
** to do a binary search to locate a row in a table or index is roughly
@@ -104897,7 +107929,19 @@ static void bestBtreeIndex(
** So this computation assumes table records are about twice as big
** as index records
*/
- if( (wsFlags & WHERE_NOT_FULLSCAN)==0 ){
+ if( (pc.plan.wsFlags&~(WHERE_REVERSE|WHERE_ORDERED|WHERE_OB_UNIQUE))
+ ==WHERE_IDX_ONLY
+ && (pWC->wctrlFlags & WHERE_ONEPASS_DESIRED)==0
+ && sqlite3GlobalConfig.bUseCis
+ && OptimizationEnabled(pParse->db, SQLITE_CoverIdxScan)
+ ){
+ /* This index is not useful for indexing, but it is a covering index.
+ ** A full-scan of the index might be a little faster than a full-scan
+ ** of the table, so give this case a cost slightly less than a table
+ ** scan. */
+ pc.rCost = aiRowEst[0]*3 + pProbe->nColumn;
+ pc.plan.wsFlags |= WHERE_COVER_SCAN|WHERE_COLUMN_RANGE;
+ }else if( (pc.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ){
/* The cost of a full table scan is a number of move operations equal
** to the number of rows in the table.
**
@@ -104907,10 +107951,15 @@ static void bestBtreeIndex(
** decision and one which we expect to revisit in the future. But
** it seems to be working well enough at the moment.
*/
- cost = aiRowEst[0]*4;
+ pc.rCost = aiRowEst[0]*4;
+ pc.plan.wsFlags &= ~WHERE_IDX_ONLY;
+ if( pIdx ){
+ pc.plan.wsFlags &= ~WHERE_ORDERED;
+ pc.plan.nOBSat = nPriorSat;
+ }
}else{
log10N = estLog(aiRowEst[0]);
- cost = nRow;
+ pc.rCost = pc.plan.nRow;
if( pIdx ){
if( bLookup ){
/* For an index lookup followed by a table lookup:
@@ -104918,20 +107967,20 @@ static void bestBtreeIndex(
** + nRow steps through the index
** + nRow table searches to lookup the table entry using the rowid
*/
- cost += (nInMul + nRow)*log10N;
+ pc.rCost += (nInMul + pc.plan.nRow)*log10N;
}else{
/* For a covering index:
** nInMul index searches to find the initial entry
** + nRow steps through the index
*/
- cost += nInMul*log10N;
+ pc.rCost += nInMul*log10N;
}
}else{
/* For a rowid primary key lookup:
** nInMult table searches to find the initial entry for each range
** + nRow steps through the table
*/
- cost += nInMul*log10N;
+ pc.rCost += nInMul*log10N;
}
}
@@ -104942,10 +107991,12 @@ static void bestBtreeIndex(
** difference and select C of 3.0.
*/
if( bSort ){
- cost += nRow*estLog(nRow)*3;
+ double m = estLog(pc.plan.nRow*(nOrderBy - pc.plan.nOBSat)/nOrderBy);
+ m *= (double)(pc.plan.nOBSat ? 2 : 3);
+ pc.rCost += pc.plan.nRow*m;
}
if( bDist ){
- cost += nRow*estLog(nRow)*3;
+ pc.rCost += pc.plan.nRow*estLog(pc.plan.nRow)*3;
}
/**** Cost of using this index has now been computed ****/
@@ -104966,25 +108017,25 @@ static void bestBtreeIndex(
** might be selected even when there exists an optimal index that has
** no such dependency.
*/
- if( nRow>2 && cost<=pCost->rCost ){
+ if( pc.plan.nRow>2 && pc.rCost<=p->cost.rCost ){
int k; /* Loop counter */
- int nSkipEq = nEq; /* Number of == constraints to skip */
+ int nSkipEq = pc.plan.nEq; /* Number of == constraints to skip */
int nSkipRange = nBound; /* Number of < constraints to skip */
Bitmask thisTab; /* Bitmap for pSrc */
thisTab = getMask(pWC->pMaskSet, iCur);
- for(pTerm=pWC->a, k=pWC->nTerm; nRow>2 && k; k--, pTerm++){
+ for(pTerm=pWC->a, k=pWC->nTerm; pc.plan.nRow>2 && k; k--, pTerm++){
if( pTerm->wtFlags & TERM_VIRTUAL ) continue;
- if( (pTerm->prereqAll & notValid)!=thisTab ) continue;
+ if( (pTerm->prereqAll & p->notValid)!=thisTab ) continue;
if( pTerm->eOperator & (WO_EQ|WO_IN|WO_ISNULL) ){
if( nSkipEq ){
- /* Ignore the first nEq equality matches since the index
+ /* Ignore the first pc.plan.nEq equality matches since the index
** has already accounted for these */
nSkipEq--;
}else{
/* Assume each additional equality match reduces the result
** set size by a factor of 10 */
- nRow /= 10;
+ pc.plan.nRow /= 10;
}
}else if( pTerm->eOperator & (WO_LT|WO_LE|WO_GT|WO_GE) ){
if( nSkipRange ){
@@ -104998,37 +108049,33 @@ static void bestBtreeIndex(
** more selective intentionally because of the subjective
** observation that indexed range constraints really are more
** selective in practice, on average. */
- nRow /= 3;
+ pc.plan.nRow /= 3;
}
- }else if( pTerm->eOperator!=WO_NOOP ){
+ }else if( (pTerm->eOperator & WO_NOOP)==0 ){
/* Any other expression lowers the output row count by half */
- nRow /= 2;
+ pc.plan.nRow /= 2;
}
}
- if( nRow<2 ) nRow = 2;
+ if( pc.plan.nRow<2 ) pc.plan.nRow = 2;
}
WHERETRACE((
- "%s(%s): nEq=%d nInMul=%d rangeDiv=%d bSort=%d bLookup=%d wsFlags=0x%x\n"
- " notReady=0x%llx log10N=%.1f nRow=%.1f cost=%.1f used=0x%llx\n",
- pSrc->pTab->zName, (pIdx ? pIdx->zName : "ipk"),
- nEq, nInMul, (int)rangeDiv, bSort, bLookup, wsFlags,
- notReady, log10N, nRow, cost, used
+ " nEq=%d nInMul=%d rangeDiv=%d bSort=%d bLookup=%d wsFlags=0x%08x\n"
+ " notReady=0x%llx log10N=%.1f nRow=%.1f cost=%.1f\n"
+ " used=0x%llx nOBSat=%d\n",
+ pc.plan.nEq, nInMul, (int)rangeDiv, bSort, bLookup, pc.plan.wsFlags,
+ p->notReady, log10N, pc.plan.nRow, pc.rCost, pc.used,
+ pc.plan.nOBSat
));
/* If this index is the best we have seen so far, then record this
- ** index and its cost in the pCost structure.
+ ** index and its cost in the p->cost structure.
*/
- if( (!pIdx || wsFlags)
- && (cost<pCost->rCost || (cost<=pCost->rCost && nRow<pCost->plan.nRow))
- ){
- pCost->rCost = cost;
- pCost->used = used;
- pCost->plan.nRow = nRow;
- pCost->plan.wsFlags = (wsFlags&wsFlagMask);
- pCost->plan.nEq = nEq;
- pCost->plan.u.pIdx = pIdx;
+ if( (!pIdx || pc.plan.wsFlags) && compareCost(&pc, &p->cost) ){
+ p->cost = pc;
+ p->cost.plan.wsFlags &= wsFlagMask;
+ p->cost.plan.u.pIdx = pIdx;
}
/* If there was an INDEXED BY clause, then only that one index is
@@ -105043,27 +108090,26 @@ static void bestBtreeIndex(
/* If there is no ORDER BY clause and the SQLITE_ReverseOrder flag
** is set, then reverse the order that the index will be scanned
** in. This is used for application testing, to help find cases
- ** where application behaviour depends on the (undefined) order that
+ ** where application behavior depends on the (undefined) order that
** SQLite outputs rows in in the absence of an ORDER BY clause. */
- if( !pOrderBy && pParse->db->flags & SQLITE_ReverseOrder ){
- pCost->plan.wsFlags |= WHERE_REVERSE;
+ if( !p->pOrderBy && pParse->db->flags & SQLITE_ReverseOrder ){
+ p->cost.plan.wsFlags |= WHERE_REVERSE;
}
- assert( pOrderBy || (pCost->plan.wsFlags&WHERE_ORDERBY)==0 );
- assert( pCost->plan.u.pIdx==0 || (pCost->plan.wsFlags&WHERE_ROWID_EQ)==0 );
+ assert( p->pOrderBy || (p->cost.plan.wsFlags&WHERE_ORDERED)==0 );
+ assert( p->cost.plan.u.pIdx==0 || (p->cost.plan.wsFlags&WHERE_ROWID_EQ)==0 );
assert( pSrc->pIndex==0
- || pCost->plan.u.pIdx==0
- || pCost->plan.u.pIdx==pSrc->pIndex
+ || p->cost.plan.u.pIdx==0
+ || p->cost.plan.u.pIdx==pSrc->pIndex
);
- WHERETRACE(("best index is: %s\n",
- ((pCost->plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ? "none" :
- pCost->plan.u.pIdx ? pCost->plan.u.pIdx->zName : "ipk")
- ));
+ WHERETRACE((" best index is %s cost=%.1f\n",
+ p->cost.plan.u.pIdx ? p->cost.plan.u.pIdx->zName : "ipk",
+ p->cost.rCost));
- bestOrClauseIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost);
- bestAutomaticIndex(pParse, pWC, pSrc, notReady, pCost);
- pCost->plan.wsFlags |= eqTermMask;
+ bestOrClauseIndex(p);
+ bestAutomaticIndex(p);
+ p->cost.plan.wsFlags |= eqTermMask;
}
/*
@@ -105071,28 +108117,28 @@ static void bestBtreeIndex(
** best query plan and its cost into the WhereCost object supplied
** as the last parameter. This function may calculate the cost of
** both real and virtual table scans.
+**
+** This function does not take ORDER BY or DISTINCT into account. Nor
+** does it remember the virtual table query plan. All it does is compute
+** the cost while determining if an OR optimization is applicable. The
+** details will be reconsidered later if the optimization is found to be
+** applicable.
*/
-static void bestIndex(
- Parse *pParse, /* The parsing context */
- WhereClause *pWC, /* The WHERE clause */
- struct SrcList_item *pSrc, /* The FROM clause term to search */
- Bitmask notReady, /* Mask of cursors not available for indexing */
- Bitmask notValid, /* Cursors not available for any purpose */
- ExprList *pOrderBy, /* The ORDER BY clause */
- WhereCost *pCost /* Lowest cost query plan */
-){
+static void bestIndex(WhereBestIdx *p){
#ifndef SQLITE_OMIT_VIRTUALTABLE
- if( IsVirtual(pSrc->pTab) ){
- sqlite3_index_info *p = 0;
- bestVirtualIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost,&p);
- if( p->needToFreeIdxStr ){
- sqlite3_free(p->idxStr);
- }
- sqlite3DbFree(pParse->db, p);
+ if( IsVirtual(p->pSrc->pTab) ){
+ sqlite3_index_info *pIdxInfo = 0;
+ p->ppIdxInfo = &pIdxInfo;
+ bestVirtualIndex(p);
+ assert( pIdxInfo!=0 || p->pParse->db->mallocFailed );
+ if( pIdxInfo && pIdxInfo->needToFreeIdxStr ){
+ sqlite3_free(pIdxInfo->idxStr);
+ }
+ sqlite3DbFree(p->pParse->db, pIdxInfo);
}else
#endif
{
- bestBtreeIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, 0, pCost);
+ bestBtreeIndex(p);
}
}
@@ -105191,7 +108237,8 @@ static void codeApplyAffinity(Parse *pParse, int base, int n, char *zAff){
static int codeEqualityTerm(
Parse *pParse, /* The parsing context */
WhereTerm *pTerm, /* The term of the WHERE clause to be coded */
- WhereLevel *pLevel, /* When level of the FROM clause we are working on */
+ WhereLevel *pLevel, /* The level of the FROM clause we are working on */
+ int iEq, /* Index of the equality term within this level */
int iTarget /* Attempt to leave results in this register */
){
Expr *pX = pTerm->pExpr;
@@ -105209,12 +108256,26 @@ static int codeEqualityTerm(
int eType;
int iTab;
struct InLoop *pIn;
+ u8 bRev = (pLevel->plan.wsFlags & WHERE_REVERSE)!=0;
+ if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0
+ && pLevel->plan.u.pIdx->aSortOrder[iEq]
+ ){
+ testcase( iEq==0 );
+ testcase( iEq==pLevel->plan.u.pIdx->nColumn-1 );
+ testcase( iEq>0 && iEq+1<pLevel->plan.u.pIdx->nColumn );
+ testcase( bRev );
+ bRev = !bRev;
+ }
assert( pX->op==TK_IN );
iReg = iTarget;
eType = sqlite3FindInIndex(pParse, pX, 0);
+ if( eType==IN_INDEX_INDEX_DESC ){
+ testcase( bRev );
+ bRev = !bRev;
+ }
iTab = pX->iTable;
- sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0);
+ sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0);
assert( pLevel->plan.wsFlags & WHERE_IN_ABLE );
if( pLevel->u.in.nIn==0 ){
pLevel->addrNxt = sqlite3VdbeMakeLabel(v);
@@ -105232,6 +108293,7 @@ static int codeEqualityTerm(
}else{
pIn->addrInTop = sqlite3VdbeAddOp3(v, OP_Column, iTab, 0, iReg);
}
+ pIn->eEndLoopOp = bRev ? OP_Prev : OP_Next;
sqlite3VdbeAddOp1(v, OP_IsNull, iReg);
}else{
pLevel->u.in.nIn = 0;
@@ -105326,7 +108388,7 @@ static int codeAllEqualityTerms(
** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */
testcase( (pTerm->wtFlags & TERM_CODED)!=0 );
testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
- r1 = codeEqualityTerm(pParse, pTerm, pLevel, regBase+j);
+ r1 = codeEqualityTerm(pParse, pTerm, pLevel, j, regBase+j);
if( r1!=regBase+j ){
if( nReg==1 ){
sqlite3ReleaseTempReg(pParse, regBase);
@@ -105536,6 +108598,7 @@ static Bitmask codeOneLoopStart(
int addrCont; /* Jump here to continue with next cycle */
int iRowidReg = 0; /* Rowid is stored in this register, if not zero */
int iReleaseReg = 0; /* Temp register to free before returning */
+ Bitmask newNotReady; /* Return value */
pParse = pWInfo->pParse;
v = pParse->pVdbe;
@@ -105546,6 +108609,7 @@ static Bitmask codeOneLoopStart(
bRev = (pLevel->plan.wsFlags & WHERE_REVERSE)!=0;
omitTable = (pLevel->plan.wsFlags & WHERE_IDX_ONLY)!=0
&& (wctrlFlags & WHERE_FORCE_TABLE)==0;
+ VdbeNoopComment((v, "Begin Join Loop %d", iLevel));
/* Create labels for the "break" and "continue" instructions
** for the current loop. Jump to addrBrk to break out of a loop.
@@ -105570,12 +108634,23 @@ static Bitmask codeOneLoopStart(
VdbeComment((v, "init LEFT JOIN no-match flag"));
}
+ /* Special case of a FROM clause subquery implemented as a co-routine */
+ if( pTabItem->viaCoroutine ){
+ int regYield = pTabItem->regReturn;
+ sqlite3VdbeAddOp2(v, OP_Integer, pTabItem->addrFillSub-1, regYield);
+ pLevel->p2 = sqlite3VdbeAddOp1(v, OP_Yield, regYield);
+ VdbeComment((v, "next row of co-routine %s", pTabItem->pTab->zName));
+ sqlite3VdbeAddOp2(v, OP_If, regYield+1, addrBrk);
+ pLevel->op = OP_Goto;
+ }else
+
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( (pLevel->plan.wsFlags & WHERE_VIRTUALTABLE)!=0 ){
/* Case 0: The table is a virtual-table. Use the VFilter and VNext
** to access the data.
*/
int iReg; /* P3 Value for OP_VFilter */
+ int addrNotFound;
sqlite3_index_info *pVtabIdx = pLevel->plan.u.pVtabIdx;
int nConstraint = pVtabIdx->nConstraint;
struct sqlite3_index_constraint_usage *aUsage =
@@ -105585,11 +108660,18 @@ static Bitmask codeOneLoopStart(
sqlite3ExprCachePush(pParse);
iReg = sqlite3GetTempRange(pParse, nConstraint+2);
+ addrNotFound = pLevel->addrBrk;
for(j=1; j<=nConstraint; j++){
for(k=0; k<nConstraint; k++){
if( aUsage[k].argvIndex==j ){
- int iTerm = aConstraint[k].iTermOffset;
- sqlite3ExprCode(pParse, pWC->a[iTerm].pExpr->pRight, iReg+j+1);
+ int iTarget = iReg+j+1;
+ pTerm = &pWC->a[aConstraint[k].iTermOffset];
+ if( pTerm->eOperator & WO_IN ){
+ codeEqualityTerm(pParse, pTerm, pLevel, k, iTarget);
+ addrNotFound = pLevel->addrNxt;
+ }else{
+ sqlite3ExprCode(pParse, pTerm->pExpr->pRight, iTarget);
+ }
break;
}
}
@@ -105597,7 +108679,7 @@ static Bitmask codeOneLoopStart(
}
sqlite3VdbeAddOp2(v, OP_Integer, pVtabIdx->idxNum, iReg);
sqlite3VdbeAddOp2(v, OP_Integer, j-1, iReg+1);
- sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrBrk, iReg, pVtabIdx->idxStr,
+ sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrNotFound, iReg, pVtabIdx->idxStr,
pVtabIdx->needToFreeIdxStr ? P4_MPRINTF : P4_STATIC);
pVtabIdx->needToFreeIdxStr = 0;
for(j=0; j<nConstraint; j++){
@@ -105624,13 +108706,13 @@ static Bitmask codeOneLoopStart(
pTerm = findTerm(pWC, iCur, -1, notReady, WO_EQ|WO_IN, 0);
assert( pTerm!=0 );
assert( pTerm->pExpr!=0 );
- assert( pTerm->leftCursor==iCur );
assert( omitTable==0 );
testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
- iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, iReleaseReg);
+ iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, iReleaseReg);
addrNxt = pLevel->addrNxt;
sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt);
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addrNxt, iRowidReg);
+ sqlite3ExprCacheAffinityChange(pParse, iRowidReg, 1);
sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
VdbeComment((v, "pk"));
pLevel->op = OP_Noop;
@@ -105788,7 +108870,7 @@ static Bitmask codeOneLoopStart(
** this requires some special handling.
*/
if( (wctrlFlags&WHERE_ORDERBY_MIN)!=0
- && (pLevel->plan.wsFlags&WHERE_ORDERBY)
+ && (pLevel->plan.wsFlags&WHERE_ORDERED)
&& (pIdx->nColumn>nEq)
){
/* assert( pOrderBy->nExpr==1 ); */
@@ -105951,6 +109033,11 @@ static Bitmask codeOneLoopStart(
pLevel->op = OP_Next;
}
pLevel->p1 = iIdxCur;
+ if( pLevel->plan.wsFlags & WHERE_COVER_SCAN ){
+ pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
+ }else{
+ assert( pLevel->p5==0 );
+ }
}else
#ifndef SQLITE_OMIT_OR_OPTIMIZATION
@@ -106010,7 +109097,7 @@ static Bitmask codeOneLoopStart(
pTerm = pLevel->plan.u.pTerm;
assert( pTerm!=0 );
- assert( pTerm->eOperator==WO_OR );
+ assert( pTerm->eOperator & WO_OR );
assert( (pTerm->wtFlags & TERM_ORINFO)!=0 );
pOrWc = &pTerm->u.pOrInfo->wc;
pLevel->op = OP_Return;
@@ -106065,6 +109152,10 @@ static Bitmask codeOneLoopStart(
** the "interesting" terms of z - terms that did not originate in the
** ON or USING clause of a LEFT JOIN, and terms that are usable as
** indices.
+ **
+ ** This optimization also only applies if the (x1 OR x2 OR ...) term
+ ** is not contained in the ON clause of a LEFT JOIN.
+ ** See ticket http://www.sqlite.org/src/info/f2369304e4
*/
if( pWC->nTerm>1 ){
int iTerm;
@@ -106083,10 +109174,10 @@ static Bitmask codeOneLoopStart(
for(ii=0; ii<pOrWc->nTerm; ii++){
WhereTerm *pOrTerm = &pOrWc->a[ii];
- if( pOrTerm->leftCursor==iCur || pOrTerm->eOperator==WO_AND ){
+ if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){
WhereInfo *pSubWInfo; /* Info for single OR-term scan */
Expr *pOrExpr = pOrTerm->pExpr;
- if( pAndExpr ){
+ if( pAndExpr && !ExprHasProperty(pOrExpr, EP_FromJoin) ){
pAndExpr->pLeft = pOrExpr;
pOrExpr = pAndExpr;
}
@@ -106173,7 +109264,7 @@ static Bitmask codeOneLoopStart(
pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk);
pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
}
- notReady &= ~getMask(pWC->pMaskSet, iCur);
+ newNotReady = notReady & ~getMask(pWC->pMaskSet, iCur);
/* Insert code to test every subexpression that can be completely
** computed using the current set of tables.
@@ -106187,7 +109278,7 @@ static Bitmask codeOneLoopStart(
testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* IMP: R-30575-11662 */
testcase( pTerm->wtFlags & TERM_CODED );
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
- if( (pTerm->prereqAll & notReady)!=0 ){
+ if( (pTerm->prereqAll & newNotReady)!=0 ){
testcase( pWInfo->untestedTerms==0
&& (pWInfo->wctrlFlags & WHERE_ONETABLE_ONLY)!=0 );
pWInfo->untestedTerms = 1;
@@ -106202,6 +109293,33 @@ static Bitmask codeOneLoopStart(
pTerm->wtFlags |= TERM_CODED;
}
+ /* Insert code to test for implied constraints based on transitivity
+ ** of the "==" operator.
+ **
+ ** Example: If the WHERE clause contains "t1.a=t2.b" and "t2.b=123"
+ ** and we are coding the t1 loop and the t2 loop has not yet coded,
+ ** then we cannot use the "t1.a=t2.b" constraint, but we can code
+ ** the implied "t1.a=123" constraint.
+ */
+ for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
+ Expr *pE;
+ WhereTerm *pAlt;
+ Expr sEq;
+ if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
+ if( pTerm->eOperator!=(WO_EQUIV|WO_EQ) ) continue;
+ if( pTerm->leftCursor!=iCur ) continue;
+ pE = pTerm->pExpr;
+ assert( !ExprHasProperty(pE, EP_FromJoin) );
+ assert( (pTerm->prereqRight & newNotReady)!=0 );
+ pAlt = findTerm(pWC, iCur, pTerm->u.leftColumn, notReady, WO_EQ|WO_IN, 0);
+ if( pAlt==0 ) continue;
+ if( pAlt->wtFlags & (TERM_CODED) ) continue;
+ VdbeNoopComment((v, "begin transitive constraint"));
+ sEq = *pAlt->pExpr;
+ sEq.pLeft = pE->pLeft;
+ sqlite3ExprIfFalse(pParse, &sEq, addrCont, SQLITE_JUMPIFNULL);
+ }
+
/* For a LEFT OUTER JOIN, generate code that will record the fact that
** at least one row of the right table has matched the left table.
*/
@@ -106214,7 +109332,7 @@ static Bitmask codeOneLoopStart(
testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* IMP: R-30575-11662 */
testcase( pTerm->wtFlags & TERM_CODED );
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
- if( (pTerm->prereqAll & notReady)!=0 ){
+ if( (pTerm->prereqAll & newNotReady)!=0 ){
assert( pWInfo->untestedTerms );
continue;
}
@@ -106225,7 +109343,7 @@ static Bitmask codeOneLoopStart(
}
sqlite3ReleaseTempReg(pParse, iReleaseReg);
- return notReady;
+ return newNotReady;
}
#if defined(SQLITE_TEST)
@@ -106345,42 +109463,46 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
**
** ORDER BY CLAUSE PROCESSING
**
-** *ppOrderBy is a pointer to the ORDER BY clause of a SELECT statement,
+** pOrderBy is a pointer to the ORDER BY clause of a SELECT statement,
** if there is one. If there is no ORDER BY clause or if this routine
-** is called from an UPDATE or DELETE statement, then ppOrderBy is NULL.
+** is called from an UPDATE or DELETE statement, then pOrderBy is NULL.
**
** If an index can be used so that the natural output order of the table
** scan is correct for the ORDER BY clause, then that index is used and
-** *ppOrderBy is set to NULL. This is an optimization that prevents an
-** unnecessary sort of the result set if an index appropriate for the
-** ORDER BY clause already exists.
+** the returned WhereInfo.nOBSat field is set to pOrderBy->nExpr. This
+** is an optimization that prevents an unnecessary sort of the result set
+** if an index appropriate for the ORDER BY clause already exists.
**
** If the where clause loops cannot be arranged to provide the correct
-** output order, then the *ppOrderBy is unchanged.
+** output order, then WhereInfo.nOBSat is 0.
*/
SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
Parse *pParse, /* The parser context */
SrcList *pTabList, /* A list of all tables to be scanned */
Expr *pWhere, /* The WHERE clause */
- ExprList **ppOrderBy, /* An ORDER BY clause, or NULL */
+ ExprList *pOrderBy, /* An ORDER BY clause, or NULL */
ExprList *pDistinct, /* The select-list for DISTINCT queries - or NULL */
u16 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */
int iIdxCur /* If WHERE_ONETABLE_ONLY is set, index cursor number */
){
- int i; /* Loop counter */
int nByteWInfo; /* Num. bytes allocated for WhereInfo struct */
int nTabList; /* Number of elements in pTabList */
WhereInfo *pWInfo; /* Will become the return value of this function */
Vdbe *v = pParse->pVdbe; /* The virtual database engine */
Bitmask notReady; /* Cursors that are not yet positioned */
+ WhereBestIdx sWBI; /* Best index search context */
WhereMaskSet *pMaskSet; /* The expression mask set */
- WhereClause *pWC; /* Decomposition of the WHERE clause */
- struct SrcList_item *pTabItem; /* A single entry from pTabList */
- WhereLevel *pLevel; /* A single level in the pWInfo list */
- int iFrom; /* First unused FROM clause element */
+ WhereLevel *pLevel; /* A single level in pWInfo->a[] */
+ int iFrom; /* First unused FROM clause element */
int andFlags; /* AND-ed combination of all pWC->a[].wtFlags */
+ int ii; /* Loop counter */
sqlite3 *db; /* Database connection */
+
+ /* Variable initialization */
+ memset(&sWBI, 0, sizeof(sWBI));
+ sWBI.pParse = pParse;
+
/* The number of tables in the FROM clause is limited by the number of
** bits in a Bitmask
*/
@@ -106420,22 +109542,23 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
pWInfo->pParse = pParse;
pWInfo->pTabList = pTabList;
pWInfo->iBreak = sqlite3VdbeMakeLabel(v);
- pWInfo->pWC = pWC = (WhereClause *)&((u8 *)pWInfo)[nByteWInfo];
+ pWInfo->pWC = sWBI.pWC = (WhereClause *)&((u8 *)pWInfo)[nByteWInfo];
pWInfo->wctrlFlags = wctrlFlags;
pWInfo->savedNQueryLoop = pParse->nQueryLoop;
- pMaskSet = (WhereMaskSet*)&pWC[1];
+ pMaskSet = (WhereMaskSet*)&sWBI.pWC[1];
+ sWBI.aLevel = pWInfo->a;
/* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via
** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */
- if( db->flags & SQLITE_DistinctOpt ) pDistinct = 0;
+ if( OptimizationDisabled(db, SQLITE_DistinctOpt) ) pDistinct = 0;
/* Split the WHERE clause into separate subexpressions where each
** subexpression is separated by an AND operator.
*/
initMaskSet(pMaskSet);
- whereClauseInit(pWC, pParse, pMaskSet, wctrlFlags);
+ whereClauseInit(sWBI.pWC, pParse, pMaskSet, wctrlFlags);
sqlite3ExprCodeConstants(pParse, pWhere);
- whereSplit(pWC, pWhere, TK_AND); /* IMP: R-15842-53296 */
+ whereSplit(sWBI.pWC, pWhere, TK_AND); /* IMP: R-15842-53296 */
/* Special case: a WHERE clause that is constant. Evaluate the
** expression and either jump over all of the code or fall thru.
@@ -106456,30 +109579,19 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
** bitmask for all tables to the left of the join. Knowing the bitmask
** for all tables to the left of a left join is important. Ticket #3015.
**
- ** Configure the WhereClause.vmask variable so that bits that correspond
- ** to virtual table cursors are set. This is used to selectively disable
- ** the OR-to-IN transformation in exprAnalyzeOrTerm(). It is not helpful
- ** with virtual tables.
- **
** Note that bitmasks are created for all pTabList->nSrc tables in
** pTabList, not just the first nTabList tables. nTabList is normally
** equal to pTabList->nSrc but might be shortened to 1 if the
** WHERE_ONETABLE_ONLY flag is set.
*/
- assert( pWC->vmask==0 && pMaskSet->n==0 );
- for(i=0; i<pTabList->nSrc; i++){
- createMask(pMaskSet, pTabList->a[i].iCursor);
-#ifndef SQLITE_OMIT_VIRTUALTABLE
- if( ALWAYS(pTabList->a[i].pTab) && IsVirtual(pTabList->a[i].pTab) ){
- pWC->vmask |= ((Bitmask)1 << i);
- }
-#endif
+ for(ii=0; ii<pTabList->nSrc; ii++){
+ createMask(pMaskSet, pTabList->a[ii].iCursor);
}
#ifndef NDEBUG
{
Bitmask toTheLeft = 0;
- for(i=0; i<pTabList->nSrc; i++){
- Bitmask m = getMask(pMaskSet, pTabList->a[i].iCursor);
+ for(ii=0; ii<pTabList->nSrc; ii++){
+ Bitmask m = getMask(pMaskSet, pTabList->a[ii].iCursor);
assert( (m-1)==toTheLeft );
toTheLeft |= m;
}
@@ -106491,7 +109603,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
** want to analyze these virtual terms, so start analyzing at the end
** and work forward so that the added virtual terms are never processed.
*/
- exprAnalyzeAll(pTabList, pWC);
+ exprAnalyzeAll(pTabList, sWBI.pWC);
if( db->mallocFailed ){
goto whereBeginError;
}
@@ -106500,7 +109612,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
** If it is, then set pDistinct to NULL and WhereInfo.eDistinct to
** WHERE_DISTINCT_UNIQUE to tell the caller to ignore the DISTINCT.
*/
- if( pDistinct && isDistinctRedundant(pParse, pTabList, pWC, pDistinct) ){
+ if( pDistinct && isDistinctRedundant(pParse, pTabList, sWBI.pWC, pDistinct) ){
pDistinct = 0;
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
}
@@ -106520,22 +109632,26 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
** This loop also figures out the nesting order of tables in the FROM
** clause.
*/
- notReady = ~(Bitmask)0;
+ sWBI.notValid = ~(Bitmask)0;
+ sWBI.pOrderBy = pOrderBy;
+ sWBI.n = nTabList;
+ sWBI.pDistinct = pDistinct;
andFlags = ~0;
WHERETRACE(("*** Optimizer Start ***\n"));
- for(i=iFrom=0, pLevel=pWInfo->a; i<nTabList; i++, pLevel++){
+ for(sWBI.i=iFrom=0, pLevel=pWInfo->a; sWBI.i<nTabList; sWBI.i++, pLevel++){
WhereCost bestPlan; /* Most efficient plan seen so far */
Index *pIdx; /* Index for FROM table at pTabItem */
int j; /* For looping over FROM tables */
int bestJ = -1; /* The value of j */
Bitmask m; /* Bitmask value for j or bestJ */
int isOptimal; /* Iterator for optimal/non-optimal search */
+ int ckOptimal; /* Do the optimal scan check */
int nUnconstrained; /* Number tables without INDEXED BY */
Bitmask notIndexed; /* Mask of tables that cannot use an index */
memset(&bestPlan, 0, sizeof(bestPlan));
bestPlan.rCost = SQLITE_BIG_DBL;
- WHERETRACE(("*** Begin search for loop %d ***\n", i));
+ WHERETRACE(("*** Begin search for loop %d ***\n", sWBI.i));
/* Loop through the remaining entries in the FROM clause to find the
** next nested loop. The loop tests all FROM clause entries
@@ -106551,8 +109667,8 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
** by waiting for other tables to run first. This "optimal" test works
** by first assuming that the FROM clause is on the inner loop and finding
** its query plan, then checking to see if that query plan uses any
- ** other FROM clause terms that are notReady. If no notReady terms are
- ** used then the "optimal" query plan works.
+ ** other FROM clause terms that are sWBI.notValid. If no notValid terms
+ ** are used then the "optimal" query plan works.
**
** Note that the WhereCost.nRow parameter for an optimal scan might
** not be as small as it would be if the table really were the innermost
@@ -106564,10 +109680,8 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
** strategies were found by the first iteration. This second iteration
** is used to search for the lowest cost scan overall.
**
- ** Previous versions of SQLite performed only the second iteration -
- ** the next outermost loop was always that with the lowest overall
- ** cost. However, this meant that SQLite could select the wrong plan
- ** for scripts such as the following:
+ ** Without the optimal scan step (the first iteration) a suboptimal
+ ** plan might be chosen for queries like this:
**
** CREATE TABLE t1(a, b);
** CREATE TABLE t2(c, d);
@@ -106582,59 +109696,89 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
*/
nUnconstrained = 0;
notIndexed = 0;
- for(isOptimal=(iFrom<nTabList-1); isOptimal>=0 && bestJ<0; isOptimal--){
- Bitmask mask; /* Mask of tables not yet ready */
- for(j=iFrom, pTabItem=&pTabList->a[j]; j<nTabList; j++, pTabItem++){
- int doNotReorder; /* True if this table should not be reordered */
- WhereCost sCost; /* Cost information from best[Virtual]Index() */
- ExprList *pOrderBy; /* ORDER BY clause for index to optimize */
- ExprList *pDist; /* DISTINCT clause for index to optimize */
-
- doNotReorder = (pTabItem->jointype & (JT_LEFT|JT_CROSS))!=0;
- if( j!=iFrom && doNotReorder ) break;
- m = getMask(pMaskSet, pTabItem->iCursor);
- if( (m & notReady)==0 ){
+
+ /* The optimal scan check only occurs if there are two or more tables
+ ** available to be reordered */
+ if( iFrom==nTabList-1 ){
+ ckOptimal = 0; /* Common case of just one table in the FROM clause */
+ }else{
+ ckOptimal = -1;
+ for(j=iFrom, sWBI.pSrc=&pTabList->a[j]; j<nTabList; j++, sWBI.pSrc++){
+ m = getMask(pMaskSet, sWBI.pSrc->iCursor);
+ if( (m & sWBI.notValid)==0 ){
if( j==iFrom ) iFrom++;
continue;
}
- mask = (isOptimal ? m : notReady);
- pOrderBy = ((i==0 && ppOrderBy )?*ppOrderBy:0);
- pDist = (i==0 ? pDistinct : 0);
- if( pTabItem->pIndex==0 ) nUnconstrained++;
+ if( j>iFrom && (sWBI.pSrc->jointype & (JT_LEFT|JT_CROSS))!=0 ) break;
+ if( ++ckOptimal ) break;
+ if( (sWBI.pSrc->jointype & JT_LEFT)!=0 ) break;
+ }
+ }
+ assert( ckOptimal==0 || ckOptimal==1 );
+
+ for(isOptimal=ckOptimal; isOptimal>=0 && bestJ<0; isOptimal--){
+ for(j=iFrom, sWBI.pSrc=&pTabList->a[j]; j<nTabList; j++, sWBI.pSrc++){
+ if( j>iFrom && (sWBI.pSrc->jointype & (JT_LEFT|JT_CROSS))!=0 ){
+ /* This break and one like it in the ckOptimal computation loop
+ ** above prevent table reordering across LEFT and CROSS JOINs.
+ ** The LEFT JOIN case is necessary for correctness. The prohibition
+ ** against reordering across a CROSS JOIN is an SQLite feature that
+ ** allows the developer to control table reordering */
+ break;
+ }
+ m = getMask(pMaskSet, sWBI.pSrc->iCursor);
+ if( (m & sWBI.notValid)==0 ){
+ assert( j>iFrom );
+ continue;
+ }
+ sWBI.notReady = (isOptimal ? m : sWBI.notValid);
+ if( sWBI.pSrc->pIndex==0 ) nUnconstrained++;
- WHERETRACE(("=== trying table %d with isOptimal=%d ===\n",
- j, isOptimal));
- assert( pTabItem->pTab );
+ WHERETRACE((" === trying table %d (%s) with isOptimal=%d ===\n",
+ j, sWBI.pSrc->pTab->zName, isOptimal));
+ assert( sWBI.pSrc->pTab );
#ifndef SQLITE_OMIT_VIRTUALTABLE
- if( IsVirtual(pTabItem->pTab) ){
- sqlite3_index_info **pp = &pWInfo->a[j].pIdxInfo;
- bestVirtualIndex(pParse, pWC, pTabItem, mask, notReady, pOrderBy,
- &sCost, pp);
+ if( IsVirtual(sWBI.pSrc->pTab) ){
+ sWBI.ppIdxInfo = &pWInfo->a[j].pIdxInfo;
+ bestVirtualIndex(&sWBI);
}else
#endif
{
- bestBtreeIndex(pParse, pWC, pTabItem, mask, notReady, pOrderBy,
- pDist, &sCost);
+ bestBtreeIndex(&sWBI);
}
- assert( isOptimal || (sCost.used¬Ready)==0 );
+ assert( isOptimal || (sWBI.cost.used&sWBI.notValid)==0 );
/* If an INDEXED BY clause is present, then the plan must use that
** index if it uses any index at all */
- assert( pTabItem->pIndex==0
- || (sCost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0
- || sCost.plan.u.pIdx==pTabItem->pIndex );
+ assert( sWBI.pSrc->pIndex==0
+ || (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0
+ || sWBI.cost.plan.u.pIdx==sWBI.pSrc->pIndex );
- if( isOptimal && (sCost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ){
+ if( isOptimal && (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ){
notIndexed |= m;
}
+ if( isOptimal ){
+ pWInfo->a[j].rOptCost = sWBI.cost.rCost;
+ }else if( ckOptimal ){
+ /* If two or more tables have nearly the same outer loop cost, but
+ ** very different inner loop (optimal) cost, we want to choose
+ ** for the outer loop that table which benefits the least from
+ ** being in the inner loop. The following code scales the
+ ** outer loop cost estimate to accomplish that. */
+ WHERETRACE((" scaling cost from %.1f to %.1f\n",
+ sWBI.cost.rCost,
+ sWBI.cost.rCost/pWInfo->a[j].rOptCost));
+ sWBI.cost.rCost /= pWInfo->a[j].rOptCost;
+ }
/* Conditions under which this table becomes the best so far:
**
** (1) The table must not depend on other tables that have not
- ** yet run.
+ ** yet run. (In other words, it must not depend on tables
+ ** in inner loops.)
**
- ** (2) A full-table-scan plan cannot supercede indexed plan unless
- ** the full-table-scan is an "optimal" plan as defined above.
+ ** (2) (This rule was removed on 2012-11-09. The scaling of the
+ ** cost using the optimal scan cost made this rule obsolete.)
**
** (3) All tables have an INDEXED BY clause or this table lacks an
** INDEXED BY clause or this table uses the specific
@@ -106645,43 +109789,47 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
** The NEVER() comes about because rule (2) above prevents
** An indexable full-table-scan from reaching rule (3).
**
- ** (4) The plan cost must be lower than prior plans or else the
- ** cost must be the same and the number of rows must be lower.
+ ** (4) The plan cost must be lower than prior plans, where "cost"
+ ** is defined by the compareCost() function above.
*/
- if( (sCost.used¬Ready)==0 /* (1) */
- && (bestJ<0 || (notIndexed&m)!=0 /* (2) */
- || (bestPlan.plan.wsFlags & WHERE_NOT_FULLSCAN)==0
- || (sCost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0)
- && (nUnconstrained==0 || pTabItem->pIndex==0 /* (3) */
- || NEVER((sCost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0))
- && (bestJ<0 || sCost.rCost<bestPlan.rCost /* (4) */
- || (sCost.rCost<=bestPlan.rCost
- && sCost.plan.nRow<bestPlan.plan.nRow))
+ if( (sWBI.cost.used&sWBI.notValid)==0 /* (1) */
+ && (nUnconstrained==0 || sWBI.pSrc->pIndex==0 /* (3) */
+ || NEVER((sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0))
+ && (bestJ<0 || compareCost(&sWBI.cost, &bestPlan)) /* (4) */
){
- WHERETRACE(("=== table %d is best so far"
- " with cost=%g and nRow=%g\n",
- j, sCost.rCost, sCost.plan.nRow));
- bestPlan = sCost;
+ WHERETRACE((" === table %d (%s) is best so far\n"
+ " cost=%.1f, nRow=%.1f, nOBSat=%d, wsFlags=%08x\n",
+ j, sWBI.pSrc->pTab->zName,
+ sWBI.cost.rCost, sWBI.cost.plan.nRow,
+ sWBI.cost.plan.nOBSat, sWBI.cost.plan.wsFlags));
+ bestPlan = sWBI.cost;
bestJ = j;
}
- if( doNotReorder ) break;
+
+ /* In a join like "w JOIN x LEFT JOIN y JOIN z" make sure that
+ ** table y (and not table z) is always the next inner loop inside
+ ** of table x. */
+ if( (sWBI.pSrc->jointype & JT_LEFT)!=0 ) break;
}
}
assert( bestJ>=0 );
- assert( notReady & getMask(pMaskSet, pTabList->a[bestJ].iCursor) );
- WHERETRACE(("*** Optimizer selects table %d for loop %d"
- " with cost=%g and nRow=%g\n",
- bestJ, pLevel-pWInfo->a, bestPlan.rCost, bestPlan.plan.nRow));
- /* The ALWAYS() that follows was added to hush up clang scan-build */
- if( (bestPlan.plan.wsFlags & WHERE_ORDERBY)!=0 && ALWAYS(ppOrderBy) ){
- *ppOrderBy = 0;
- }
+ assert( sWBI.notValid & getMask(pMaskSet, pTabList->a[bestJ].iCursor) );
+ assert( bestJ==iFrom || (pTabList->a[iFrom].jointype & JT_LEFT)==0 );
+ testcase( bestJ>iFrom && (pTabList->a[iFrom].jointype & JT_CROSS)!=0 );
+ testcase( bestJ>iFrom && bestJ<nTabList-1
+ && (pTabList->a[bestJ+1].jointype & JT_LEFT)!=0 );
+ WHERETRACE(("*** Optimizer selects table %d (%s) for loop %d with:\n"
+ " cost=%.1f, nRow=%.1f, nOBSat=%d, wsFlags=0x%08x\n",
+ bestJ, pTabList->a[bestJ].pTab->zName,
+ pLevel-pWInfo->a, bestPlan.rCost, bestPlan.plan.nRow,
+ bestPlan.plan.nOBSat, bestPlan.plan.wsFlags));
if( (bestPlan.plan.wsFlags & WHERE_DISTINCT)!=0 ){
assert( pWInfo->eDistinct==0 );
pWInfo->eDistinct = WHERE_DISTINCT_ORDERED;
}
andFlags &= bestPlan.plan.wsFlags;
pLevel->plan = bestPlan.plan;
+ pLevel->iTabCur = pTabList->a[bestJ].iCursor;
testcase( bestPlan.plan.wsFlags & WHERE_INDEXED );
testcase( bestPlan.plan.wsFlags & WHERE_TEMP_INDEX );
if( bestPlan.plan.wsFlags & (WHERE_INDEXED|WHERE_TEMP_INDEX) ){
@@ -106695,7 +109843,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
}else{
pLevel->iIdxCur = -1;
}
- notReady &= ~getMask(pMaskSet, pTabList->a[bestJ].iCursor);
+ sWBI.notValid &= ~getMask(pMaskSet, pTabList->a[bestJ].iCursor);
pLevel->iFrom = (u8)bestJ;
if( bestPlan.plan.nRow>=(double)1 ){
pParse->nQueryLoop *= bestPlan.plan.nRow;
@@ -106723,12 +109871,19 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
if( pParse->nErr || db->mallocFailed ){
goto whereBeginError;
}
+ if( nTabList ){
+ pLevel--;
+ pWInfo->nOBSat = pLevel->plan.nOBSat;
+ }else{
+ pWInfo->nOBSat = 0;
+ }
/* If the total query only selects a single row, then the ORDER BY
** clause is irrelevant.
*/
- if( (andFlags & WHERE_UNIQUE)!=0 && ppOrderBy ){
- *ppOrderBy = 0;
+ if( (andFlags & WHERE_UNIQUE)!=0 && pOrderBy ){
+ assert( nTabList==0 || (pLevel->plan.wsFlags & WHERE_ALL_UNIQUE)!=0 );
+ pWInfo->nOBSat = pOrderBy->nExpr;
}
/* If the caller is an UPDATE or DELETE statement that is requesting
@@ -106748,13 +109903,13 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */
notReady = ~(Bitmask)0;
pWInfo->nRowOut = (double)1;
- for(i=0, pLevel=pWInfo->a; i<nTabList; i++, pLevel++){
+ for(ii=0, pLevel=pWInfo->a; ii<nTabList; ii++, pLevel++){
Table *pTab; /* Table to open */
int iDb; /* Index of database containing table/index */
+ struct SrcList_item *pTabItem;
pTabItem = &pTabList->a[pLevel->iFrom];
pTab = pTabItem->pTab;
- pLevel->iTabCur = pTabItem->iCursor;
pWInfo->nRowOut *= pLevel->plan.nRow;
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ){
@@ -106765,6 +109920,8 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
int iCur = pTabItem->iCursor;
sqlite3VdbeAddOp4(v, OP_VOpen, iCur, 0, 0, pVTab, P4_VTAB);
+ }else if( IsVirtual(pTab) ){
+ /* noop */
}else
#endif
if( (pLevel->plan.wsFlags & WHERE_IDX_ONLY)==0
@@ -106786,7 +109943,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
}
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
if( (pLevel->plan.wsFlags & WHERE_TEMP_INDEX)!=0 ){
- constructAutomaticIndex(pParse, pWC, pTabItem, notReady, pLevel);
+ constructAutomaticIndex(pParse, sWBI.pWC, pTabItem, notReady, pLevel);
}else
#endif
if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){
@@ -106800,7 +109957,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
VdbeComment((v, "%s", pIx->zName));
}
sqlite3CodeVerifySchema(pParse, iDb);
- notReady &= ~getMask(pWC->pMaskSet, pTabItem->iCursor);
+ notReady &= ~getMask(sWBI.pWC->pMaskSet, pTabItem->iCursor);
}
pWInfo->iTop = sqlite3VdbeCurrentAddr(v);
if( db->mallocFailed ) goto whereBeginError;
@@ -106810,10 +109967,10 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
** program.
*/
notReady = ~(Bitmask)0;
- for(i=0; i<nTabList; i++){
- pLevel = &pWInfo->a[i];
- explainOneScan(pParse, pTabList, pLevel, i, pLevel->iFrom, wctrlFlags);
- notReady = codeOneLoopStart(pWInfo, i, wctrlFlags, notReady);
+ for(ii=0; ii<nTabList; ii++){
+ pLevel = &pWInfo->a[ii];
+ explainOneScan(pParse, pTabList, pLevel, ii, pLevel->iFrom, wctrlFlags);
+ notReady = codeOneLoopStart(pWInfo, ii, wctrlFlags, notReady);
pWInfo->iContinue = pLevel->addrCont;
}
@@ -106824,16 +109981,20 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
** the index is listed as "{}". If the primary key is used the
** index name is '*'.
*/
- for(i=0; i<nTabList; i++){
+ for(ii=0; ii<nTabList; ii++){
char *z;
int n;
- pLevel = &pWInfo->a[i];
+ int w;
+ struct SrcList_item *pTabItem;
+
+ pLevel = &pWInfo->a[ii];
+ w = pLevel->plan.wsFlags;
pTabItem = &pTabList->a[pLevel->iFrom];
z = pTabItem->zAlias;
if( z==0 ) z = pTabItem->pTab->zName;
n = sqlite3Strlen30(z);
if( n+nQPlan < sizeof(sqlite3_query_plan)-10 ){
- if( pLevel->plan.wsFlags & WHERE_IDX_ONLY ){
+ if( (w & WHERE_IDX_ONLY)!=0 && (w & WHERE_COVER_SCAN)==0 ){
memcpy(&sqlite3_query_plan[nQPlan], "{}", 2);
nQPlan += 2;
}else{
@@ -106842,12 +110003,12 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
}
sqlite3_query_plan[nQPlan++] = ' ';
}
- testcase( pLevel->plan.wsFlags & WHERE_ROWID_EQ );
- testcase( pLevel->plan.wsFlags & WHERE_ROWID_RANGE );
- if( pLevel->plan.wsFlags & (WHERE_ROWID_EQ|WHERE_ROWID_RANGE) ){
+ testcase( w & WHERE_ROWID_EQ );
+ testcase( w & WHERE_ROWID_RANGE );
+ if( w & (WHERE_ROWID_EQ|WHERE_ROWID_RANGE) ){
memcpy(&sqlite3_query_plan[nQPlan], "* ", 2);
nQPlan += 2;
- }else if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){
+ }else if( (w & WHERE_INDEXED)!=0 && (w & WHERE_COVER_SCAN)==0 ){
n = sqlite3Strlen30(pLevel->plan.u.pIdx->zName);
if( n+nQPlan < sizeof(sqlite3_query_plan)-2 ){
memcpy(&sqlite3_query_plan[nQPlan], pLevel->plan.u.pIdx->zName, n);
@@ -106908,7 +110069,7 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
sqlite3VdbeResolveLabel(v, pLevel->addrNxt);
for(j=pLevel->u.in.nIn, pIn=&pLevel->u.in.aInLoop[j-1]; j>0; j--, pIn--){
sqlite3VdbeJumpHere(v, pIn->addrInTop+1);
- sqlite3VdbeAddOp2(v, OP_Next, pIn->iCur, pIn->addrInTop);
+ sqlite3VdbeAddOp2(v, pIn->eEndLoopOp, pIn->iCur, pIn->addrInTop);
sqlite3VdbeJumpHere(v, pIn->addrInTop-1);
}
sqlite3DbFree(db, pLevel->u.in.aInLoop);
@@ -107216,6 +110377,7 @@ typedef union {
IdList* yy180;
struct {int value; int mask;} yy207;
u8 yy258;
+ u16 yy305;
struct LikeOp yy318;
TriggerStep* yy327;
ExprSpan yy342;
@@ -109166,8 +112328,6 @@ static void yy_reduce(
case 86: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ yytestcase(yyruleno==86);
case 98: /* defer_subclause_opt ::= */ yytestcase(yyruleno==98);
case 109: /* ifexists ::= */ yytestcase(yyruleno==109);
- case 120: /* distinct ::= ALL */ yytestcase(yyruleno==120);
- case 121: /* distinct ::= */ yytestcase(yyruleno==121);
case 221: /* between_op ::= BETWEEN */ yytestcase(yyruleno==221);
case 224: /* in_op ::= IN */ yytestcase(yyruleno==224);
{yygotominor.yy392 = 0;}
@@ -109177,7 +112337,6 @@ static void yy_reduce(
case 70: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==70);
case 85: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ yytestcase(yyruleno==85);
case 108: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==108);
- case 119: /* distinct ::= DISTINCT */ yytestcase(yyruleno==119);
case 222: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==222);
case 225: /* in_op ::= NOT IN */ yytestcase(yyruleno==225);
{yygotominor.yy392 = 1;}
@@ -109417,9 +112576,16 @@ static void yy_reduce(
break;
case 118: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt
orderby_opt limit_opt */
{
- yygotominor.yy159 =
sqlite3SelectNew(pParse,yymsp[-6].minor.yy442,yymsp[-5].minor.yy347,yymsp[-4].minor.yy122,yymsp[-3].minor.yy442,yymsp[-2].minor.yy122,yymsp[-1].minor.yy442,yymsp[-7].minor.yy392,yymsp[0].minor.yy64.pLimit,yymsp[0].minor.yy64.pOffset);
+ yygotominor.yy159 =
sqlite3SelectNew(pParse,yymsp[-6].minor.yy442,yymsp[-5].minor.yy347,yymsp[-4].minor.yy122,yymsp[-3].minor.yy442,yymsp[-2].minor.yy122,yymsp[-1].minor.yy442,yymsp[-7].minor.yy305,yymsp[0].minor.yy64.pLimit,yymsp[0].minor.yy64.pOffset);
}
break;
+ case 119: /* distinct ::= DISTINCT */
+{yygotominor.yy305 = SF_Distinct;}
+ break;
+ case 120: /* distinct ::= ALL */
+ case 121: /* distinct ::= */ yytestcase(yyruleno==121);
+{yygotominor.yy305 = 0;}
+ break;
case 122: /* sclp ::= selcollist COMMA */
case 246: /* idxlist_opt ::= LP idxlist RP */ yytestcase(yyruleno==246);
{yygotominor.yy442 = yymsp[-1].minor.yy442;}
@@ -109488,10 +112654,22 @@ static void yy_reduce(
{
if( yymsp[-6].minor.yy347==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy122==0 &&
yymsp[0].minor.yy180==0 ){
yygotominor.yy347 = yymsp[-4].minor.yy347;
+ }else if( yymsp[-4].minor.yy347->nSrc==1 ){
+ yygotominor.yy347 =
sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy347,0,0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy122,yymsp[0].minor.yy180);
+ if( yygotominor.yy347 ){
+ struct SrcList_item *pNew = &yygotominor.yy347->a[yygotominor.yy347->nSrc-1];
+ struct SrcList_item *pOld = yymsp[-4].minor.yy347->a;
+ pNew->zName = pOld->zName;
+ pNew->zDatabase = pOld->zDatabase;
+ pNew->pSelect = pOld->pSelect;
+ pOld->zName = pOld->zDatabase = 0;
+ pOld->pSelect = 0;
+ }
+ sqlite3SrcListDelete(pParse->db, yymsp[-4].minor.yy347);
}else{
Select *pSubquery;
sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy347);
- pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy347,0,0,0,0,0,0,0);
+ pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy347,0,0,0,0,SF_NestedFrom,0,0);
yygotominor.yy347 =
sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy347,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy122,yymsp[0].minor.yy180);
}
}
@@ -109706,7 +112884,7 @@ static void yy_reduce(
break;
case 194: /* expr ::= expr COLLATE ids */
{
- yygotominor.yy342.pExpr = sqlite3ExprSetCollByToken(pParse, yymsp[-2].minor.yy342.pExpr,
&yymsp[0].minor.yy0);
+ yygotominor.yy342.pExpr = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy342.pExpr,
&yymsp[0].minor.yy0);
yygotominor.yy342.zStart = yymsp[-2].minor.yy342.zStart;
yygotominor.yy342.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
@@ -109724,7 +112902,7 @@ static void yy_reduce(
}
yygotominor.yy342.pExpr = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy442, &yymsp[-4].minor.yy0);
spanSet(&yygotominor.yy342,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0);
- if( yymsp[-2].minor.yy392 && yygotominor.yy342.pExpr ){
+ if( yymsp[-2].minor.yy305 && yygotominor.yy342.pExpr ){
yygotominor.yy342.pExpr->flags |= EP_Distinct;
}
}
@@ -109965,11 +113143,7 @@ static void yy_reduce(
break;
case 247: /* idxlist ::= idxlist COMMA nm collate sortorder */
{
- Expr *p = 0;
- if( yymsp[-1].minor.yy0.n>0 ){
- p = sqlite3Expr(pParse->db, TK_COLUMN, 0);
- sqlite3ExprSetCollByToken(pParse, p, &yymsp[-1].minor.yy0);
- }
+ Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &yymsp[-1].minor.yy0);
yygotominor.yy442 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy442, p);
sqlite3ExprListSetName(pParse,yygotominor.yy442,&yymsp[-2].minor.yy0,1);
sqlite3ExprListCheckLength(pParse, yygotominor.yy442, "index");
@@ -109978,11 +113152,7 @@ static void yy_reduce(
break;
case 248: /* idxlist ::= nm collate sortorder */
{
- Expr *p = 0;
- if( yymsp[-1].minor.yy0.n>0 ){
- p = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0);
- sqlite3ExprSetCollByToken(pParse, p, &yymsp[-1].minor.yy0);
- }
+ Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &yymsp[-1].minor.yy0);
yygotominor.yy442 = sqlite3ExprListAppend(pParse,0, p);
sqlite3ExprListSetName(pParse, yygotominor.yy442, &yymsp[-2].minor.yy0, 1);
sqlite3ExprListCheckLength(pParse, yygotominor.yy442, "index");
@@ -110231,6 +113401,7 @@ static void yy_reduce(
/* (326) anylist ::= anylist ANY */ yytestcase(yyruleno==326);
break;
};
+ assert( yyruleno>=0 && yyruleno<sizeof(yyRuleInfo)/sizeof(yyRuleInfo[0]) );
yygoto = yyRuleInfo[yyruleno].lhs;
yysize = yyRuleInfo[yyruleno].nrhs;
yypParser->yyidx -= yysize;
@@ -111796,6 +114967,13 @@ SQLITE_API int sqlite3_initialize(void){
*/
if( sqlite3GlobalConfig.isInit ) return SQLITE_OK;
+#ifdef SQLITE_ENABLE_SQLLOG
+ {
+ extern void sqlite3_init_sqllog(void);
+ sqlite3_init_sqllog();
+ }
+#endif
+
/* Make sure the mutex subsystem is initialized. If unable to
** initialize the mutex subsystem, return early with the error.
** If the system is so sick that we are unable to allocate a mutex,
@@ -112139,6 +115317,33 @@ SQLITE_API int sqlite3_config(int op, ...){
break;
}
+ case SQLITE_CONFIG_COVERING_INDEX_SCAN: {
+ sqlite3GlobalConfig.bUseCis = va_arg(ap, int);
+ break;
+ }
+
+#ifdef SQLITE_ENABLE_SQLLOG
+ case SQLITE_CONFIG_SQLLOG: {
+ typedef void(*SQLLOGFUNC_t)(void*, sqlite3*, const char*, int);
+ sqlite3GlobalConfig.xSqllog = va_arg(ap, SQLLOGFUNC_t);
+ sqlite3GlobalConfig.pSqllogArg = va_arg(ap, void *);
+ break;
+ }
+#endif
+
+ case SQLITE_CONFIG_MMAP_SIZE: {
+ sqlite3_int64 szMmap = va_arg(ap, sqlite3_int64);
+ sqlite3_int64 mxMmap = va_arg(ap, sqlite3_int64);
+ 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.szMmap = szMmap;
+ break;
+ }
+
default: {
rc = SQLITE_ERROR;
break;
@@ -112478,6 +115683,13 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){
return SQLITE_BUSY;
}
+#ifdef SQLITE_ENABLE_SQLLOG
+ if( sqlite3GlobalConfig.xSqllog ){
+ /* Closing the handle. Fourth parameter is passed the value 2. */
+ sqlite3GlobalConfig.xSqllog(sqlite3GlobalConfig.pSqllogArg, db, 0, 2);
+ }
+#endif
+
/* Convert the connection into a zombie and then close it.
*/
db->magic = SQLITE_MAGIC_ZOMBIE;
@@ -112521,10 +115733,16 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
/* If we reach this point, it means that the database connection has
** closed all sqlite3_stmt and sqlite3_backup objects and has been
- ** pased to sqlite3_close (meaning that it is a zombie). Therefore,
+ ** passed to sqlite3_close (meaning that it is a zombie). Therefore,
** go ahead and free all resources.
*/
+ /* If a transaction is open, roll it back. This also ensures that if
+ ** any database schemas have been modified by an uncommitted transaction
+ ** they are reset. And that the required b-tree mutex is held to make
+ ** the pager rollback and schema reset an atomic operation. */
+ sqlite3RollbackAll(db, SQLITE_OK);
+
/* Free any outstanding Savepoint structures. */
sqlite3CloseSavepoints(db);
@@ -112625,6 +115843,15 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){
int inTrans = 0;
assert( sqlite3_mutex_held(db->mutex) );
sqlite3BeginBenignMalloc();
+
+ /* Obtain all b-tree mutexes before making any calls to BtreeRollback().
+ ** This is important in case the transaction being rolled back has
+ ** modified the database schema. If the b-tree mutexes are not taken
+ ** here, then another shared-cache connection might sneak in between
+ ** the database rollback and schema reset, which can cause false
+ ** corruption reports in some cases. */
+ sqlite3BtreeEnterAll(db);
+
for(i=0; i<db->nDb; i++){
Btree *p = db->aDb[i].pBt;
if( p ){
@@ -112638,10 +115865,11 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){
sqlite3VtabRollback(db);
sqlite3EndBenignMalloc();
- if( db->flags&SQLITE_InternChanges ){
+ if( (db->flags&SQLITE_InternChanges)!=0 && db->init.busy==0 ){
sqlite3ExpirePreparedStatements(db);
sqlite3ResetAllSchemasOfConnection(db);
}
+ sqlite3BtreeLeaveAll(db);
/* Any deferred constraint violations have now been resolved. */
db->nDeferredCons = 0;
@@ -112653,6 +115881,110 @@ 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) || defined(SQLITE_TEST) || \
+ defined(SQLITE_DEBUG_OS_TRACE)
+SQLITE_PRIVATE const char *sqlite3ErrName(int rc){
+ const char *zName = 0;
+ int i, origRc = rc;
+ for(i=0; i<2 && zName==0; i++, rc &= 0xff){
+ switch( rc ){
+ case SQLITE_OK: zName = "SQLITE_OK"; break;
+ case SQLITE_ERROR: zName = "SQLITE_ERROR"; break;
+ case SQLITE_INTERNAL: zName = "SQLITE_INTERNAL"; break;
+ case SQLITE_PERM: zName = "SQLITE_PERM"; break;
+ case SQLITE_ABORT: zName = "SQLITE_ABORT"; break;
+ case SQLITE_ABORT_ROLLBACK: zName = "SQLITE_ABORT_ROLLBACK"; break;
+ case SQLITE_BUSY: zName = "SQLITE_BUSY"; break;
+ case SQLITE_BUSY_RECOVERY: zName = "SQLITE_BUSY_RECOVERY"; break;
+ case SQLITE_LOCKED: zName = "SQLITE_LOCKED"; break;
+ case SQLITE_LOCKED_SHAREDCACHE: zName = "SQLITE_LOCKED_SHAREDCACHE";break;
+ case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break;
+ case SQLITE_READONLY: zName = "SQLITE_READONLY"; break;
+ case SQLITE_READONLY_RECOVERY: zName = "SQLITE_READONLY_RECOVERY"; break;
+ case SQLITE_READONLY_CANTLOCK: zName = "SQLITE_READONLY_CANTLOCK"; break;
+ case SQLITE_READONLY_ROLLBACK: zName = "SQLITE_READONLY_ROLLBACK"; break;
+ case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break;
+ case SQLITE_IOERR: zName = "SQLITE_IOERR"; break;
+ case SQLITE_IOERR_READ: zName = "SQLITE_IOERR_READ"; break;
+ case SQLITE_IOERR_SHORT_READ: zName = "SQLITE_IOERR_SHORT_READ"; break;
+ case SQLITE_IOERR_WRITE: zName = "SQLITE_IOERR_WRITE"; break;
+ case SQLITE_IOERR_FSYNC: zName = "SQLITE_IOERR_FSYNC"; break;
+ case SQLITE_IOERR_DIR_FSYNC: zName = "SQLITE_IOERR_DIR_FSYNC"; break;
+ case SQLITE_IOERR_TRUNCATE: zName = "SQLITE_IOERR_TRUNCATE"; break;
+ case SQLITE_IOERR_FSTAT: zName = "SQLITE_IOERR_FSTAT"; break;
+ case SQLITE_IOERR_UNLOCK: zName = "SQLITE_IOERR_UNLOCK"; break;
+ case SQLITE_IOERR_RDLOCK: zName = "SQLITE_IOERR_RDLOCK"; break;
+ case SQLITE_IOERR_DELETE: zName = "SQLITE_IOERR_DELETE"; break;
+ case SQLITE_IOERR_BLOCKED: zName = "SQLITE_IOERR_BLOCKED"; break;
+ case SQLITE_IOERR_NOMEM: zName = "SQLITE_IOERR_NOMEM"; break;
+ case SQLITE_IOERR_ACCESS: zName = "SQLITE_IOERR_ACCESS"; break;
+ case SQLITE_IOERR_CHECKRESERVEDLOCK:
+ zName = "SQLITE_IOERR_CHECKRESERVEDLOCK"; break;
+ case SQLITE_IOERR_LOCK: zName = "SQLITE_IOERR_LOCK"; break;
+ case SQLITE_IOERR_CLOSE: zName = "SQLITE_IOERR_CLOSE"; break;
+ case SQLITE_IOERR_DIR_CLOSE: zName = "SQLITE_IOERR_DIR_CLOSE"; break;
+ case SQLITE_IOERR_SHMOPEN: zName = "SQLITE_IOERR_SHMOPEN"; break;
+ case SQLITE_IOERR_SHMSIZE: zName = "SQLITE_IOERR_SHMSIZE"; break;
+ case SQLITE_IOERR_SHMLOCK: zName = "SQLITE_IOERR_SHMLOCK"; break;
+ case SQLITE_IOERR_SHMMAP: zName = "SQLITE_IOERR_SHMMAP"; break;
+ case SQLITE_IOERR_SEEK: zName = "SQLITE_IOERR_SEEK"; break;
+ case SQLITE_IOERR_DELETE_NOENT: zName = "SQLITE_IOERR_DELETE_NOENT";break;
+ case SQLITE_IOERR_MMAP: zName = "SQLITE_IOERR_MMAP"; break;
+ case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break;
+ case SQLITE_CORRUPT_VTAB: zName = "SQLITE_CORRUPT_VTAB"; break;
+ case SQLITE_NOTFOUND: zName = "SQLITE_NOTFOUND"; break;
+ case SQLITE_FULL: zName = "SQLITE_FULL"; break;
+ case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break;
+ case SQLITE_CANTOPEN_NOTEMPDIR: zName = "SQLITE_CANTOPEN_NOTEMPDIR";break;
+ case SQLITE_CANTOPEN_ISDIR: zName = "SQLITE_CANTOPEN_ISDIR"; break;
+ case SQLITE_CANTOPEN_FULLPATH: zName = "SQLITE_CANTOPEN_FULLPATH"; break;
+ case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break;
+ case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break;
+ case SQLITE_SCHEMA: zName = "SQLITE_SCHEMA"; break;
+ case SQLITE_TOOBIG: zName = "SQLITE_TOOBIG"; break;
+ case SQLITE_CONSTRAINT: zName = "SQLITE_CONSTRAINT"; break;
+ case SQLITE_CONSTRAINT_UNIQUE: zName = "SQLITE_CONSTRAINT_UNIQUE"; break;
+ case SQLITE_CONSTRAINT_TRIGGER: zName = "SQLITE_CONSTRAINT_TRIGGER";break;
+ case SQLITE_CONSTRAINT_FOREIGNKEY:
+ zName = "SQLITE_CONSTRAINT_FOREIGNKEY"; break;
+ case SQLITE_CONSTRAINT_CHECK: zName = "SQLITE_CONSTRAINT_CHECK"; break;
+ case SQLITE_CONSTRAINT_PRIMARYKEY:
+ zName = "SQLITE_CONSTRAINT_PRIMARYKEY"; break;
+ case SQLITE_CONSTRAINT_NOTNULL: zName = "SQLITE_CONSTRAINT_NOTNULL";break;
+ case SQLITE_CONSTRAINT_COMMITHOOK:
+ zName = "SQLITE_CONSTRAINT_COMMITHOOK"; break;
+ case SQLITE_CONSTRAINT_VTAB: zName = "SQLITE_CONSTRAINT_VTAB"; break;
+ case SQLITE_CONSTRAINT_FUNCTION:
+ zName = "SQLITE_CONSTRAINT_FUNCTION"; break;
+ case SQLITE_MISMATCH: zName = "SQLITE_MISMATCH"; break;
+ case SQLITE_MISUSE: zName = "SQLITE_MISUSE"; break;
+ case SQLITE_NOLFS: zName = "SQLITE_NOLFS"; break;
+ case SQLITE_AUTH: zName = "SQLITE_AUTH"; break;
+ case SQLITE_FORMAT: zName = "SQLITE_FORMAT"; break;
+ case SQLITE_RANGE: zName = "SQLITE_RANGE"; break;
+ case SQLITE_NOTADB: zName = "SQLITE_NOTADB"; break;
+ case SQLITE_ROW: zName = "SQLITE_ROW"; break;
+ case SQLITE_NOTICE: zName = "SQLITE_NOTICE"; break;
+ case SQLITE_NOTICE_RECOVER_WAL: zName = "SQLITE_NOTICE_RECOVER_WAL";break;
+ case SQLITE_NOTICE_RECOVER_ROLLBACK:
+ zName = "SQLITE_NOTICE_RECOVER_ROLLBACK"; break;
+ case SQLITE_WARNING: zName = "SQLITE_WARNING"; break;
+ case SQLITE_DONE: zName = "SQLITE_DONE"; break;
+ }
+ }
+ if( zName==0 ){
+ static char zBuf[50];
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "SQLITE_UNKNOWN(%d)", origRc);
+ zName = zBuf;
+ }
+ return zName;
+}
+#endif
+
+/*
** Return a static string that describes the kind of error specified in the
** argument.
*/
@@ -112780,6 +116112,7 @@ SQLITE_API int sqlite3_busy_handler(
db->busyHandler.xFunc = xBusy;
db->busyHandler.pArg = pArg;
db->busyHandler.nBusy = 0;
+ db->busyTimeout = 0;
sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
}
@@ -112817,8 +116150,8 @@ SQLITE_API void sqlite3_progress_handler(
*/
SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms){
if( ms>0 ){
- db->busyTimeout = ms;
sqlite3_busy_handler(db, sqliteDefaultBusyCallback, (void*)db);
+ db->busyTimeout = ms;
}else{
sqlite3_busy_handler(db, 0, 0);
}
@@ -113432,6 +116765,15 @@ SQLITE_API int sqlite3_extended_errcode(sqlite3 *db){
}
/*
+** Return a string that describes the kind of error specified in the
+** argument. For now, this simply calls the internal sqlite3ErrStr()
+** function.
+*/
+SQLITE_API const char *sqlite3_errstr(int rc){
+ return sqlite3ErrStr(rc);
+}
+
+/*
** Create a new collating function for database "db". The name is zName
** and the encoding is enc.
*/
@@ -113942,6 +117284,7 @@ static int openDatabase(
memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit));
db->autoCommit = 1;
db->nextAutovac = -1;
+ db->szMmap = sqlite3GlobalConfig.szMmap;
db->nextPagesize = 0;
db->flags |= SQLITE_ShortColNames | SQLITE_AutoIndex | SQLITE_EnableTrigger
#if SQLITE_DEFAULT_FILE_FORMAT<4
@@ -114100,6 +117443,13 @@ opendb_out:
db->magic = SQLITE_MAGIC_SICK;
}
*ppDb = db;
+#ifdef SQLITE_ENABLE_SQLLOG
+ if( sqlite3GlobalConfig.xSqllog ){
+ /* Opening a db handle. Fourth parameter is passed 0. */
+ void *pArg = sqlite3GlobalConfig.pSqllogArg;
+ sqlite3GlobalConfig.xSqllog(pArg, db, zFilename, 0);
+ }
+#endif
return sqlite3ApiExit(0, rc);
}
@@ -114405,7 +117755,7 @@ SQLITE_API int sqlite3_table_column_metadata(
zDataType = pCol->zType;
zCollSeq = pCol->zColl;
notnull = pCol->notNull!=0;
- primarykey = pCol->isPrimKey!=0;
+ primarykey = (pCol->colFlags & COLFLAG_PRIMKEY)!=0;
autoinc = pTab->iPKey==iCol && (pTab->tabFlags & TF_Autoincrement)!=0;
}else{
zDataType = "INTEGER";
@@ -114668,8 +118018,7 @@ SQLITE_API int sqlite3_test_control(int op, ...){
*/
case SQLITE_TESTCTRL_OPTIMIZATIONS: {
sqlite3 *db = va_arg(ap, sqlite3*);
- int x = va_arg(ap,int);
- db->flags = (x & SQLITE_OptMask) | (db->flags & ~SQLITE_OptMask);
+ db->dbOptFlags = (u16)(va_arg(ap, int) & 0xffff);
break;
}
@@ -115557,7 +118906,7 @@ struct sqlite3_tokenizer_module {
** This method should return either SQLITE_OK (0), or an SQLite error
** code. If SQLITE_OK is returned, then *ppTokenizer should be set
** to point at the newly created tokenizer structure. The generic
- ** sqlite3_tokenizer.pModule variable should not be initialised by
+ ** sqlite3_tokenizer.pModule variable should not be initialized by
** this callback. The caller will do so.
*/
int (*xCreate)(
@@ -115662,7 +119011,7 @@ int fts3_term_cnt(int iTerm, int iCol);
** May you share freely, never taking more than you give.
**
*************************************************************************
-** This is the header file for the generic hash-table implemenation
+** This is the header file for the generic hash-table implementation
** used in SQLite. We've modified it slightly to serve as a standalone
** hash table implementation for the full-text indexing module.
**
@@ -116252,7 +119601,7 @@ SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *, const
/* fts3_expr.c */
SQLITE_PRIVATE int sqlite3Fts3ExprParse(sqlite3_tokenizer *, int,
- char **, int, int, int, const char *, int, Fts3Expr **
+ char **, int, int, int, const char *, int, Fts3Expr **, char **
);
SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *);
#ifdef SQLITE_TEST
@@ -116277,6 +119626,9 @@ SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(Fts3Cursor *, Fts3Expr *, int iC
SQLITE_PRIVATE int sqlite3Fts3MsrOvfl(Fts3Cursor *, Fts3MultiSegReader *, int *);
SQLITE_PRIVATE int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr);
+/* fts3_tokenize_vtab.c */
+SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3*, Fts3Hash *);
+
/* fts3_unicode2.c (functions generated by parsing unicode text files) */
#ifdef SQLITE_ENABLE_FTS4_UNICODE61
SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int, int);
@@ -117569,7 +120921,7 @@ static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){
}else{
rc = sqlite3_reset(pCsr->pStmt);
if( rc==SQLITE_OK && ((Fts3Table *)pCsr->base.pVtab)->zContentTbl==0 ){
- /* If no row was found and no error has occured, then the %_content
+ /* If no row was found and no error has occurred, then the %_content
** table is missing a row that is present in the full-text index.
** The data structures are corrupt. */
rc = FTS_CORRUPT_VTAB;
@@ -118809,7 +122161,7 @@ static void fts3SegReaderCursorFree(Fts3MultiSegReader *pSegcsr){
}
/*
-** This function retreives the doclist for the specified term (or term
+** This function retrieves the doclist for the specified term (or term
** prefix) from the database.
*/
static int fts3TermSelect(
@@ -118973,14 +122325,12 @@ static int fts3FilterMethod(
pCsr->iLangid = 0;
if( nVal==2 ) pCsr->iLangid = sqlite3_value_int(apVal[1]);
+ assert( p->base.zErrMsg==0 );
rc = sqlite3Fts3ExprParse(p->pTokenizer, pCsr->iLangid,
- p->azColumn, p->bFts4, p->nColumn, iCol, zQuery, -1, &pCsr->pExpr
+ p->azColumn, p->bFts4, p->nColumn, iCol, zQuery, -1, &pCsr->pExpr,
+ &p->base.zErrMsg
);
if( rc!=SQLITE_OK ){
- if( rc==SQLITE_ERROR ){
- static const char *zErr = "malformed MATCH expression: [%s]";
- p->base.zErrMsg = sqlite3_mprintf(zErr, zQuery);
- }
return rc;
}
@@ -119560,7 +122910,7 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(sqlite3_tokenizer_module const
#endif
/*
-** Initialise the fts3 extension. If this extension is built as part
+** Initialize the fts3 extension. If this extension is built as part
** of the sqlite library, then this function is called directly by
** SQLite. If fts3 is built as a dynamically loadable extension, this
** function is called by the sqlite3_extension_init() entry point.
@@ -119594,7 +122944,7 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){
sqlite3Fts3SimpleTokenizerModule(&pSimple);
sqlite3Fts3PorterTokenizerModule(&pPorter);
- /* Allocate and initialise the hash-table used to store tokenizers. */
+ /* Allocate and initialize the hash-table used to store tokenizers. */
pHash = sqlite3_malloc(sizeof(Fts3Hash));
if( !pHash ){
rc = SQLITE_NOMEM;
@@ -119644,9 +122994,13 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){
db, "fts4", &fts3Module, (void *)pHash, 0
);
}
+ if( rc==SQLITE_OK ){
+ rc = sqlite3Fts3InitTok(db, (void *)pHash);
+ }
return rc;
}
+
/* An error has occurred. Delete the hash table and return the error code. */
assert( rc!=SQLITE_OK );
if( pHash ){
@@ -120741,35 +124095,39 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){
nTmp += p->pRight->pPhrase->doclist.nList;
}
nTmp += p->pPhrase->doclist.nList;
- aTmp = sqlite3_malloc(nTmp*2);
- if( !aTmp ){
- *pRc = SQLITE_NOMEM;
+ if( nTmp==0 ){
res = 0;
}else{
- char *aPoslist = p->pPhrase->doclist.pList;
- int nToken = p->pPhrase->nToken;
+ aTmp = sqlite3_malloc(nTmp*2);
+ if( !aTmp ){
+ *pRc = SQLITE_NOMEM;
+ res = 0;
+ }else{
+ char *aPoslist = p->pPhrase->doclist.pList;
+ int nToken = p->pPhrase->nToken;
- for(p=p->pParent;res && p && p->eType==FTSQUERY_NEAR; p=p->pParent){
- Fts3Phrase *pPhrase = p->pRight->pPhrase;
- int nNear = p->nNear;
- res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase);
- }
-
- aPoslist = pExpr->pRight->pPhrase->doclist.pList;
- nToken = pExpr->pRight->pPhrase->nToken;
- for(p=pExpr->pLeft; p && res; p=p->pLeft){
- int nNear;
- Fts3Phrase *pPhrase;
- assert( p->pParent && p->pParent->pLeft==p );
- nNear = p->pParent->nNear;
- pPhrase = (
- p->eType==FTSQUERY_NEAR ? p->pRight->pPhrase : p->pPhrase
- );
- res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase);
+ for(p=p->pParent;res && p && p->eType==FTSQUERY_NEAR; p=p->pParent){
+ Fts3Phrase *pPhrase = p->pRight->pPhrase;
+ int nNear = p->nNear;
+ res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase);
+ }
+
+ aPoslist = pExpr->pRight->pPhrase->doclist.pList;
+ nToken = pExpr->pRight->pPhrase->nToken;
+ for(p=pExpr->pLeft; p && res; p=p->pLeft){
+ int nNear;
+ Fts3Phrase *pPhrase;
+ assert( p->pParent && p->pParent->pLeft==p );
+ nNear = p->pParent->nNear;
+ pPhrase = (
+ p->eType==FTSQUERY_NEAR ? p->pRight->pPhrase : p->pPhrase
+ );
+ res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase);
+ }
}
- }
- sqlite3_free(aTmp);
+ sqlite3_free(aTmp);
+ }
}
return res;
@@ -121189,7 +124547,7 @@ SQLITE_PRIVATE int sqlite3Fts3EvalPhraseStats(
** of the current row.
**
** More specifically, the returned buffer contains 1 varint for each
-** occurence of the phrase in the column, stored using the normal (delta+2)
+** occurrence of the phrase in the column, stored using the normal (delta+2)
** compression and is terminated by either an 0x01 or 0x00 byte. For example,
** if the requested column contains "a b X c d X X" and the position-list
** for 'X' is requested, the buffer returned may contain:
@@ -121416,17 +124774,26 @@ static int fts3auxConnectMethod(
UNUSED_PARAMETER(pUnused);
- /* The user should specify a single argument - the name of an fts3 table. */
- if( argc!=4 ){
- *pzErr = sqlite3_mprintf(
- "wrong number of arguments to fts4aux constructor"
- );
- return SQLITE_ERROR;
- }
+ /* The user should invoke this in one of two forms:
+ **
+ ** CREATE VIRTUAL TABLE xxx USING fts4aux(fts4-table);
+ ** CREATE VIRTUAL TABLE xxx USING fts4aux(fts4-table-db, fts4-table);
+ */
+ if( argc!=4 && argc!=5 ) goto bad_args;
zDb = argv[1];
nDb = (int)strlen(zDb);
- zFts3 = argv[3];
+ if( argc==5 ){
+ if( nDb==4 && 0==sqlite3_strnicmp("temp", zDb, 4) ){
+ zDb = argv[3];
+ nDb = (int)strlen(zDb);
+ zFts3 = argv[4];
+ }else{
+ goto bad_args;
+ }
+ }else{
+ zFts3 = argv[3];
+ }
nFts3 = (int)strlen(zFts3);
rc = sqlite3_declare_vtab(db, FTS3_TERMS_SCHEMA);
@@ -121449,6 +124816,10 @@ static int fts3auxConnectMethod(
*ppVtab = (sqlite3_vtab *)p;
return SQLITE_OK;
+
+ bad_args:
+ *pzErr = sqlite3_mprintf("invalid arguments to fts4aux constructor");
+ return SQLITE_ERROR;
}
/*
@@ -121928,7 +125299,7 @@ struct ParseContext {
** This function is equivalent to the standard isspace() function.
**
** The standard isspace() can be awkward to use safely, because although it
-** is defined to accept an argument of type int, its behaviour when passed
+** is defined to accept an argument of type int, its behavior when passed
** an integer that falls outside of the range of the unsigned char type
** is undefined (and sometimes, "undefined" means segfault). This wrapper
** is defined to accept an argument of type char, and always returns 0 for
@@ -122007,7 +125378,7 @@ static int getNextToken(
rc = sqlite3Fts3OpenTokenizer(pTokenizer, pParse->iLangid, z, n, &pCursor);
if( rc==SQLITE_OK ){
const char *zToken;
- int nToken, iStart, iEnd, iPosition;
+ int nToken = 0, iStart = 0, iEnd = 0, iPosition = 0;
int nByte; /* total space to allocate */
rc = pModule->xNext(pCursor, &zToken, &nToken, &iStart, &iEnd, &iPosition);
@@ -122122,7 +125493,7 @@ static int getNextString(
int ii;
for(ii=0; rc==SQLITE_OK; ii++){
const char *zByte;
- int nByte, iBegin, iEnd, iPos;
+ int nByte = 0, iBegin = 0, iEnd = 0, iPos = 0;
rc = pModule->xNext(pCursor, &zByte, &nByte, &iBegin, &iEnd, &iPos);
if( rc==SQLITE_OK ){
Fts3PhraseToken *pToken;
@@ -122462,8 +125833,10 @@ static int fts3ExprParse(
}
pNot->eType = FTSQUERY_NOT;
pNot->pRight = p;
+ p->pParent = pNot;
if( pNotBranch ){
pNot->pLeft = pNotBranch;
+ pNotBranch->pParent = pNot;
}
pNotBranch = pNot;
p = pPrev;
@@ -122551,6 +125924,7 @@ static int fts3ExprParse(
pIter = pIter->pLeft;
}
pIter->pLeft = pRet;
+ pRet->pParent = pIter;
pRet = pNotBranch;
}
}
@@ -122568,30 +125942,184 @@ exprparse_out:
}
/*
-** Parameters z and n contain a pointer to and length of a buffer containing
-** an fts3 query expression, respectively. This function attempts to parse the
-** query expression and create a tree of Fts3Expr structures representing the
-** parsed expression. If successful, *ppExpr is set to point to the head
-** of the parsed expression tree and SQLITE_OK is returned. If an error
-** occurs, either SQLITE_NOMEM (out-of-memory error) or SQLITE_ERROR (parse
-** error) is returned and *ppExpr is set to 0.
+** Return SQLITE_ERROR if the maximum depth of the expression tree passed
+** as the only argument is more than nMaxDepth.
+*/
+static int fts3ExprCheckDepth(Fts3Expr *p, int nMaxDepth){
+ int rc = SQLITE_OK;
+ if( p ){
+ if( nMaxDepth<0 ){
+ rc = SQLITE_TOOBIG;
+ }else{
+ rc = fts3ExprCheckDepth(p->pLeft, nMaxDepth-1);
+ if( rc==SQLITE_OK ){
+ rc = fts3ExprCheckDepth(p->pRight, nMaxDepth-1);
+ }
+ }
+ }
+ return rc;
+}
+
+/*
+** This function attempts to transform the expression tree at (*pp) to
+** an equivalent but more balanced form. The tree is modified in place.
+** If successful, SQLITE_OK is returned and (*pp) set to point to the
+** new root expression node.
**
-** If parameter n is a negative number, then z is assumed to point to a
-** nul-terminated string and the length is determined using strlen().
+** nMaxDepth is the maximum allowable depth of the balanced sub-tree.
**
-** The first parameter, pTokenizer, is passed the fts3 tokenizer module to
-** use to normalize query tokens while parsing the expression. The azCol[]
-** array, which is assumed to contain nCol entries, should contain the names
-** of each column in the target fts3 table, in order from left to right.
-** Column names must be nul-terminated strings.
+** Otherwise, if an error occurs, an SQLite error code is returned and
+** expression (*pp) freed.
+*/
+static int fts3ExprBalance(Fts3Expr **pp, int nMaxDepth){
+ int rc = SQLITE_OK; /* Return code */
+ Fts3Expr *pRoot = *pp; /* Initial root node */
+ Fts3Expr *pFree = 0; /* List of free nodes. Linked by pParent. */
+ int eType = pRoot->eType; /* Type of node in this tree */
+
+ if( nMaxDepth==0 ){
+ rc = SQLITE_ERROR;
+ }
+
+ if( rc==SQLITE_OK && (eType==FTSQUERY_AND || eType==FTSQUERY_OR) ){
+ Fts3Expr **apLeaf;
+ apLeaf = (Fts3Expr **)sqlite3_malloc(sizeof(Fts3Expr *) * nMaxDepth);
+ if( 0==apLeaf ){
+ rc = SQLITE_NOMEM;
+ }else{
+ memset(apLeaf, 0, sizeof(Fts3Expr *) * nMaxDepth);
+ }
+
+ if( rc==SQLITE_OK ){
+ int i;
+ Fts3Expr *p;
+
+ /* Set $p to point to the left-most leaf in the tree of eType nodes. */
+ for(p=pRoot; p->eType==eType; p=p->pLeft){
+ assert( p->pParent==0 || p->pParent->pLeft==p );
+ assert( p->pLeft && p->pRight );
+ }
+
+ /* This loop runs once for each leaf in the tree of eType nodes. */
+ while( 1 ){
+ int iLvl;
+ Fts3Expr *pParent = p->pParent; /* Current parent of p */
+
+ assert( pParent==0 || pParent->pLeft==p );
+ p->pParent = 0;
+ if( pParent ){
+ pParent->pLeft = 0;
+ }else{
+ pRoot = 0;
+ }
+ rc = fts3ExprBalance(&p, nMaxDepth-1);
+ if( rc!=SQLITE_OK ) break;
+
+ for(iLvl=0; p && iLvl<nMaxDepth; iLvl++){
+ if( apLeaf[iLvl]==0 ){
+ apLeaf[iLvl] = p;
+ p = 0;
+ }else{
+ assert( pFree );
+ pFree->pLeft = apLeaf[iLvl];
+ pFree->pRight = p;
+ pFree->pLeft->pParent = pFree;
+ pFree->pRight->pParent = pFree;
+
+ p = pFree;
+ pFree = pFree->pParent;
+ p->pParent = 0;
+ apLeaf[iLvl] = 0;
+ }
+ }
+ if( p ){
+ sqlite3Fts3ExprFree(p);
+ rc = SQLITE_TOOBIG;
+ break;
+ }
+
+ /* If that was the last leaf node, break out of the loop */
+ if( pParent==0 ) break;
+
+ /* Set $p to point to the next leaf in the tree of eType nodes */
+ for(p=pParent->pRight; p->eType==eType; p=p->pLeft);
+
+ /* Remove pParent from the original tree. */
+ assert( pParent->pParent==0 || pParent->pParent->pLeft==pParent );
+ pParent->pRight->pParent = pParent->pParent;
+ if( pParent->pParent ){
+ pParent->pParent->pLeft = pParent->pRight;
+ }else{
+ assert( pParent==pRoot );
+ pRoot = pParent->pRight;
+ }
+
+ /* Link pParent into the free node list. It will be used as an
+ ** internal node of the new tree. */
+ pParent->pParent = pFree;
+ pFree = pParent;
+ }
+
+ if( rc==SQLITE_OK ){
+ p = 0;
+ for(i=0; i<nMaxDepth; i++){
+ if( apLeaf[i] ){
+ if( p==0 ){
+ p = apLeaf[i];
+ p->pParent = 0;
+ }else{
+ assert( pFree!=0 );
+ pFree->pRight = p;
+ pFree->pLeft = apLeaf[i];
+ pFree->pLeft->pParent = pFree;
+ pFree->pRight->pParent = pFree;
+
+ p = pFree;
+ pFree = pFree->pParent;
+ p->pParent = 0;
+ }
+ }
+ }
+ pRoot = p;
+ }else{
+ /* An error occurred. Delete the contents of the apLeaf[] array
+ ** and pFree list. Everything else is cleaned up by the call to
+ ** sqlite3Fts3ExprFree(pRoot) below. */
+ Fts3Expr *pDel;
+ for(i=0; i<nMaxDepth; i++){
+ sqlite3Fts3ExprFree(apLeaf[i]);
+ }
+ while( (pDel=pFree)!=0 ){
+ pFree = pDel->pParent;
+ sqlite3_free(pDel);
+ }
+ }
+
+ assert( pFree==0 );
+ sqlite3_free( apLeaf );
+ }
+ }
+
+ if( rc!=SQLITE_OK ){
+ sqlite3Fts3ExprFree(pRoot);
+ pRoot = 0;
+ }
+ *pp = pRoot;
+ return rc;
+}
+
+/*
+** This function is similar to sqlite3Fts3ExprParse(), with the following
+** differences:
**
-** The iDefaultCol parameter should be passed the index of the table column
-** that appears on the left-hand-side of the MATCH operator (the default
-** column to match against for tokens for which a column name is not explicitly
-** specified as part of the query string), or -1 if tokens may by default
-** match any table column.
+** 1. It does not do expression rebalancing.
+** 2. It does not check that the expression does not exceed the
+** maximum allowable depth.
+** 3. Even if it fails, *ppExpr may still be set to point to an
+** expression tree. It should be deleted using sqlite3Fts3ExprFree()
+** in this case.
*/
-SQLITE_PRIVATE int sqlite3Fts3ExprParse(
+static int fts3ExprParseUnbalanced(
sqlite3_tokenizer *pTokenizer, /* Tokenizer module */
int iLangid, /* Language id for tokenizer */
char **azCol, /* Array of column names for fts3 table */
@@ -122620,28 +126148,116 @@ SQLITE_PRIVATE int sqlite3Fts3ExprParse(
n = (int)strlen(z);
}
rc = fts3ExprParse(&sParse, z, n, ppExpr, &nParsed);
+ assert( rc==SQLITE_OK || *ppExpr==0 );
/* Check for mismatched parenthesis */
if( rc==SQLITE_OK && sParse.nNest ){
rc = SQLITE_ERROR;
+ }
+
+ return rc;
+}
+
+/*
+** Parameters z and n contain a pointer to and length of a buffer containing
+** an fts3 query expression, respectively. This function attempts to parse the
+** query expression and create a tree of Fts3Expr structures representing the
+** parsed expression. If successful, *ppExpr is set to point to the head
+** of the parsed expression tree and SQLITE_OK is returned. If an error
+** occurs, either SQLITE_NOMEM (out-of-memory error) or SQLITE_ERROR (parse
+** error) is returned and *ppExpr is set to 0.
+**
+** If parameter n is a negative number, then z is assumed to point to a
+** nul-terminated string and the length is determined using strlen().
+**
+** The first parameter, pTokenizer, is passed the fts3 tokenizer module to
+** use to normalize query tokens while parsing the expression. The azCol[]
+** array, which is assumed to contain nCol entries, should contain the names
+** of each column in the target fts3 table, in order from left to right.
+** Column names must be nul-terminated strings.
+**
+** The iDefaultCol parameter should be passed the index of the table column
+** that appears on the left-hand-side of the MATCH operator (the default
+** column to match against for tokens for which a column name is not explicitly
+** specified as part of the query string), or -1 if tokens may by default
+** match any table column.
+*/
+SQLITE_PRIVATE int sqlite3Fts3ExprParse(
+ sqlite3_tokenizer *pTokenizer, /* Tokenizer module */
+ int iLangid, /* Language id for tokenizer */
+ char **azCol, /* Array of column names for fts3 table */
+ int bFts4, /* True to allow FTS4-only syntax */
+ int nCol, /* Number of entries in azCol[] */
+ int iDefaultCol, /* Default column to query */
+ const char *z, int n, /* Text of MATCH query */
+ Fts3Expr **ppExpr, /* OUT: Parsed query structure */
+ char **pzErr /* OUT: Error message (sqlite3_malloc) */
+){
+ static const int MAX_EXPR_DEPTH = 12;
+ int rc = fts3ExprParseUnbalanced(
+ pTokenizer, iLangid, azCol, bFts4, nCol, iDefaultCol, z, n, ppExpr
+ );
+
+ /* Rebalance the expression. And check that its depth does not exceed
+ ** MAX_EXPR_DEPTH. */
+ if( rc==SQLITE_OK && *ppExpr ){
+ rc = fts3ExprBalance(ppExpr, MAX_EXPR_DEPTH);
+ if( rc==SQLITE_OK ){
+ rc = fts3ExprCheckDepth(*ppExpr, MAX_EXPR_DEPTH);
+ }
+ }
+
+ if( rc!=SQLITE_OK ){
sqlite3Fts3ExprFree(*ppExpr);
*ppExpr = 0;
+ if( rc==SQLITE_TOOBIG ){
+ *pzErr = sqlite3_mprintf(
+ "FTS expression tree is too large (maximum depth %d)", MAX_EXPR_DEPTH
+ );
+ rc = SQLITE_ERROR;
+ }else if( rc==SQLITE_ERROR ){
+ *pzErr = sqlite3_mprintf("malformed MATCH expression: [%s]", z);
+ }
}
return rc;
}
/*
+** Free a single node of an expression tree.
+*/
+static void fts3FreeExprNode(Fts3Expr *p){
+ assert( p->eType==FTSQUERY_PHRASE || p->pPhrase==0 );
+ sqlite3Fts3EvalPhraseCleanup(p->pPhrase);
+ sqlite3_free(p->aMI);
+ sqlite3_free(p);
+}
+
+/*
** Free a parsed fts3 query expression allocated by sqlite3Fts3ExprParse().
+**
+** This function would be simpler if it recursively called itself. But
+** that would mean passing a sufficiently large expression to ExprParse()
+** could cause a stack overflow.
*/
-SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *p){
- if( p ){
- assert( p->eType==FTSQUERY_PHRASE || p->pPhrase==0 );
- sqlite3Fts3ExprFree(p->pLeft);
- sqlite3Fts3ExprFree(p->pRight);
- sqlite3Fts3EvalPhraseCleanup(p->pPhrase);
- sqlite3_free(p->aMI);
- sqlite3_free(p);
+SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *pDel){
+ Fts3Expr *p;
+ assert( pDel==0 || pDel->pParent==0 );
+ for(p=pDel; p && (p->pLeft||p->pRight); p=(p->pLeft ? p->pLeft : p->pRight)){
+ assert( p->pParent==0 || p==p->pParent->pRight || p==p->pParent->pLeft );
+ }
+ while( p ){
+ Fts3Expr *pParent = p->pParent;
+ fts3FreeExprNode(p);
+ if( pParent && p==pParent->pLeft && pParent->pRight ){
+ p = pParent->pRight;
+ while( p && (p->pLeft || p->pRight) ){
+ assert( p==p->pParent->pRight || p==p->pParent->pLeft );
+ p = (p->pLeft ? p->pLeft : p->pRight);
+ }
+ }else{
+ p = pParent;
+ }
}
}
@@ -122693,6 +126309,9 @@ static int queryTestTokenizer(
** the returned expression text and then freed using sqlite3_free().
*/
static char *exprToString(Fts3Expr *pExpr, char *zBuf){
+ if( pExpr==0 ){
+ return sqlite3_mprintf("");
+ }
switch( pExpr->eType ){
case FTSQUERY_PHRASE: {
Fts3Phrase *pPhrase = pExpr->pPhrase;
@@ -122800,10 +126419,21 @@ static void fts3ExprTest(
azCol[ii] = (char *)sqlite3_value_text(argv[ii+2]);
}
- rc = sqlite3Fts3ExprParse(
- pTokenizer, 0, azCol, 0, nCol, nCol, zExpr, nExpr, &pExpr
- );
+ if( sqlite3_user_data(context) ){
+ char *zDummy = 0;
+ rc = sqlite3Fts3ExprParse(
+ pTokenizer, 0, azCol, 0, nCol, nCol, zExpr, nExpr, &pExpr, &zDummy
+ );
+ assert( rc==SQLITE_OK || pExpr==0 );
+ sqlite3_free(zDummy);
+ }else{
+ rc = fts3ExprParseUnbalanced(
+ pTokenizer, 0, azCol, 0, nCol, nCol, zExpr, nExpr, &pExpr
+ );
+ }
+
if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){
+ sqlite3Fts3ExprFree(pExpr);
sqlite3_result_error(context, "Error parsing expression", -1);
}else if( rc==SQLITE_NOMEM || !(zBuf = exprToString(pExpr, 0)) ){
sqlite3_result_error_nomem(context);
@@ -122826,9 +126456,15 @@ exprtest_out:
** with database connection db.
*/
SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3* db){
- return sqlite3_create_function(
+ int rc = sqlite3_create_function(
db, "fts3_exprtest", -1, SQLITE_UTF8, 0, fts3ExprTest, 0, 0
);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "fts3_exprtest_rebalance",
+ -1, SQLITE_UTF8, (void *)1, fts3ExprTest, 0, 0
+ );
+ }
+ return rc;
}
#endif
@@ -124119,10 +127755,10 @@ static void testFunc(
const char *azArg[64];
const char *zToken;
- int nToken;
- int iStart;
- int iEnd;
- int iPos;
+ int nToken = 0;
+ int iStart = 0;
+ int iEnd = 0;
+ int iPos = 0;
int i;
Tcl_Obj *pRet;
@@ -124296,7 +127932,7 @@ static void intTestFunc(
/*
** Set up SQL objects in database db used to access the contents of
** the hash table pointed to by argument pHash. The hash table must
-** been initialised to use string keys, and to take a private copy
+** been initialized to use string keys, and to take a private copy
** of the key when a value is inserted. i.e. by a call similar to:
**
** sqlite3Fts3HashInit(pHash, FTS3_HASH_STRING, 1);
@@ -124591,6 +128227,462 @@ SQLITE_PRIVATE void sqlite3Fts3SimpleTokenizerModule(
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */
/************** End of fts3_tokenizer1.c *************************************/
+/************** Begin file fts3_tokenize_vtab.c ******************************/
+/*
+** 2013 Apr 22
+**
+** 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 for the "fts3tokenize" virtual table module.
+** An fts3tokenize virtual table is created as follows:
+**
+** CREATE VIRTUAL TABLE <tbl> USING fts3tokenize(
+** <tokenizer-name>, <arg-1>, ...
+** );
+**
+** The table created has the following schema:
+**
+** CREATE TABLE <tbl>(input, token, start, end, position)
+**
+** When queried, the query must include a WHERE clause of type:
+**
+** input = <string>
+**
+** The virtual table module tokenizes this <string>, using the FTS3
+** tokenizer specified by the arguments to the CREATE VIRTUAL TABLE
+** statement and returns one row for each token in the result. With
+** fields set as follows:
+**
+** input: Always set to a copy of <string>
+** token: A token from the input.
+** start: Byte offset of the token within the input <string>.
+** end: Byte offset of the byte immediately following the end of the
+** token within the input string.
+** pos: Token offset of token within input.
+**
+*/
+#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
+
+/* #include <string.h> */
+/* #include <assert.h> */
+
+typedef struct Fts3tokTable Fts3tokTable;
+typedef struct Fts3tokCursor Fts3tokCursor;
+
+/*
+** Virtual table structure.
+*/
+struct Fts3tokTable {
+ sqlite3_vtab base; /* Base class used by SQLite core */
+ const sqlite3_tokenizer_module *pMod;
+ sqlite3_tokenizer *pTok;
+};
+
+/*
+** Virtual table cursor structure.
+*/
+struct Fts3tokCursor {
+ sqlite3_vtab_cursor base; /* Base class used by SQLite core */
+ char *zInput; /* Input string */
+ sqlite3_tokenizer_cursor *pCsr; /* Cursor to iterate through zInput */
+ int iRowid; /* Current 'rowid' value */
+ const char *zToken; /* Current 'token' value */
+ int nToken; /* Size of zToken in bytes */
+ int iStart; /* Current 'start' value */
+ int iEnd; /* Current 'end' value */
+ int iPos; /* Current 'pos' value */
+};
+
+/*
+** Query FTS for the tokenizer implementation named zName.
+*/
+static int fts3tokQueryTokenizer(
+ Fts3Hash *pHash,
+ const char *zName,
+ const sqlite3_tokenizer_module **pp,
+ char **pzErr
+){
+ sqlite3_tokenizer_module *p;
+ int nName = (int)strlen(zName);
+
+ p = (sqlite3_tokenizer_module *)sqlite3Fts3HashFind(pHash, zName, nName+1);
+ if( !p ){
+ *pzErr = sqlite3_mprintf("unknown tokenizer: %s", zName);
+ return SQLITE_ERROR;
+ }
+
+ *pp = p;
+ return SQLITE_OK;
+}
+
+/*
+** The second argument, argv[], is an array of pointers to nul-terminated
+** strings. This function makes a copy of the array and strings into a
+** single block of memory. It then dequotes any of the strings that appear
+** to be quoted.
+**
+** If successful, output parameter *pazDequote is set to point at the
+** array of dequoted strings and SQLITE_OK is returned. The caller is
+** responsible for eventually calling sqlite3_free() to free the array
+** in this case. Or, if an error occurs, an SQLite error code is returned.
+** The final value of *pazDequote is undefined in this case.
+*/
+static int fts3tokDequoteArray(
+ int argc, /* Number of elements in argv[] */
+ const char * const *argv, /* Input array */
+ char ***pazDequote /* Output array */
+){
+ int rc = SQLITE_OK; /* Return code */
+ if( argc==0 ){
+ *pazDequote = 0;
+ }else{
+ int i;
+ int nByte = 0;
+ char **azDequote;
+
+ for(i=0; i<argc; i++){
+ nByte += (int)(strlen(argv[i]) + 1);
+ }
+
+ *pazDequote = azDequote = sqlite3_malloc(sizeof(char *)*argc + nByte);
+ if( azDequote==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ char *pSpace = (char *)&azDequote[argc];
+ for(i=0; i<argc; i++){
+ int n = (int)strlen(argv[i]);
+ azDequote[i] = pSpace;
+ memcpy(pSpace, argv[i], n+1);
+ sqlite3Fts3Dequote(pSpace);
+ pSpace += (n+1);
+ }
+ }
+ }
+
+ return rc;
+}
+
+/*
+** Schema of the tokenizer table.
+*/
+#define FTS3_TOK_SCHEMA "CREATE TABLE x(input, token, start, end, position)"
+
+/*
+** This function does all the work for both the xConnect and xCreate methods.
+** These tables have no persistent representation of their own, so xConnect
+** and xCreate are identical operations.
+**
+** argv[0]: module name
+** argv[1]: database name
+** argv[2]: table name
+** argv[3]: first argument (tokenizer name)
+*/
+static int fts3tokConnectMethod(
+ sqlite3 *db, /* Database connection */
+ void *pHash, /* Hash table of tokenizers */
+ int argc, /* Number of elements in argv array */
+ const char * const *argv, /* xCreate/xConnect argument array */
+ sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */
+ char **pzErr /* OUT: sqlite3_malloc'd error message */
+){
+ Fts3tokTable *pTab;
+ const sqlite3_tokenizer_module *pMod = 0;
+ sqlite3_tokenizer *pTok = 0;
+ int rc;
+ char **azDequote = 0;
+ int nDequote;
+
+ rc = sqlite3_declare_vtab(db, FTS3_TOK_SCHEMA);
+ if( rc!=SQLITE_OK ) return rc;
+
+ nDequote = argc-3;
+ rc = fts3tokDequoteArray(nDequote, &argv[3], &azDequote);
+
+ if( rc==SQLITE_OK ){
+ const char *zModule;
+ if( nDequote<1 ){
+ zModule = "simple";
+ }else{
+ zModule = azDequote[0];
+ }
+ rc = fts3tokQueryTokenizer((Fts3Hash*)pHash, zModule, &pMod, pzErr);
+ }
+
+ assert( (rc==SQLITE_OK)==(pMod!=0) );
+ if( rc==SQLITE_OK ){
+ const char * const *azArg = (const char * const *)&azDequote[1];
+ rc = pMod->xCreate((nDequote>1 ? nDequote-1 : 0), azArg, &pTok);
+ }
+
+ if( rc==SQLITE_OK ){
+ pTab = (Fts3tokTable *)sqlite3_malloc(sizeof(Fts3tokTable));
+ if( pTab==0 ){
+ rc = SQLITE_NOMEM;
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ memset(pTab, 0, sizeof(Fts3tokTable));
+ pTab->pMod = pMod;
+ pTab->pTok = pTok;
+ *ppVtab = &pTab->base;
+ }else{
+ if( pTok ){
+ pMod->xDestroy(pTok);
+ }
+ }
+
+ sqlite3_free(azDequote);
+ return rc;
+}
+
+/*
+** This function does the work for both the xDisconnect and xDestroy methods.
+** These tables have no persistent representation of their own, so xDisconnect
+** and xDestroy are identical operations.
+*/
+static int fts3tokDisconnectMethod(sqlite3_vtab *pVtab){
+ Fts3tokTable *pTab = (Fts3tokTable *)pVtab;
+
+ pTab->pMod->xDestroy(pTab->pTok);
+ sqlite3_free(pTab);
+ return SQLITE_OK;
+}
+
+/*
+** xBestIndex - Analyze a WHERE and ORDER BY clause.
+*/
+static int fts3tokBestIndexMethod(
+ sqlite3_vtab *pVTab,
+ sqlite3_index_info *pInfo
+){
+ int i;
+ UNUSED_PARAMETER(pVTab);
+
+ for(i=0; i<pInfo->nConstraint; i++){
+ if( pInfo->aConstraint[i].usable
+ && pInfo->aConstraint[i].iColumn==0
+ && pInfo->aConstraint[i].op==SQLITE_INDEX_CONSTRAINT_EQ
+ ){
+ pInfo->idxNum = 1;
+ pInfo->aConstraintUsage[i].argvIndex = 1;
+ pInfo->aConstraintUsage[i].omit = 1;
+ pInfo->estimatedCost = 1;
+ return SQLITE_OK;
+ }
+ }
+
+ pInfo->idxNum = 0;
+ assert( pInfo->estimatedCost>1000000.0 );
+
+ return SQLITE_OK;
+}
+
+/*
+** xOpen - Open a cursor.
+*/
+static int fts3tokOpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){
+ Fts3tokCursor *pCsr;
+ UNUSED_PARAMETER(pVTab);
+
+ pCsr = (Fts3tokCursor *)sqlite3_malloc(sizeof(Fts3tokCursor));
+ if( pCsr==0 ){
+ return SQLITE_NOMEM;
+ }
+ memset(pCsr, 0, sizeof(Fts3tokCursor));
+
+ *ppCsr = (sqlite3_vtab_cursor *)pCsr;
+ return SQLITE_OK;
+}
+
+/*
+** Reset the tokenizer cursor passed as the only argument. As if it had
+** just been returned by fts3tokOpenMethod().
+*/
+static void fts3tokResetCursor(Fts3tokCursor *pCsr){
+ if( pCsr->pCsr ){
+ Fts3tokTable *pTab = (Fts3tokTable *)(pCsr->base.pVtab);
+ pTab->pMod->xClose(pCsr->pCsr);
+ pCsr->pCsr = 0;
+ }
+ sqlite3_free(pCsr->zInput);
+ pCsr->zInput = 0;
+ pCsr->zToken = 0;
+ pCsr->nToken = 0;
+ pCsr->iStart = 0;
+ pCsr->iEnd = 0;
+ pCsr->iPos = 0;
+ pCsr->iRowid = 0;
+}
+
+/*
+** xClose - Close a cursor.
+*/
+static int fts3tokCloseMethod(sqlite3_vtab_cursor *pCursor){
+ Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor;
+
+ fts3tokResetCursor(pCsr);
+ sqlite3_free(pCsr);
+ return SQLITE_OK;
+}
+
+/*
+** xNext - Advance the cursor to the next row, if any.
+*/
+static int fts3tokNextMethod(sqlite3_vtab_cursor *pCursor){
+ Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor;
+ Fts3tokTable *pTab = (Fts3tokTable *)(pCursor->pVtab);
+ int rc; /* Return code */
+
+ pCsr->iRowid++;
+ rc = pTab->pMod->xNext(pCsr->pCsr,
+ &pCsr->zToken, &pCsr->nToken,
+ &pCsr->iStart, &pCsr->iEnd, &pCsr->iPos
+ );
+
+ if( rc!=SQLITE_OK ){
+ fts3tokResetCursor(pCsr);
+ if( rc==SQLITE_DONE ) rc = SQLITE_OK;
+ }
+
+ return rc;
+}
+
+/*
+** xFilter - Initialize a cursor to point at the start of its data.
+*/
+static int fts3tokFilterMethod(
+ sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */
+ int idxNum, /* Strategy index */
+ const char *idxStr, /* Unused */
+ int nVal, /* Number of elements in apVal */
+ sqlite3_value **apVal /* Arguments for the indexing scheme */
+){
+ int rc = SQLITE_ERROR;
+ Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor;
+ Fts3tokTable *pTab = (Fts3tokTable *)(pCursor->pVtab);
+ UNUSED_PARAMETER(idxStr);
+ UNUSED_PARAMETER(nVal);
+
+ fts3tokResetCursor(pCsr);
+ if( idxNum==1 ){
+ const char *zByte = (const char *)sqlite3_value_text(apVal[0]);
+ int nByte = sqlite3_value_bytes(apVal[0]);
+ pCsr->zInput = sqlite3_malloc(nByte+1);
+ if( pCsr->zInput==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ memcpy(pCsr->zInput, zByte, nByte);
+ pCsr->zInput[nByte] = 0;
+ rc = pTab->pMod->xOpen(pTab->pTok, pCsr->zInput, nByte, &pCsr->pCsr);
+ if( rc==SQLITE_OK ){
+ pCsr->pCsr->pTokenizer = pTab->pTok;
+ }
+ }
+ }
+
+ if( rc!=SQLITE_OK ) return rc;
+ return fts3tokNextMethod(pCursor);
+}
+
+/*
+** xEof - Return true if the cursor is at EOF, or false otherwise.
+*/
+static int fts3tokEofMethod(sqlite3_vtab_cursor *pCursor){
+ Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor;
+ return (pCsr->zToken==0);
+}
+
+/*
+** xColumn - Return a column value.
+*/
+static int fts3tokColumnMethod(
+ sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */
+ sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */
+ int iCol /* Index of column to read value from */
+){
+ Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor;
+
+ /* CREATE TABLE x(input, token, start, end, position) */
+ switch( iCol ){
+ case 0:
+ sqlite3_result_text(pCtx, pCsr->zInput, -1, SQLITE_TRANSIENT);
+ break;
+ case 1:
+ sqlite3_result_text(pCtx, pCsr->zToken, pCsr->nToken, SQLITE_TRANSIENT);
+ break;
+ case 2:
+ sqlite3_result_int(pCtx, pCsr->iStart);
+ break;
+ case 3:
+ sqlite3_result_int(pCtx, pCsr->iEnd);
+ break;
+ default:
+ assert( iCol==4 );
+ sqlite3_result_int(pCtx, pCsr->iPos);
+ break;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** xRowid - Return the current rowid for the cursor.
+*/
+static int fts3tokRowidMethod(
+ sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */
+ sqlite_int64 *pRowid /* OUT: Rowid value */
+){
+ Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor;
+ *pRowid = (sqlite3_int64)pCsr->iRowid;
+ return SQLITE_OK;
+}
+
+/*
+** Register the fts3tok module with database connection db. Return SQLITE_OK
+** if successful or an error code if sqlite3_create_module() fails.
+*/
+SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash){
+ static const sqlite3_module fts3tok_module = {
+ 0, /* iVersion */
+ fts3tokConnectMethod, /* xCreate */
+ fts3tokConnectMethod, /* xConnect */
+ fts3tokBestIndexMethod, /* xBestIndex */
+ fts3tokDisconnectMethod, /* xDisconnect */
+ fts3tokDisconnectMethod, /* xDestroy */
+ fts3tokOpenMethod, /* xOpen */
+ fts3tokCloseMethod, /* xClose */
+ fts3tokFilterMethod, /* xFilter */
+ fts3tokNextMethod, /* xNext */
+ fts3tokEofMethod, /* xEof */
+ fts3tokColumnMethod, /* xColumn */
+ fts3tokRowidMethod, /* xRowid */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindFunction */
+ 0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0 /* xRollbackTo */
+ };
+ int rc; /* Return code */
+
+ rc = sqlite3_create_module(db, "fts3tokenize", &fts3tok_module, (void*)pHash);
+ return rc;
+}
+
+#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */
+
+/************** End of fts3_tokenize_vtab.c **********************************/
/************** Begin file fts3_write.c **************************************/
/*
** 2009 Oct 23
@@ -125369,16 +129461,16 @@ static int fts3PendingTermsAdd(
int iLangid, /* Language id to use */
const char *zText, /* Text of document to be inserted */
int iCol, /* Column into which text is being inserted */
- u32 *pnWord /* OUT: Number of tokens inserted */
+ u32 *pnWord /* IN/OUT: Incr. by number tokens inserted */
){
int rc;
- int iStart;
- int iEnd;
- int iPos;
+ int iStart = 0;
+ int iEnd = 0;
+ int iPos = 0;
int nWord = 0;
char const *zToken;
- int nToken;
+ int nToken = 0;
sqlite3_tokenizer *pTokenizer = p->pTokenizer;
sqlite3_tokenizer_module const *pModule = pTokenizer->pModule;
@@ -125433,7 +129525,7 @@ static int fts3PendingTermsAdd(
}
pModule->xClose(pCsr);
- *pnWord = nWord;
+ *pnWord += nWord;
return (rc==SQLITE_DONE ? SQLITE_OK : rc);
}
@@ -125637,11 +129729,13 @@ static void fts3DeleteTerms(
int *pRC, /* Result code */
Fts3Table *p, /* The FTS table to delete from */
sqlite3_value *pRowid, /* The docid to be deleted */
- u32 *aSz /* Sizes of deleted document written here */
+ u32 *aSz, /* Sizes of deleted document written here */
+ int *pbFound /* OUT: Set to true if row really does exist */
){
int rc;
sqlite3_stmt *pSelect;
+ assert( *pbFound==0 );
if( *pRC ) return;
rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pSelect, &pRowid);
if( rc==SQLITE_OK ){
@@ -125659,6 +129753,7 @@ static void fts3DeleteTerms(
*pRC = rc;
return;
}
+ *pbFound = 1;
}
rc = sqlite3_reset(pSelect);
}else{
@@ -126072,6 +130167,7 @@ static int fts3SegReaderNextDocid(
*pnOffsetList = (int)(p - pReader->pOffsetList - 1);
}
+ /* List may have been edited in place by fts3EvalNearTrim() */
while( p<pEnd && *p==0 ) p++;
/* If there are no more entries in the doclist, set pOffsetList to
@@ -127087,9 +131183,13 @@ static int fts3DeleteSegdir(
**
** If there are no entries in the input position list for column iCol, then
** *pnList is set to zero before returning.
+**
+** If parameter bZero is non-zero, then any part of the input list following
+** the end of the output list is zeroed before returning.
*/
static void fts3ColumnFilter(
int iCol, /* Column to filter on */
+ int bZero, /* Zero out anything following *ppList */
char **ppList, /* IN/OUT: Pointer to position list */
int *pnList /* IN/OUT: Size of buffer *ppList in bytes */
){
@@ -127118,6 +131218,9 @@ static void fts3ColumnFilter(
p += sqlite3Fts3GetVarint32(p, &iCurrent);
}
+ if( bZero && &pList[nList]!=pEnd ){
+ memset(&pList[nList], 0, pEnd - &pList[nList]);
+ }
*ppList = pList;
*pnList = nList;
}
@@ -127191,19 +131294,19 @@ SQLITE_PRIVATE int sqlite3Fts3MsrIncrNext(
if( rc!=SQLITE_OK ) return rc;
fts3SegReaderSort(pMsr->apSegment, nMerge, j, xCmp);
+ if( nList>0 && fts3SegReaderIsPending(apSegment[0]) ){
+ rc = fts3MsrBufferData(pMsr, pList, nList+1);
+ if( rc!=SQLITE_OK ) return rc;
+ assert( (pMsr->aBuffer[nList] & 0xFE)==0x00 );
+ pList = pMsr->aBuffer;
+ }
+
if( pMsr->iColFilter>=0 ){
- fts3ColumnFilter(pMsr->iColFilter, &pList, &nList);
+ fts3ColumnFilter(pMsr->iColFilter, 1, &pList, &nList);
}
if( nList>0 ){
- if( fts3SegReaderIsPending(apSegment[0]) ){
- rc = fts3MsrBufferData(pMsr, pList, nList+1);
- if( rc!=SQLITE_OK ) return rc;
- *paPoslist = pMsr->aBuffer;
- assert( (pMsr->aBuffer[nList] & 0xFE)==0x00 );
- }else{
- *paPoslist = pList;
- }
+ *paPoslist = pList;
*piDocid = iDocid;
*pnPoslist = nList;
break;
@@ -127446,7 +131549,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
}
if( isColFilter ){
- fts3ColumnFilter(pFilter->iCol, &pList, &nList);
+ fts3ColumnFilter(pFilter->iCol, 0, &pList, &nList);
}
if( !isIgnoreEmpty || nList>0 ){
@@ -127883,7 +131986,7 @@ static int fts3DoRebuild(Fts3Table *p){
int iCol;
int iLangid = langidFromSelect(p, pStmt);
rc = fts3PendingTermsDocid(p, iLangid, sqlite3_column_int64(pStmt, 0));
- aSz[p->nColumn] = 0;
+ memset(aSz, 0, sizeof(aSz[0]) * (p->nColumn+1));
for(iCol=0; rc==SQLITE_OK && iCol<p->nColumn; iCol++){
const char *z = (const char *) sqlite3_column_text(pStmt, iCol+1);
rc = fts3PendingTermsAdd(p, iLangid, z, iCol, &aSz[iCol]);
@@ -129527,9 +133630,9 @@ static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){
rc = sqlite3Fts3OpenTokenizer(p->pTokenizer, iLang, zText, nText, &pT);
while( rc==SQLITE_OK ){
char const *zToken; /* Buffer containing token */
- int nToken; /* Number of bytes in token */
- int iDum1, iDum2; /* Dummy variables */
- int iPos; /* Position of token in zText */
+ int nToken = 0; /* Number of bytes in token */
+ int iDum1 = 0, iDum2 = 0; /* Dummy variables */
+ int iPos = 0; /* Position of token in zText */
rc = pModule->xNext(pT, &zToken, &nToken, &iDum1, &iDum2, &iPos);
if( rc==SQLITE_OK ){
@@ -129696,9 +133799,9 @@ SQLITE_PRIVATE int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *pCsr){
rc = sqlite3Fts3OpenTokenizer(pT, pCsr->iLangid, zText, -1, &pTC);
while( rc==SQLITE_OK ){
char const *zToken; /* Buffer containing token */
- int nToken; /* Number of bytes in token */
- int iDum1, iDum2; /* Dummy variables */
- int iPos; /* Position of token in zText */
+ int nToken = 0; /* Number of bytes in token */
+ int iDum1 = 0, iDum2 = 0; /* Dummy variables */
+ int iPos = 0; /* Position of token in zText */
rc = pModule->xNext(pTC, &zToken, &nToken, &iDum1, &iDum2, &iPos);
for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){
@@ -129787,28 +133890,32 @@ SQLITE_PRIVATE int sqlite3Fts3DeferToken(
static int fts3DeleteByRowid(
Fts3Table *p,
sqlite3_value *pRowid,
- int *pnDoc,
+ int *pnChng, /* IN/OUT: Decrement if row is deleted */
u32 *aSzDel
){
- int isEmpty = 0;
- int rc = fts3IsEmpty(p, pRowid, &isEmpty);
- if( rc==SQLITE_OK ){
- if( isEmpty ){
- /* Deleting this row means the whole table is empty. In this case
- ** delete the contents of all three tables and throw away any
- ** data in the pendingTerms hash table. */
- rc = fts3DeleteAll(p, 1);
- *pnDoc = *pnDoc - 1;
- }else{
- fts3DeleteTerms(&rc, p, pRowid, aSzDel);
- if( p->zContentTbl==0 ){
- fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, &pRowid);
- if( sqlite3_changes(p->db) ) *pnDoc = *pnDoc - 1;
+ int rc = SQLITE_OK; /* Return code */
+ int bFound = 0; /* True if *pRowid really is in the table */
+
+ fts3DeleteTerms(&rc, p, pRowid, aSzDel, &bFound);
+ if( bFound && rc==SQLITE_OK ){
+ int isEmpty = 0; /* Deleting *pRowid leaves the table empty */
+ rc = fts3IsEmpty(p, pRowid, &isEmpty);
+ if( rc==SQLITE_OK ){
+ if( isEmpty ){
+ /* Deleting this row means the whole table is empty. In this case
+ ** delete the contents of all three tables and throw away any
+ ** data in the pendingTerms hash table. */
+ rc = fts3DeleteAll(p, 1);
+ *pnChng = 0;
+ memset(aSzDel, 0, sizeof(u32) * (p->nColumn+1) * 2);
}else{
- *pnDoc = *pnDoc - 1;
- }
- if( p->bHasDocsize ){
- fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, &pRowid);
+ *pnChng = *pnChng - 1;
+ if( p->zContentTbl==0 ){
+ fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, &pRowid);
+ }
+ if( p->bHasDocsize ){
+ fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, &pRowid);
+ }
}
}
}
@@ -129839,7 +133946,7 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
int rc = SQLITE_OK; /* Return Code */
int isRemove = 0; /* True for an UPDATE or DELETE */
u32 *aSzIns = 0; /* Sizes of inserted documents */
- u32 *aSzDel; /* Sizes of deleted documents */
+ u32 *aSzDel = 0; /* Sizes of deleted documents */
int nChng = 0; /* Net change in number of documents */
int bInsertDone = 0;
@@ -129867,13 +133974,13 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
}
/* Allocate space to hold the change in document sizes */
- aSzIns = sqlite3_malloc( sizeof(aSzIns[0])*(p->nColumn+1)*2 );
- if( aSzIns==0 ){
+ aSzDel = sqlite3_malloc( sizeof(aSzDel[0])*(p->nColumn+1)*2 );
+ if( aSzDel==0 ){
rc = SQLITE_NOMEM;
goto update_out;
}
- aSzDel = &aSzIns[p->nColumn+1];
- memset(aSzIns, 0, sizeof(aSzIns[0])*(p->nColumn+1)*2);
+ aSzIns = &aSzDel[p->nColumn+1];
+ memset(aSzDel, 0, sizeof(aSzDel[0])*(p->nColumn+1)*2);
/* If this is an INSERT operation, or an UPDATE that modifies the rowid
** value, then this operation requires constraint handling.
@@ -129958,7 +134065,7 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
}
update_out:
- sqlite3_free(aSzIns);
+ sqlite3_free(aSzDel);
sqlite3Fts3SegmentsClose(p);
return rc;
}
@@ -130379,9 +134486,9 @@ static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){
** is the snippet with the highest score, where scores are calculated
** by adding:
**
-** (a) +1 point for each occurence of a matchable phrase in the snippet.
+** (a) +1 point for each occurrence of a matchable phrase in the snippet.
**
-** (b) +1000 points for the first occurence of each matchable phrase in
+** (b) +1000 points for the first occurrence of each matchable phrase in
** the snippet for which the corresponding mCovered bit is not set.
**
** The selected snippet parameters are stored in structure *pFragment before
@@ -130566,7 +134673,7 @@ static int fts3SnippetShift(
return rc;
}
while( rc==SQLITE_OK && iCurrent<(nSnippet+nDesired) ){
- const char *ZDUMMY; int DUMMY1, DUMMY2, DUMMY3;
+ const char *ZDUMMY; int DUMMY1 = 0, DUMMY2 = 0, DUMMY3 = 0;
rc = pMod->xNext(pC, &ZDUMMY, &DUMMY1, &DUMMY2, &DUMMY3, &iCurrent);
}
pMod->xClose(pC);
@@ -130610,8 +134717,6 @@ static int fts3SnippetText(
int iCol = pFragment->iCol+1; /* Query column to extract text from */
sqlite3_tokenizer_module *pMod; /* Tokenizer module methods object */
sqlite3_tokenizer_cursor *pC; /* Tokenizer cursor open on zDoc/nDoc */
- const char *ZDUMMY; /* Dummy argument used with tokenizer */
- int DUMMY1; /* Dummy argument used with tokenizer */
zDoc = (const char *)sqlite3_column_text(pCsr->pStmt, iCol);
if( zDoc==0 ){
@@ -130630,10 +134735,23 @@ static int fts3SnippetText(
}
while( rc==SQLITE_OK ){
- int iBegin; /* Offset in zDoc of start of token */
- int iFin; /* Offset in zDoc of end of token */
- int isHighlight; /* True for highlighted terms */
-
+ const char *ZDUMMY; /* Dummy argument used with tokenizer */
+ int DUMMY1 = -1; /* Dummy argument used with tokenizer */
+ int iBegin = 0; /* Offset in zDoc of start of token */
+ int iFin = 0; /* Offset in zDoc of end of token */
+ int isHighlight = 0; /* True for highlighted terms */
+
+ /* Variable DUMMY1 is initialized to a negative value above. Elsewhere
+ ** in the FTS code the variable that the third argument to xNext points to
+ ** is initialized to zero before the first (*but not necessarily
+ ** subsequent*) call to xNext(). This is done for a particular application
+ ** that needs to know whether or not the tokenizer is being used for
+ ** snippet generation or for some other purpose.
+ **
+ ** Extreme care is required when writing code to depend on this
+ ** initialization. It is not a documented part of the tokenizer interface.
+ ** If a tokenizer is used directly by any code outside of FTS, this
+ ** convention might not be respected. */
rc = pMod->xNext(pC, &ZDUMMY, &DUMMY1, &iBegin, &iFin, &iCurrent);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_DONE ){
@@ -131323,8 +135441,6 @@ SQLITE_PRIVATE void sqlite3Fts3Offsets(
){
Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
sqlite3_tokenizer_module const *pMod = pTab->pTokenizer->pModule;
- const char *ZDUMMY; /* Dummy argument used with xNext() */
- int NDUMMY; /* Dummy argument used with xNext() */
int rc; /* Return Code */
int nToken; /* Number of tokens in query */
int iCol; /* Column currently being processed */
@@ -131357,9 +135473,11 @@ SQLITE_PRIVATE void sqlite3Fts3Offsets(
*/
for(iCol=0; iCol<pTab->nColumn; iCol++){
sqlite3_tokenizer_cursor *pC; /* Tokenizer cursor */
- int iStart;
- int iEnd;
- int iCurrent;
+ const char *ZDUMMY; /* Dummy argument used with xNext() */
+ int NDUMMY = 0; /* Dummy argument used with xNext() */
+ int iStart = 0;
+ int iEnd = 0;
+ int iCurrent = 0;
const char *zDoc;
int nDoc;
@@ -131625,7 +135743,7 @@ static int unicodeDestroy(sqlite3_tokenizer *pTokenizer){
**
** If a standalone diacritic mark (one that sqlite3FtsUnicodeIsdiacritic()
** identifies as a diacritic) occurs in the zIn/nIn string it is ignored.
-** It is not possible to change the behaviour of the tokenizer with respect
+** It is not possible to change the behavior of the tokenizer with respect
** to these codepoints.
*/
static int unicodeAddExceptions(
@@ -134923,12 +139041,12 @@ static int newRowid(Rtree *pRtree, i64 *piRowid){
*/
static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){
int rc; /* Return code */
- RtreeNode *pLeaf; /* Leaf node containing record iDelete */
+ RtreeNode *pLeaf = 0; /* Leaf node containing record iDelete */
int iCell; /* Index of iDelete cell in pLeaf */
RtreeNode *pRoot; /* Root node of rtree structure */
- /* Obtain a reference to the root node to initialise Rtree.iDepth */
+ /* Obtain a reference to the root node to initialize Rtree.iDepth */
rc = nodeAcquire(pRtree, 1, 0, &pRoot);
/* Obtain a reference to the leaf node that contains the entry
@@ -135126,7 +139244,7 @@ static int rtreeUpdate(
*/
if( rc==SQLITE_OK && nData>1 ){
/* Insert the new record into the r-tree */
- RtreeNode *pLeaf;
+ RtreeNode *pLeaf = 0;
/* Figure out the rowid of the new row. */
if( bHaveRowid==0 ){
@@ -135312,7 +139430,8 @@ static int getIntFromStmt(sqlite3 *db, const char *zSql, int *piVal){
static int getNodeSize(
sqlite3 *db, /* Database handle */
Rtree *pRtree, /* Rtree handle */
- int isCreate /* True for xCreate, false for xConnect */
+ int isCreate, /* True for xCreate, false for xConnect */
+ char **pzErr /* OUT: Error message, if any */
){
int rc;
char *zSql;
@@ -135325,6 +139444,8 @@ static int getNodeSize(
if( (4+pRtree->nBytesPerCell*RTREE_MAXCELLS)<pRtree->iNodeSize ){
pRtree->iNodeSize = 4+pRtree->nBytesPerCell*RTREE_MAXCELLS;
}
+ }else{
+ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
}
}else{
zSql = sqlite3_mprintf(
@@ -135332,6 +139453,9 @@ static int getNodeSize(
pRtree->zDb, pRtree->zName
);
rc = getIntFromStmt(db, zSql, &pRtree->iNodeSize);
+ if( rc!=SQLITE_OK ){
+ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
+ }
}
sqlite3_free(zSql);
@@ -135395,7 +139519,7 @@ static int rtreeInit(
memcpy(pRtree->zName, argv[2], nName);
/* Figure out the node size to use. */
- rc = getNodeSize(db, pRtree, isCreate);
+ rc = getNodeSize(db, pRtree, isCreate, pzErr);
/* Create/Connect to the underlying relational database schema. If
** that is successful, call sqlite3_declare_vtab() to configure
@@ -136242,7 +140366,7 @@ static int icuOpen(
nChar = nInput+1;
pCsr = (IcuCursor *)sqlite3_malloc(
sizeof(IcuCursor) + /* IcuCursor */
- nChar * sizeof(UChar) + /* IcuCursor.aChar[] */
+ ((nChar+3)&~3) * sizeof(UChar) + /* IcuCursor.aChar[] */
(nChar+1) * sizeof(int) /* IcuCursor.aOffset[] */
);
if( !pCsr ){
@@ -136250,7 +140374,7 @@ static int icuOpen(
}
memset(pCsr, 0, sizeof(IcuCursor));
pCsr->aChar = (UChar *)&pCsr[1];
- pCsr->aOffset = (int *)&pCsr->aChar[nChar];
+ pCsr->aOffset = (int *)&pCsr->aChar[(nChar+3)&~3];
pCsr->aOffset[iOut] = iInput;
U8_NEXT(zInput, iInput, nInput, c);
diff --git a/libgda/sqlite/sqlite-src/sqlite3.h b/libgda/sqlite/sqlite-src/sqlite3.h
index 5a1f9d4..e398838 100644
--- a/libgda/sqlite/sqlite-src/sqlite3.h
+++ b/libgda/sqlite/sqlite-src/sqlite3.h
@@ -107,9 +107,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.7.14.1"
-#define SQLITE_VERSION_NUMBER 3007014
-#define SQLITE_SOURCE_ID "2012-10-04 19:37:12 091570e46d04e84b67228e0bdbcd6e1fb60c6bdb"
+#define SQLITE_VERSION "3.7.17"
+#define SQLITE_VERSION_NUMBER 3007017
+#define SQLITE_SOURCE_ID "2013-05-20 00:56:22 118a3b35693b134d56ebd780123b7fd6f1497668"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -288,7 +288,7 @@ typedef sqlite_uint64 sqlite3_uint64;
** [sqlite3_blob_close | close] all [BLOB handles], and
** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated
** with the [sqlite3] object prior to attempting to close the object. ^If
-** sqlite3_close() is called on a [database connection] that still has
+** sqlite3_close_v2() is called on a [database connection] that still has
** outstanding [prepared statements], [BLOB handles], and/or
** [sqlite3_backup] objects then it returns SQLITE_OK but the deallocation
** of resources is deferred until all [prepared statements], [BLOB handles],
@@ -425,6 +425,8 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_FORMAT 24 /* Auxiliary database format error */
#define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */
#define SQLITE_NOTADB 26 /* File opened that is not a database file */
+#define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */
+#define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */
#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */
#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */
/* end-of-error-codes */
@@ -474,14 +476,29 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8))
#define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8))
#define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8))
+#define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23<<8))
+#define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24<<8))
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8))
+#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8))
#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
+#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8))
#define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8))
+#define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1<<8))
+#define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2<<8))
+#define SQLITE_CONSTRAINT_FOREIGNKEY (SQLITE_CONSTRAINT | (3<<8))
+#define SQLITE_CONSTRAINT_FUNCTION (SQLITE_CONSTRAINT | (4<<8))
+#define SQLITE_CONSTRAINT_NOTNULL (SQLITE_CONSTRAINT | (5<<8))
+#define SQLITE_CONSTRAINT_PRIMARYKEY (SQLITE_CONSTRAINT | (6<<8))
+#define SQLITE_CONSTRAINT_TRIGGER (SQLITE_CONSTRAINT | (7<<8))
+#define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8))
+#define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8))
+#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8))
+#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
/*
** CAPI3REF: Flags For File Open Operations
@@ -721,6 +738,9 @@ struct sqlite3_io_methods {
void (*xShmBarrier)(sqlite3_file*);
int (*xShmUnmap)(sqlite3_file*, int deleteFlag);
/* Methods above are valid for version 2 */
+ int (*xFetch)(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);
+ int (*xUnfetch)(sqlite3_file*, sqlite3_int64 iOfst, void *p);
+ /* Methods above are valid for version 3 */
/* Additional methods may be added in future releases */
};
@@ -855,6 +875,38 @@ struct sqlite3_io_methods {
** compilation of the PRAGMA fails with an error. ^The [SQLITE_FCNTL_PRAGMA]
** file control occurs at the beginning of pragma statement analysis and so
** it is able to override built-in [PRAGMA] statements.
+**
+** <li>[[SQLITE_FCNTL_BUSYHANDLER]]
+** ^The [SQLITE_FCNTL_BUSYHANDLER]
+** file-control may be invoked by SQLite on the database file handle
+** shortly after it is opened in order to provide a custom VFS with access
+** to the connections busy-handler callback. The argument is of type (void **)
+** - an array of two (void *) values. The first (void *) actually points
+** to a function of type (int (*)(void *)). In order to invoke the connections
+** busy-handler, this function should be invoked with the second (void *) in
+** the array as the only argument. If it returns non-zero, then the operation
+** should be retried. If it returns zero, the custom VFS should abandon the
+** current operation.
+**
+** <li>[[SQLITE_FCNTL_TEMPFILENAME]]
+** ^Application can invoke the [SQLITE_FCNTL_TEMPFILENAME] file-control
+** to have SQLite generate a
+** temporary filename using the same algorithm that is followed to generate
+** temporary filenames for TEMP tables and other internal uses. The
+** argument should be a char** which will be filled with the filename
+** written into memory obtained from [sqlite3_malloc()]. The caller should
+** invoke [sqlite3_free()] on the result to avoid a memory leak.
+**
+** <li>[[SQLITE_FCNTL_MMAP_SIZE]]
+** The [SQLITE_FCNTL_MMAP_SIZE] file control is used to query or set the
+** maximum number of bytes that will be used for memory-mapped I/O.
+** The argument is a pointer to a value of type sqlite3_int64 that
+** is an advisory maximum number of bytes in the file to memory map. The
+** pointer is overwritten with the old value. The limit is not changed if
+** the value originally pointed to is negative, and so the current limit
+** can be queried by passing in a pointer to a negative number. This
+** file-control is used internally to implement [PRAGMA mmap_size].
+**
** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE 1
@@ -871,6 +923,9 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_VFSNAME 12
#define SQLITE_FCNTL_POWERSAFE_OVERWRITE 13
#define SQLITE_FCNTL_PRAGMA 14
+#define SQLITE_FCNTL_BUSYHANDLER 15
+#define SQLITE_FCNTL_TEMPFILENAME 16
+#define SQLITE_FCNTL_MMAP_SIZE 18
/*
** CAPI3REF: Mutex Handle
@@ -1537,7 +1592,9 @@ struct sqlite3_mem_methods {
** page cache implementation into that object.)^ </dd>
**
** [[SQLITE_CONFIG_LOG]] <dt>SQLITE_CONFIG_LOG</dt>
-** <dd> ^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a
+** <dd> The SQLITE_CONFIG_LOG option is used to configure the SQLite
+** global [error log].
+** (^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a
** function with a call signature of void(*)(void*,int,const char*),
** and a pointer to void. ^If the function pointer is not NULL, it is
** invoked by [sqlite3_log()] to process each logging event. ^If the
@@ -1567,10 +1624,54 @@ struct sqlite3_mem_methods {
** disabled. The default value may be changed by compiling with the
** [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
+** 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
+** is because some incorrectly coded legacy applications might malfunction
+** malfunction when the optimization is enabled. Providing the ability to
+** disable the optimization allows the older, buggy application code to work
+** without change even with newer versions of SQLite.
+**
** [[SQLITE_CONFIG_PCACHE]] [[SQLITE_CONFIG_GETPCACHE]]
** <dt>SQLITE_CONFIG_PCACHE and SQLITE_CONFIG_GETPCACHE
** <dd> These options are obsolete and should not be used by new code.
** They are retained for backwards compatibility but are now no-ops.
+** </dd>
+**
+** [[SQLITE_CONFIG_SQLLOG]]
+** <dt>SQLITE_CONFIG_SQLLOG
+** <dd>This option is only available if sqlite is compiled with the
+** [SQLITE_ENABLE_SQLLOG] pre-processor macro defined. The first argument should
+** be a pointer to a function of type void(*)(void*,sqlite3*,const char*, int).
+** The second should be of type (void*). The callback is invoked by the library
+** in three separate circumstances, identified by the value passed as the
+** fourth parameter. If the fourth parameter is 0, then the database connection
+** passed as the second argument has just been opened. The third argument
+** points to a buffer containing the name of the main database file. If the
+** fourth parameter is 1, then the SQL statement that the third parameter
+** points to has just been executed. Or, if the fourth parameter is 2, then
+** the connection being passed as the second parameter is being closed. The
+** third parameter is passed NULL In this case. An example of using this
+** configuration option can be seen in the "test_sqllog.c" source file in
+** the canonical SQLite source tree.</dd>
+**
+** [[SQLITE_CONFIG_MMAP_SIZE]]
+** <dt>SQLITE_CONFIG_MMAP_SIZE
+** <dd>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.
+** 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
+** [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.
** </dl>
*/
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
@@ -1592,6 +1693,9 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_URI 17 /* int */
#define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */
#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */
+#define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */
+#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
+#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */
/*
** CAPI3REF: Database Connection Configuration Options
@@ -2425,6 +2529,9 @@ SQLITE_API int sqlite3_set_authorizer(
** as each triggered subprogram is entered. The callbacks for triggers
** contain a UTF-8 SQL comment that identifies the trigger.)^
**
+** The [SQLITE_TRACE_SIZE_LIMIT] compile-time option can be used to limit
+** the length of [bound parameter] expansion in the output of sqlite3_trace().
+**
** ^The callback function registered by sqlite3_profile() is invoked
** as each SQL statement finishes. ^The profile callback contains
** the original statement text and an estimate of wall-clock time
@@ -2600,7 +2707,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** an error)^.
** ^If "ro" is specified, then the database is opened for read-only
** access, just as if the [SQLITE_OPEN_READONLY] flag had been set in the
-** third argument to sqlite3_prepare_v2(). ^If the mode option is set to
+** third argument to sqlite3_open_v2(). ^If the mode option is set to
** "rw", then the database is opened for read-write (but not create)
** access, as if SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had
** been set. ^Value "rwc" is equivalent to setting both
@@ -2616,7 +2723,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** sqlite3_open_v2(). ^Setting the cache parameter to "private" is
** equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit.
** ^If sqlite3_open_v2() is used and the "cache" parameter is present in
-** a URI filename, its value overrides any behaviour requested by setting
+** a URI filename, its value overrides any behavior requested by setting
** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag.
** </ul>
**
@@ -2752,6 +2859,11 @@ SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int
** However, the error string might be overwritten or deallocated by
** subsequent calls to other SQLite interface functions.)^
**
+** ^The sqlite3_errstr() interface returns the English-language text
+** that describes the [result code], as UTF-8.
+** ^(Memory to hold the error message string is managed internally
+** and must not be freed by the application)^.
+**
** When the serialized [threading mode] is in use, it might be the
** case that a second error occurs on a separate thread in between
** the time of the first error and the call to these interfaces.
@@ -2770,6 +2882,7 @@ 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);
/*
** CAPI3REF: SQL Statement Object
@@ -2957,7 +3070,8 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** <li>
** ^If the database schema changes, instead of returning [SQLITE_SCHEMA] as it
** always used to do, [sqlite3_step()] will automatically recompile the SQL
-** statement and try to run it again.
+** statement and try to run it again. As many as [SQLITE_MAX_SCHEMA_RETRY]
+** retries will occur before sqlite3_step() gives up and returns an error.
** </li>
**
** <li>
@@ -3161,6 +3275,9 @@ typedef struct sqlite3_context sqlite3_context;
** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 999).
**
** ^The third argument is the value to bind to the parameter.
+** ^If the third parameter to sqlite3_bind_text() or sqlite3_bind_text16()
+** or sqlite3_bind_blob() is a NULL pointer then the fourth parameter
+** is ignored and the end result is the same as sqlite3_bind_null().
**
** ^(In those routines that have a fourth argument, its value is the
** number of bytes in the parameter. To be clear: the value is the
@@ -3928,7 +4045,8 @@ 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),void*,sqlite3_int64);
+SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
+ void*,sqlite3_int64);
#endif
/*
@@ -4008,14 +4126,17 @@ SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
** In those cases, sqlite3_aggregate_context() might be called for the
** first time from within xFinal().)^
**
-** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer if N is
-** less than or equal to zero or if a memory allocate error occurs.
+** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer
+** when first called if N is less than or equal to zero or if a memory
+** allocate error occurs.
**
** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is
** determined by the N parameter on first successful call. Changing the
** value of N in subsequent call to sqlite3_aggregate_context() within
** the same aggregate function instance will not resize the memory
-** allocation.)^
+** allocation.)^ Within the xFinal callback, it is customary to set
+** N=0 in calls to sqlite3_aggregate_context(C,N) so that no
+** pointless memory allocations occur.
**
** ^SQLite automatically frees the memory allocated by
** sqlite3_aggregate_context() when the aggregate query concludes.
@@ -4113,7 +4234,7 @@ SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(voi
** the content before returning.
**
** The typedef is necessary to work around problems in certain
-** C++ compilers. See ticket #2191.
+** C++ compilers.
*/
typedef void (*sqlite3_destructor_type)(void*);
#define SQLITE_STATIC ((sqlite3_destructor_type)0)
@@ -4732,6 +4853,9 @@ SQLITE_API void *sqlite3_update_hook(
** future releases of SQLite. Applications that care about shared
** cache setting should set it explicitly.
**
+** 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);
@@ -4909,11 +5033,20 @@ SQLITE_API int sqlite3_table_column_metadata(
** ^This interface loads an SQLite extension library from the named file.
**
** ^The sqlite3_load_extension() interface attempts to load an
-** SQLite extension library contained in the file zFile.
+** [SQLite extension] library contained in the file zFile. If
+** the file cannot be loaded directly, attempts are made to load
+** with various operating-system specific extensions added.
+** So for example, if "samplelib" cannot be loaded, then names like
+** "samplelib.so" or "samplelib.dylib" or "samplelib.dll" might
+** be tried also.
**
** ^The entry point is zProc.
-** ^zProc may be 0, in which case the name of the entry point
-** defaults to "sqlite3_extension_init".
+** ^(zProc may be 0, in which case SQLite will try to come up with an
+** entry point name on its own. It first tries "sqlite3_extension_init".
+** If that does not work, it constructs a name "sqlite3_X_init" where the
+** X is consists of the lower-case equivalent of all ASCII alphabetic
+** characters in the filename from the last "/" to the first following
+** "." and omitting any initial "lib".)^
** ^The sqlite3_load_extension() interface returns
** [SQLITE_OK] on success and [SQLITE_ERROR] if something goes wrong.
** ^If an error occurs and pzErrMsg is not 0, then the
@@ -4939,11 +5072,11 @@ SQLITE_API int sqlite3_load_extension(
** CAPI3REF: Enable Or Disable Extension Loading
**
** ^So as not to open security holes in older applications that are
-** unprepared to deal with extension loading, and as a means of disabling
-** extension loading while evaluating user-entered SQL, the following API
+** unprepared to deal with [extension loading], and as a means of disabling
+** [extension loading] while evaluating user-entered SQL, the following API
** is provided to turn the [sqlite3_load_extension()] mechanism on and off.
**
-** ^Extension loading is off by default. See ticket #1863.
+** ^Extension loading is off by default.
** ^Call the sqlite3_enable_load_extension() routine with onoff==1
** to turn extension loading on and call it with onoff==0 to turn
** it back off again.
@@ -4955,7 +5088,7 @@ SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
**
** ^This interface causes the xEntryPoint() function to be invoked for
** each new [database connection] that is created. The idea here is that
-** xEntryPoint() is the entry point for a statically linked SQLite extension
+** xEntryPoint() is the entry point for a statically linked [SQLite extension]
** that is to be automatically loaded into all new database connections.
**
** ^(Even though the function prototype shows that xEntryPoint() takes
@@ -6306,7 +6439,7 @@ struct sqlite3_pcache_page {
** parameter to help it determined what action to take:
**
** <table border=1 width=85% align=center>
-** <tr><th> createFlag <th> Behaviour when page is not already in cache
+** <tr><th> createFlag <th> Behavior when page is not already in cache
** <tr><td> 0 <td> Do not allocate a new page. Return NULL.
** <tr><td> 1 <td> Allocate a new page if it easy and convenient to do so.
** Otherwise return NULL.
@@ -6736,9 +6869,24 @@ SQLITE_API int sqlite3_stricmp(const char *, const char *);
SQLITE_API int sqlite3_strnicmp(const char *, const char *, int);
/*
+** CAPI3REF: String Globbing
+*
+** ^The [sqlite3_strglob(P,X)] interface returns zero if string X matches
+** the glob pattern P, and it returns non-zero if string X does not match
+** the glob pattern P. ^The definition of glob pattern matching used in
+** [sqlite3_strglob(P,X)] is the same as for the "X GLOB P" operator in the
+** SQL dialect used by SQLite. ^The sqlite3_strglob(P,X) function is case
+** sensitive.
+**
+** 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);
+
+/*
** CAPI3REF: Error Logging Interface
**
-** ^The [sqlite3_log()] interface writes a message into the error log
+** ^The [sqlite3_log()] interface writes a message into the [error log]
** established by the [SQLITE_CONFIG_LOG] option to [sqlite3_config()].
** ^If logging is enabled, the zFormat string and subsequent arguments are
** used with [sqlite3_snprintf()] to generate the final output string.
diff --git a/providers/sqlcipher/sqlcipher.patch b/providers/sqlcipher/sqlcipher.patch
index 81128dc..047ef67 100644
--- a/providers/sqlcipher/sqlcipher.patch
+++ b/providers/sqlcipher/sqlcipher.patch
@@ -1,6 +1,6 @@
---- sqlite3.c.sqlite 2012-12-22 18:15:17.484622846 +0100
-+++ sqlite3.c 2012-12-22 18:14:44.407175450 +0100
-@@ -12317,9 +12317,47 @@
+--- sqlite3.c.sqlite 2013-06-30 15:20:58.230969175 +0200
++++ sqlite3.c 2013-06-30 15:14:57.082959321 +0200
+@@ -12585,9 +12585,45 @@
#endif /* _SQLITEINT_H_ */
/************** End of sqliteInt.h *******************************************/
@@ -8,11 +8,9 @@
+/************** Begin file crypto.c ******************************************/
+/*
+** SQLCipher
-+** crypto.c developed by Stephen Lombardo (Zetetic LLC)
-+** sjlombardo at zetetic dot net
-+** http://zetetic.net
++** http://sqlcipher.net
+**
-+** Copyright (c) 2009, ZETETIC LLC
++** Copyright (c) 2008 - 2013, ZETETIC LLC
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
@@ -38,7 +36,7 @@
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**
+*/
-+/* BEGIN CRYPTO */
++/* BEGIN SQLCIPHER */
+#ifdef SQLITE_HAS_CODEC
+
+/* #include <assert.h> */
@@ -50,7 +48,7 @@
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
-@@ -12329,220 +12367,2496 @@
+@@ -12597,3032 +12633,3163 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
@@ -337,7 +335,7 @@
- 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 */
@@ -355,10 +353,6 @@
- 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 ........ */
-+/* The following value is the maximum cell size assuming a maximum page
-+** size give above.
-+*/
-+#define MX_CELL_SIZE(pBt) ((int)(pBt->pageSize-8))
- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* c0..c7 ........ */
- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* c8..cf ........ */
@@ -370,6 +364,14 @@
- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 /* f8..ff ........ */
-};
-#endif
++/* The following value is the maximum cell size assuming a maximum page
++** size give above.
++*/
++#define MX_CELL_SIZE(pBt) ((int)(pBt->pageSize-8))
+
+-#ifndef SQLITE_USE_URI
+-# define SQLITE_USE_URI 0
+-#endif
+/* 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
@@ -377,13 +379,16 @@
+*/
+#define MX_CELL(pBt) ((pBt->pageSize-8)/6)
--#ifndef SQLITE_USE_URI
--# define SQLITE_USE_URI 0
+-#ifndef SQLITE_ALLOW_COVERING_INDEX_SCAN
+-# define SQLITE_ALLOW_COVERING_INDEX_SCAN 1
+-#endif
+/* Forward declarations */
+typedef struct MemPage MemPage;
+typedef struct BtLock BtLock;
-+
-+/*
+
+ /*
+-** The following singleton contains the global configuration for
+-** the SQLite library.
+** This is a magic string that appears at the beginning of every
+** SQLite database in order to identify the file as a real database.
+**
@@ -394,22 +399,13 @@
+** the header, then your custom library will not be able to read
+** databases generated by the standard tools and the standard tools
+** will not be able to read databases created by your custom library.
-+*/
-+#ifndef SQLITE_FILE_HEADER /* 123456789 123456 */
-+# define SQLITE_FILE_HEADER "SQLite format 3"
- #endif
-
- /*
--** The following singleton contains the global configuration for
--** the SQLite library.
-+** Page type flags. An ORed combination of these flags appear as the
-+** first byte of on-disk image of every BTree page.
*/
-SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
- SQLITE_DEFAULT_MEMSTATUS, /* bMemstat */
- 1, /* bCoreMutex */
- SQLITE_THREADSAFE==1, /* bFullMutex */
- SQLITE_USE_URI, /* bOpenUri */
+- SQLITE_ALLOW_COVERING_INDEX_SCAN, /* bUseCis */
- 0x7ffffffe, /* mxStrlen */
- 128, /* szLookaside */
- 500, /* nLookaside */
@@ -419,6 +415,8 @@
- (void*)0, /* pHeap */
- 0, /* nHeap */
- 0, 0, /* mnHeap, mxHeap */
+- SQLITE_DEFAULT_MMAP_SIZE, /* szMmap */
+- SQLITE_MAX_MMAP_SIZE, /* mxMmap */
- (void*)0, /* pScratch */
- 0, /* szScratch */
- 0, /* nScratch */
@@ -438,13 +436,30 @@
- 0, /* xLog */
- 0, /* pLogArg */
- 0, /* bLocaltimeFault */
+-#ifdef SQLITE_ENABLE_SQLLOG
+- 0, /* xSqllog */
+- 0 /* pSqllogArg */
++#ifndef SQLITE_FILE_HEADER /* 123456789 123456 */
++# define SQLITE_FILE_HEADER "SQLite format 3"
+ #endif
-};
+-
+
+ /*
+-** Hash table for global functions - functions common to all
+-** database connections. After initialization, this table is
+-** read-only.
++** Page type flags. An ORed combination of these flags appear as the
++** first byte of on-disk image of every BTree page.
+ */
+-SQLITE_PRIVATE SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;
+#define PTF_INTKEY 0x01
+#define PTF_ZERODATA 0x02
+#define PTF_LEAFDATA 0x04
+#define PTF_LEAF 0x08
-+/*
+ /*
+-** 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.
@@ -456,7 +471,10 @@
+**
+** Access to all fields of this structure is controlled by the mutex
+** stored in MemPage.pBt->mutex.
-+*/
+ */
+-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[] */
@@ -481,79 +499,95 @@
+ u8 *aCellIdx; /* The cell index area */
+ DbPage *pDbPage; /* Pager page handle */
+ Pgno pgno; /* Page number for this page */
-+};
+ };
+-
/*
--** Hash table for global functions - functions common to all
--** database connections. After initialization, this table is
--** read-only.
+-** 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 operating results in undefined
+-** and dileterious 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 SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;
+-#ifndef SQLITE_OMIT_WSD
+-SQLITE_PRIVATE int sqlite3PendingByte = 0x40000000;
+-#endif
+#define EXTRA_SIZE sizeof(MemPage)
/*
--** Constant tokens for values 0 and 1.
+-** 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 Token sqlite3IntTokens[] = {
-- { "0", 1 },
-- { "1", 1 }
+-SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[] = OPFLG_INITIALIZER;
+struct BtLock {
+ Btree *pBtree; /* Btree handle holding this lock */
+ Pgno iTable; /* Root page of table */
+ u8 eLock; /* READ_LOCK or WRITE_LOCK */
+ BtLock *pNext; /* Next in BtShared.pLock list */
- };
++};
+-/************** 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
-
--/*
--** 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.
++
+/* A Btree handle
**
--** 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.
+-** 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.
**
--** 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.
+-*************************************************************************
+** 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_WSD
--SQLITE_PRIVATE int sqlite3PendingByte = 0x40000000;
+-
+-#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
+-
+struct Btree {
+ sqlite3 *db; /* The database connection holding this btree */
+ BtShared *pBt; /* Sharable content of this btree */
@@ -566,30 +600,112 @@
+ Btree *pPrev; /* Back pointer of the same list */
+#ifndef SQLITE_OMIT_SHARED_CACHE
+ BtLock lock; /* Object used to lock page 1 */
- #endif
++#endif
+};
/*
--** 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.
+-** 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.
*/
--SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[] = OPFLG_INITIALIZER;
+-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
--/************** End of global.c **********************************************/
--/************** Begin file ctime.c *******************************************/
- /*
--** 2010 February 23
--**
+-#ifdef SQLITE_32BIT_ROWID
+- "32BIT_ROWID",
+-#endif
+-#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC
+- "4_BYTE_ALIGNED_MALLOC",
+-#endif
+-#ifdef SQLITE_CASE_SENSITIVE_LIKE
+- "CASE_SENSITIVE_LIKE",
+-#endif
+-#ifdef SQLITE_CHECK_PAGES
+- "CHECK_PAGES",
+-#endif
+-#ifdef SQLITE_COVERAGE_TEST
+- "COVERAGE_TEST",
+-#endif
+-#ifdef SQLITE_DEBUG
+- "DEBUG",
+-#endif
+-#ifdef 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
+- "DISABLE_DIRSYNC",
+-#endif
+-#ifdef SQLITE_DISABLE_LFS
+- "DISABLE_LFS",
+-#endif
+-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+- "ENABLE_ATOMIC_WRITE",
+-#endif
+-#ifdef SQLITE_ENABLE_CEROD
+- "ENABLE_CEROD",
+-#endif
+-#ifdef SQLITE_ENABLE_COLUMN_METADATA
+- "ENABLE_COLUMN_METADATA",
+-#endif
+-#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
+- "ENABLE_EXPENSIVE_ASSERT",
+-#endif
+-#ifdef SQLITE_ENABLE_FTS1
+- "ENABLE_FTS1",
+-#endif
+-#ifdef SQLITE_ENABLE_FTS2
+- "ENABLE_FTS2",
+-#endif
+-#ifdef SQLITE_ENABLE_FTS3
+- "ENABLE_FTS3",
+-#endif
+-#ifdef SQLITE_ENABLE_FTS3_PARENTHESIS
+- "ENABLE_FTS3_PARENTHESIS",
+-#endif
+-#ifdef SQLITE_ENABLE_FTS4
+- "ENABLE_FTS4",
+-#endif
+-#ifdef SQLITE_ENABLE_ICU
+- "ENABLE_ICU",
+-#endif
+-#ifdef SQLITE_ENABLE_IOTRACE
+- "ENABLE_IOTRACE",
+-#endif
+-#ifdef SQLITE_ENABLE_LOAD_EXTENSION
+- "ENABLE_LOAD_EXTENSION",
+-#endif
+-#ifdef SQLITE_ENABLE_LOCKING_STYLE
+- "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE),
+-#endif
+-#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+- "ENABLE_MEMORY_MANAGEMENT",
+-#endif
+-#ifdef SQLITE_ENABLE_MEMSYS3
+- "ENABLE_MEMSYS3",
+-#endif
+-#ifdef SQLITE_ENABLE_MEMSYS5
+- "ENABLE_MEMSYS5",
+-#endif
+-#ifdef SQLITE_ENABLE_OVERSIZE_CELL_CHECK
+- "ENABLE_OVERSIZE_CELL_CHECK",
++/*
+** An instance of this object represents a single database file.
+**
+** A single database file can be in use at the same time by two
@@ -633,7 +749,10 @@
+#ifndef SQLITE_OMIT_AUTOVACUUM
+ u8 autoVacuum; /* True if auto-vacuum is enabled */
+ u8 incrVacuum; /* True if incr-vacuum is enabled */
-+#endif
++ u8 bDoTruncate; /* True to truncate db on commit */
+ #endif
+-#ifdef SQLITE_ENABLE_RTREE
+- "ENABLE_RTREE",
+ u8 inTransaction; /* Transaction state */
+ u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */
+ u16 btsFlags; /* Boolean parameters. See BTS_* macros below */
@@ -654,7 +773,9 @@
+ 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
+ #endif
+-#ifdef SQLITE_ENABLE_STAT3
+- "ENABLE_STAT3",
+ u8 *pTmpSpace; /* BtShared.pageSize bytes of space for tmp use */
+};
+
@@ -718,7 +839,9 @@
+ struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
+#ifndef SQLITE_OMIT_INCRBLOB
+ Pgno *aOverflow; /* Cache of overflow page locations */
-+#endif
+ #endif
+-#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
+- "ENABLE_UNLOCK_NOTIFY",
+ Pgno pgnoRoot; /* The root page of this tree */
+ sqlite3_int64 cachedRowid; /* Next rowid cache. 0 means not valid */
+ CellInfo info; /* A parse of the cell we are pointing at */
@@ -731,7 +854,9 @@
+ u8 eState; /* One of the CURSOR_XXX constants (see below) */
+#ifndef SQLITE_OMIT_INCRBLOB
+ u8 isIncrblobHandle; /* True if this cursor is an incr. io handle */
-+#endif
+ #endif
+-#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
+- "ENABLE_UPDATE_DELETE_LIMIT",
+ u8 hints; /* As configured by CursorSetHints() */
+ i16 iPage; /* Index of current page in apPage */
+ u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */
@@ -848,7 +973,7 @@
+#define ISAUTOVACUUM (pBt->autoVacuum)
+#else
+#define ISAUTOVACUUM 0
-+#endif
+ #endif
+
+
+/*
@@ -917,20 +1042,51 @@
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**
+*/
-+/* BEGIN CRYPTO */
-+#ifdef SQLITE_HAS_CODEC
++/* BEGIN SQLCIPHER */
+ #ifdef SQLITE_HAS_CODEC
+- "HAS_CODEC",
+-#endif
+-#ifdef SQLITE_HAVE_ISNAN
+- "HAVE_ISNAN",
+-#endif
+-#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
+- "HOMEGROWN_RECURSIVE_MUTEX",
+-#endif
+-#ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS
+- "IGNORE_AFP_LOCK_ERRORS",
+-#endif
+-#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
+- "IGNORE_FLOCK_LOCK_ERRORS",
+-#endif
+-#ifdef SQLITE_INT64_TYPE
+- "INT64_TYPE",
+-#endif
+-#ifdef SQLITE_LOCK_TRACE
+- "LOCK_TRACE",
+#ifndef CRYPTO_H
+#define CRYPTO_H
+
++#if !defined (SQLCIPHER_CRYPTO_CC) \
++ && !defined (SQLCIPHER_CRYPTO_LIBTOMCRYPT) \
++ && !defined (SQLCIPHER_CRYPTO_OPENSSL)
++#define SQLCIPHER_CRYPTO_OPENSSL
+ #endif
+-#if defined(SQLITE_MAX_MMAP_SIZE) && !defined(SQLITE_MAX_MMAP_SIZE_xc)
+- "MAX_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE),
++
+#define FILE_HEADER_SZ 16
+
+#ifndef CIPHER_VERSION
-+#define CIPHER_VERSION "2.1.1"
-+#endif
++#define CIPHER_VERSION "2.2.0"
+ #endif
+-#ifdef SQLITE_MAX_SCHEMA_RETRY
+- "MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY),
+
+#ifndef CIPHER
+#define CIPHER "aes-256-cbc"
-+#endif
+ #endif
+-#ifdef SQLITE_MEMDEBUG
+- "MEMDEBUG",
+
+#define CIPHER_DECRYPT 0
+#define CIPHER_ENCRYPT 1
@@ -941,7 +1097,9 @@
+
+#ifndef PBKDF2_ITER
+#define PBKDF2_ITER 4000
-+#endif
+ #endif
+-#ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT
+- "MIXED_ENDIAN_64BIT_FLOAT",
+
+/* possible flags for cipher_ctx->flags */
+#define CIPHER_FLAG_HMAC 0x01
@@ -950,7 +1108,9 @@
+
+#ifndef DEFAULT_CIPHER_FLAGS
+#define DEFAULT_CIPHER_FLAGS CIPHER_FLAG_HMAC | CIPHER_FLAG_LE_PGNO
-+#endif
+ #endif
+-#ifdef SQLITE_NO_SYNC
+- "NO_SYNC",
+
+
+/* by default, sqlcipher will use a reduced number of iterations to generate
@@ -958,7 +1118,9 @@
+ */
+#ifndef FAST_PBKDF2_ITER
+#define FAST_PBKDF2_ITER 2
-+#endif
+ #endif
+-#ifdef SQLITE_OMIT_ALTERTABLE
+- "OMIT_ALTERTABLE",
+
+/* 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
@@ -967,13 +1129,30 @@
+ will likely allow this to be defined at runtime via pragma */
+#ifndef HMAC_SALT_MASK
+#define HMAC_SALT_MASK 0x3a
-+#endif
+ #endif
+-#ifdef SQLITE_OMIT_ANALYZE
+- "OMIT_ANALYZE",
++
++#ifndef CIPHER_MAX_IV_SZ
++#define CIPHER_MAX_IV_SZ 16
+ #endif
+-#ifdef SQLITE_OMIT_ATTACH
+- "OMIT_ATTACH",
++
++#ifndef CIPHER_MAX_KEY_SZ
++#define CIPHER_MAX_KEY_SZ 64
+ #endif
+-#ifdef SQLITE_OMIT_AUTHORIZATION
+- "OMIT_AUTHORIZATION",
++
+
+#ifdef CODEC_DEBUG
+#define CODEC_TRACE(X) {printf X;fflush(stdout);}
+#else
+#define CODEC_TRACE(X)
-+#endif
+ #endif
+-#ifdef SQLITE_OMIT_AUTOINCREMENT
+- "OMIT_AUTOINCREMENT",
+
+#ifdef CODEC_DEBUG_PAGEDATA
+#define CODEC_HEXDUMP(DESC,BUFFER,LEN) \
@@ -989,7 +1168,9 @@
+ }
+#else
+#define CODEC_HEXDUMP(DESC,BUFFER,LEN)
-+#endif
+ #endif
+-#ifdef SQLITE_OMIT_AUTOINIT
+- "OMIT_AUTOINIT",
+
+/* extensions defined in pager.c */
+SQLITE_PRIVATE void sqlite3pager_get_codec(Pager *pPager, void **ctx);
@@ -1022,16 +1203,8 @@
+}
+
+/* extensions defined in crypto_impl.c */
-+
+typedef struct codec_ctx codec_ctx;
+
-+/* utility functions */
-+void* sqlcipher_memset(void *v, unsigned char value, int len);
-+int sqlcipher_ismemset(const void *v, unsigned char value, int len);
-+int sqlcipher_memcmp(const void *v0, const void *v1, int len);
-+int sqlcipher_pseudorandom(void *, int);
-+void sqlcipher_free(void *, int);
-+
+/* activation and initialization */
+void sqlcipher_activate();
+void sqlcipher_deactivate();
@@ -1081,21 +1254,221 @@
+int sqlcipher_codec_ctx_unset_flag(codec_ctx *ctx, unsigned int flag);
+int sqlcipher_codec_ctx_get_flag(codec_ctx *ctx, unsigned int flag, int for_ctx);
+
-+/* end extensions defined in crypto_impl.c */
-+
-+#endif
-+#endif
-+/* END CRYPTO */
-+
++const char* sqlcipher_codec_get_cipher_provider(codec_ctx *ctx);
+ #endif
+-#ifdef SQLITE_OMIT_AUTOMATIC_INDEX
+- "OMIT_AUTOMATIC_INDEX",
+ #endif
+-#ifdef SQLITE_OMIT_AUTORESET
+- "OMIT_AUTORESET",
+-#endif
+-#ifdef SQLITE_OMIT_AUTOVACUUM
+- "OMIT_AUTOVACUUM",
+-#endif
+-#ifdef SQLITE_OMIT_BETWEEN_OPTIMIZATION
+- "OMIT_BETWEEN_OPTIMIZATION",
+-#endif
+-#ifdef SQLITE_OMIT_BLOB_LITERAL
+- "OMIT_BLOB_LITERAL",
+-#endif
+-#ifdef SQLITE_OMIT_BTREECOUNT
+- "OMIT_BTREECOUNT",
+-#endif
+-#ifdef SQLITE_OMIT_BUILTIN_TEST
+- "OMIT_BUILTIN_TEST",
+-#endif
+-#ifdef SQLITE_OMIT_CAST
+- "OMIT_CAST",
+-#endif
+-#ifdef SQLITE_OMIT_CHECK
+- "OMIT_CHECK",
+-#endif
+-#ifdef SQLITE_OMIT_COMPLETE
+- "OMIT_COMPLETE",
+-#endif
+-#ifdef SQLITE_OMIT_COMPOUND_SELECT
+- "OMIT_COMPOUND_SELECT",
+-#endif
+-#ifdef SQLITE_OMIT_DATETIME_FUNCS
+- "OMIT_DATETIME_FUNCS",
+-#endif
+-#ifdef SQLITE_OMIT_DECLTYPE
+- "OMIT_DECLTYPE",
+-#endif
+-#ifdef SQLITE_OMIT_DEPRECATED
+- "OMIT_DEPRECATED",
+-#endif
+-#ifdef SQLITE_OMIT_DISKIO
+- "OMIT_DISKIO",
+-#endif
+-#ifdef SQLITE_OMIT_EXPLAIN
+- "OMIT_EXPLAIN",
+-#endif
+-#ifdef SQLITE_OMIT_FLAG_PRAGMAS
+- "OMIT_FLAG_PRAGMAS",
+-#endif
+-#ifdef SQLITE_OMIT_FLOATING_POINT
+- "OMIT_FLOATING_POINT",
+-#endif
+-#ifdef SQLITE_OMIT_FOREIGN_KEY
+- "OMIT_FOREIGN_KEY",
+-#endif
+-#ifdef SQLITE_OMIT_GET_TABLE
+- "OMIT_GET_TABLE",
+-#endif
+-#ifdef SQLITE_OMIT_INCRBLOB
+- "OMIT_INCRBLOB",
+-#endif
+-#ifdef SQLITE_OMIT_INTEGRITY_CHECK
+- "OMIT_INTEGRITY_CHECK",
+-#endif
+-#ifdef SQLITE_OMIT_LIKE_OPTIMIZATION
+- "OMIT_LIKE_OPTIMIZATION",
+-#endif
+-#ifdef SQLITE_OMIT_LOAD_EXTENSION
+- "OMIT_LOAD_EXTENSION",
+-#endif
+-#ifdef SQLITE_OMIT_LOCALTIME
+- "OMIT_LOCALTIME",
+-#endif
+-#ifdef SQLITE_OMIT_LOOKASIDE
+- "OMIT_LOOKASIDE",
+-#endif
+-#ifdef SQLITE_OMIT_MEMORYDB
+- "OMIT_MEMORYDB",
+-#endif
+-#ifdef SQLITE_OMIT_OR_OPTIMIZATION
+- "OMIT_OR_OPTIMIZATION",
+-#endif
+-#ifdef SQLITE_OMIT_PAGER_PRAGMAS
+- "OMIT_PAGER_PRAGMAS",
+-#endif
+-#ifdef SQLITE_OMIT_PRAGMA
+- "OMIT_PRAGMA",
+-#endif
+-#ifdef SQLITE_OMIT_PROGRESS_CALLBACK
+- "OMIT_PROGRESS_CALLBACK",
+-#endif
+-#ifdef SQLITE_OMIT_QUICKBALANCE
+- "OMIT_QUICKBALANCE",
+-#endif
+-#ifdef SQLITE_OMIT_REINDEX
+- "OMIT_REINDEX",
+-#endif
+-#ifdef SQLITE_OMIT_SCHEMA_PRAGMAS
+- "OMIT_SCHEMA_PRAGMAS",
+-#endif
+-#ifdef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
+- "OMIT_SCHEMA_VERSION_PRAGMAS",
+-#endif
+-#ifdef SQLITE_OMIT_SHARED_CACHE
+- "OMIT_SHARED_CACHE",
+-#endif
+-#ifdef SQLITE_OMIT_SUBQUERY
+- "OMIT_SUBQUERY",
+-#endif
+-#ifdef SQLITE_OMIT_TCL_VARIABLE
+- "OMIT_TCL_VARIABLE",
+-#endif
+-#ifdef SQLITE_OMIT_TEMPDB
+- "OMIT_TEMPDB",
+-#endif
+-#ifdef SQLITE_OMIT_TRACE
+- "OMIT_TRACE",
+-#endif
+-#ifdef SQLITE_OMIT_TRIGGER
+- "OMIT_TRIGGER",
+-#endif
+-#ifdef SQLITE_OMIT_TRUNCATE_OPTIMIZATION
+- "OMIT_TRUNCATE_OPTIMIZATION",
+-#endif
+-#ifdef SQLITE_OMIT_UTF16
+- "OMIT_UTF16",
+-#endif
+-#ifdef SQLITE_OMIT_VACUUM
+- "OMIT_VACUUM",
+-#endif
+-#ifdef SQLITE_OMIT_VIEW
+- "OMIT_VIEW",
+-#endif
+-#ifdef SQLITE_OMIT_VIRTUALTABLE
+- "OMIT_VIRTUALTABLE",
+-#endif
+-#ifdef SQLITE_OMIT_WAL
+- "OMIT_WAL",
+-#endif
+-#ifdef SQLITE_OMIT_WSD
+- "OMIT_WSD",
+-#endif
+-#ifdef SQLITE_OMIT_XFER_OPT
+- "OMIT_XFER_OPT",
+-#endif
+-#ifdef SQLITE_PERFORMANCE_TRACE
+- "PERFORMANCE_TRACE",
+-#endif
+-#ifdef SQLITE_PROXY_DEBUG
+- "PROXY_DEBUG",
+-#endif
+-#ifdef SQLITE_RTREE_INT_ONLY
+- "RTREE_INT_ONLY",
+-#endif
+-#ifdef SQLITE_SECURE_DELETE
+- "SECURE_DELETE",
+-#endif
+-#ifdef SQLITE_SMALL_STACK
+- "SMALL_STACK",
+-#endif
+-#ifdef SQLITE_SOUNDEX
+- "SOUNDEX",
+-#endif
+-#ifdef 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
+- "TEST",
+-#endif
+-#if defined(SQLITE_THREADSAFE)
+- "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE),
+-#endif
+-#ifdef SQLITE_USE_ALLOCA
+- "USE_ALLOCA",
+-#endif
+-#ifdef 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 sqlite3_compileoption_used(const char *zOptName){
+- int i, n;
+- if( sqlite3StrNICmp(zOptName, "SQLITE_", 7)==0 ) zOptName += 7;
+- n = sqlite3Strlen30(zOptName);
+/************** End of crypto.h **********************************************/
+/************** Continuing where we left off in crypto.c *********************/
-+
-+const char* codec_get_cipher_version() {
+
+- /* 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
+- && sqlite3CtypeMap[(unsigned char)azCompileOpt[i][n]]==0
+- ){
+- return 1;
++static const char* codec_get_cipher_version() {
+ return CIPHER_VERSION;
+}
+
+/* Generate code to return a string value */
-+void codec_vdbe_return_static_string(Parse *pParse, const char *zLabel, const char *value){
++static void codec_vdbe_return_static_string(Parse *pParse, const char *zLabel, const char *value){
+ Vdbe *v = sqlite3GetVdbe(pParse);
+ sqlite3VdbeSetNumCols(v, 1);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLabel, SQLITE_STATIC);
@@ -1121,7 +1494,7 @@
+ return rc;
+}
+
-+int codec_set_pass_key(sqlite3* db, int nDb, const void *zKey, int nKey, int for_ctx) {
++static int codec_set_pass_key(sqlite3* db, int nDb, const void *zKey, int nKey, int for_ctx) {
+ struct Db *pDb = &db->aDb[nDb];
+ CODEC_TRACE(("codec_set_pass_key: entered db=%p nDb=%d zKey=%s nKey=%d for_ctx=%d\n", db, nDb, (char
*)zKey, nKey, for_ctx));
+ if(pDb->pBt) {
@@ -1143,6 +1516,11 @@
+
+ CODEC_TRACE(("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_provider")==0 && !zRight ){
++ if(ctx) { codec_vdbe_return_static_string(pParse, "cipher_provider",
++ sqlcipher_codec_get_cipher_provider(ctx));
++ }
++ } else
+ if( sqlite3StrICmp(zLeft, "cipher_version")==0 && !zRight ){
+ codec_vdbe_return_static_string(pParse, "cipher_version", codec_get_cipher_version());
+ }else
@@ -1262,14 +1640,21 @@
+ codec_vdbe_return_static_string(pParse, "cipher_hmac_salt_mask", hmac_salt_mask);
+ sqlite3_free(hmac_salt_mask);
+ }
-+ }
+ }
+ }else {
+ return 0;
-+ }
+ }
+- 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 *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.
@@ -1319,9 +1704,11 @@
+ default:
+ return pData;
+ break;
-+ }
-+}
-+
+ }
+- return 0;
+ }
+
+-#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
+SQLITE_PRIVATE void sqlite3FreeCodecArg(void *pCodecArg) {
+ codec_ctx *ctx = (codec_ctx *) pCodecArg;
+ if(pCodecArg == NULL) return;
@@ -1343,13 +1730,13 @@
+
+ sqlcipher_activate(); /* perform internal initialization for sqlcipher */
+
++ sqlite3_mutex_enter(db->mutex);
++
+ /* point the internal codec argument against the contet to be prepared */
+ rc = sqlcipher_codec_ctx_init(&ctx, pDb, pDb->pBt->pBt->pPager, fd, zKey, nKey);
+
+ if(rc != SQLITE_OK) return rc; /* initialization failed, do not attach potentially corrupted context */
+
-+ sqlite3_mutex_enter(db->mutex);
-+
+ sqlite3pager_sqlite3PagerSetCodec(sqlite3BtreePager(pDb->pBt), sqlite3Codec, NULL, sqlite3FreeCodecArg,
(void *) ctx);
+
+ codec_set_btree_to_codec_pagesize(db, pDb, ctx);
@@ -1475,19 +1862,336 @@
+ }
+}
+
++#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 *****************************************/
++ * 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:
++ *
++ * 1. migrate from an non-encrypted database to an encrypted database
++ * 2. move from an encrypted database to a non-encrypted database
++ * 3. convert beween the various flavors of encrypted databases.
++ *
++ * This implementation is based heavily on the procedure and code used
++ * in vacuum.c, but is exposed as a function that allows export to any
++ * named attached database.
++ */
+
-+/* END CRYPTO */
-+#endif
+ /*
+-** 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.
++** 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 _VDBEINT_H_
+-#define _VDBEINT_H_
++static int sqlcipher_finalize(sqlite3 *db, sqlite3_stmt *pStmt, char **pzErrMsg){
++ int rc;
++ rc = sqlite3VdbeFinalize((Vdbe*)pStmt);
++ if( rc ){
++ sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db));
++ }
++ return rc;
++}
+
+ /*
+-** The maximum number of times that a statement will try to reparse
+-** itself before giving up and returning SQLITE_SCHEMA.
++** Execute zSql on database db. Return an error code.
++**
++** Based on execSql from vacuum.c
+ */
+-#ifndef SQLITE_MAX_SCHEMA_RETRY
+-# define SQLITE_MAX_SCHEMA_RETRY 50
+-#endif
++static int sqlcipher_execSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
++ sqlite3_stmt *pStmt;
++ VVA_ONLY( int rc; )
++ if( !zSql ){
++ return SQLITE_NOMEM;
++ }
++ if( SQLITE_OK!=sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){
++ sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db));
++ return sqlite3_errcode(db);
++ }
++ VVA_ONLY( rc = ) sqlite3_step(pStmt);
++ assert( rc!=SQLITE_ROW );
++ return sqlcipher_finalize(db, pStmt, pzErrMsg);
++}
+
+ /*
+-** 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. The statement returns exactly
++** one column. Execute this as SQL on the same database.
++**
++** Based on execExecSql from vacuum.c
+ */
+-typedef struct VdbeOp Op;
++static int sqlcipher_execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
++ sqlite3_stmt *pStmt;
++ int rc;
++
++ rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
++ if( rc!=SQLITE_OK ) return rc;
++
++ while( SQLITE_ROW==sqlite3_step(pStmt) ){
++ rc = sqlcipher_execSql(db, pzErrMsg, (char*)sqlite3_column_text(pStmt, 0));
++ if( rc!=SQLITE_OK ){
++ sqlcipher_finalize(db, pStmt, pzErrMsg);
++ return rc;
++ }
++ }
++
++ return sqlcipher_finalize(db, pStmt, pzErrMsg);
++}
+
+ /*
+-** Boolean values
++ * copy database and schema from the main database to an attached database
++ *
++ * Based on sqlite3RunVacuum from vacuum.c
+ */
+-typedef unsigned char Bool;
++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]);
++ int saved_flags; /* Saved value of the db->flags */
++ int saved_nChange; /* Saved value of db->nChange */
++ int saved_nTotalChange; /* Saved value of db->nTotalChange */
++ void (*saved_xTrace)(void*,const char*); /* Saved db->xTrace */
++ int rc = SQLITE_OK; /* Return code from service routines */
++ char *zSql = NULL; /* SQL statements */
++ char *pzErrMsg = NULL;
++
++ saved_flags = db->flags;
++ saved_nChange = db->nChange;
++ saved_nTotalChange = db->nTotalChange;
++ saved_xTrace = db->xTrace;
++ db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks | SQLITE_PreferBuiltin;
++ db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder);
++ db->xTrace = 0;
++
++ /* Query the schema of the main database. Create a mirror schema
++ ** in the temporary database.
++ */
++ zSql = sqlite3_mprintf(
++ "SELECT 'CREATE TABLE %s.' || substr(sql,14) "
++ " FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'"
++ " AND rootpage>0"
++ , attachedDb);
++ rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
++ if( rc!=SQLITE_OK ) goto end_of_export;
++ sqlite3_free(zSql);
++
++ zSql = sqlite3_mprintf(
++ "SELECT 'CREATE INDEX %s.' || substr(sql,14)"
++ " FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %%' "
++ , attachedDb);
++ rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
++ if( rc!=SQLITE_OK ) goto end_of_export;
++ sqlite3_free(zSql);
++
++ zSql = sqlite3_mprintf(
++ "SELECT 'CREATE UNIQUE INDEX %s.' || substr(sql,21) "
++ " FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %%'"
++ , attachedDb);
++ rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
++ if( rc!=SQLITE_OK ) goto end_of_export;
++ sqlite3_free(zSql);
++
++ /* Loop through the tables in the main database. For each, do
++ ** an "INSERT INTO rekey_db.xxx SELECT * FROM main.xxx;" to copy
++ ** the contents to the temporary database.
++ */
++ zSql = sqlite3_mprintf(
++ "SELECT 'INSERT INTO %s.' || quote(name) "
++ "|| ' SELECT * FROM main.' || quote(name) || ';'"
++ "FROM main.sqlite_master "
++ "WHERE type = 'table' AND name!='sqlite_sequence' "
++ " AND rootpage>0"
++ , attachedDb);
++ rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
++ if( rc!=SQLITE_OK ) goto end_of_export;
++ sqlite3_free(zSql);
+
++ /* Copy over the sequence table
++ */
++ zSql = sqlite3_mprintf(
++ "SELECT 'DELETE FROM %s.' || quote(name) || ';' "
++ "FROM %s.sqlite_master WHERE name='sqlite_sequence' "
++ , attachedDb, attachedDb);
++ rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
++ if( rc!=SQLITE_OK ) goto end_of_export;
++ sqlite3_free(zSql);
++
++ zSql = sqlite3_mprintf(
++ "SELECT 'INSERT INTO %s.' || quote(name) "
++ "|| ' SELECT * FROM main.' || quote(name) || ';' "
++ "FROM %s.sqlite_master WHERE name=='sqlite_sequence';"
++ , attachedDb, attachedDb);
++ rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
++ if( rc!=SQLITE_OK ) goto end_of_export;
++ sqlite3_free(zSql);
++
++ /* Copy the triggers, views, and virtual tables from the main database
++ ** over to the temporary database. None of these objects has any
++ ** associated storage, so all we have to do is copy their entries
++ ** from the SQLITE_MASTER table.
++ */
++ zSql = sqlite3_mprintf(
++ "INSERT INTO %s.sqlite_master "
++ " SELECT type, name, tbl_name, rootpage, sql"
++ " FROM main.sqlite_master"
++ " WHERE type='view' OR type='trigger'"
++ " OR (type='table' AND rootpage=0)"
++ , attachedDb);
++ rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execSql(db, &pzErrMsg, zSql);
++ if( rc!=SQLITE_OK ) goto end_of_export;
++ sqlite3_free(zSql);
++
++ zSql = NULL;
++end_of_export:
++ db->flags = saved_flags;
++ db->nChange = saved_nChange;
++ db->nTotalChange = saved_nTotalChange;
++ db->xTrace = saved_xTrace;
++
++ sqlite3_free(zSql);
++
++ if(rc) {
++ if(pzErrMsg != NULL) {
++ sqlite3_result_error(context, pzErrMsg, -1);
++ sqlite3DbFree(db, pzErrMsg);
++ } else {
++ sqlite3_result_error(context, sqlite3ErrStr(rc), -1);
++ }
++ }
++}
+
+-/* Opaque type used by code in vdbesort.c */
+-typedef struct VdbeSorter VdbeSorter;
++#endif
+
+-/* Opaque type used by the explainer */
+-typedef struct Explain Explain;
++/* END SQLCIPHER */
++#endif
+
+-/*
+-** 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.
+/************** End of crypto.c **********************************************/
+/************** Begin file crypto_impl.c *************************************/
+/*
+** SQLCipher
-+** crypto_impl.c developed by Stephen Lombardo (Zetetic LLC)
++** http://sqlcipher.net
+ **
+-** Every cursor that the virtual machine has open is represented by an
+-** instance of the following structure.
++** Copyright (c) 2008 - 2013, ZETETIC LLC
++** All rights reserved.
++**
++** 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
++** notice, this list of conditions and the following disclaimer.
++** * Redistributions in binary form must reproduce the above copyright
++** notice, this list of conditions and the following disclaimer in the
++** documentation and/or other materials provided with the distribution.
++** * 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.
++**
++** 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
++** DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY
++** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++** 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.
++**
+ */
+-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 iDb; /* Index of cursor database in db->aDb[] (or -1) */
+- int pseudoTableReg; /* Register holding pseudotable content. */
+- int nField; /* Number of fields in the header */
+- Bool zeroed; /* True if zeroed out and ready for reuse */
+- Bool rowidIsValid; /* True if lastRowid is valid */
+- Bool atFirst; /* True if pointing to first entry */
+- Bool useRandomRowid; /* Generate new record numbers semi-randomly */
+- Bool nullRow; /* True if pointing to a row with no data */
+- Bool deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
+- Bool isTable; /* True if a table requiring integer keys */
+- Bool isIndex; /* True if an index containing keys only - no data */
+- Bool isOrdered; /* True if the underlying table is BTREE_UNORDERED */
+- Bool isSorter; /* True if a new-style sorter */
+- Bool multiPseudo; /* Multi-register pseudo-cursor */
+- sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */
+- const sqlite3_module *pModule; /* Module for cursor pVtabCursor */
+- i64 seqCount; /* Sequence counter */
+- i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
+- i64 lastRowid; /* Last rowid from a Next or NextIdx operation */
+- VdbeSorter *pSorter; /* Sorter object for OP_SorterOpen cursors */
++/* BEGIN SQLCIPHER */
++#ifdef SQLITE_HAS_CODEC
+
+- /* Result of last sqlite3BtreeMoveto() done by an OP_NotExists or
+- ** OP_IsUnique opcode on this cursor. */
+- int seekResult;
++/************** Include sqlcipher.h in the middle of crypto_impl.c ***********/
++/************** Begin file sqlcipher.h ***************************************/
++/*
++** SQLCipher
++** sqlcipher.h developed by Stephen Lombardo (Zetetic LLC)
+** sjlombardo at zetetic dot net
+** http://zetetic.net
+**
-+** Copyright (c) 2011, ZETETIC LLC
++** Copyright (c) 2008, ZETETIC LLC
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
@@ -1513,12 +2217,66 @@
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**
+*/
-+/* BEGIN CRYPTO */
++/* BEGIN SQLCIPHER */
+#ifdef SQLITE_HAS_CODEC
++#ifndef SQLCIPHER_H
++#define SQLCIPHER_H
+
+- /* 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 */
+- int payloadSize; /* Total number of bytes in the record */
+- u32 *aType; /* Type values for all entries in the record */
+- u32 *aOffset; /* Cached offsets to the start of each columns data */
+- u8 *aRow; /* Data for the current row, if all on one page */
+
-+#include <openssl/rand.h>
-+#include <openssl/evp.h>
-+#include <openssl/hmac.h>
++typedef struct {
++ int (*activate)(void *ctx);
++ int (*deactivate)(void *ctx);
++ const char* (*get_provider_name)(void *ctx);
++ int (*add_random)(void *ctx, void *buffer, int length);
++ int (*random)(void *ctx, void *buffer, int length);
++ int (*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);
++ int (*kdf)(void *ctx, const char *pass, int pass_sz, unsigned char* salt, int salt_sz, int workfactor,
int key_sz, unsigned char *key);
++ int (*cipher)(void *ctx, int mode, unsigned char *key, int key_sz, unsigned char *iv, unsigned char *in,
int in_sz, unsigned char *out);
++ int (*set_cipher)(void *ctx, const char *cipher_name);
++ const char* (*get_cipher)(void *ctx);
++ int (*get_key_sz)(void *ctx);
++ int (*get_iv_sz)(void *ctx);
++ int (*get_block_sz)(void *ctx);
++ int (*get_hmac_sz)(void *ctx);
++ int (*ctx_copy)(void *target_ctx, void *source_ctx);
++ int (*ctx_cmp)(void *c1, void *c2);
++ int (*ctx_init)(void **ctx);
++ int (*ctx_free)(void **ctx);
++} sqlcipher_provider;
++
++/* utility functions */
++void sqlcipher_free(void *ptr, int sz);
++void* sqlcipher_malloc(int sz);
++void* sqlcipher_memset(void *v, unsigned char value, int len);
++int sqlcipher_ismemset(const void *v, unsigned char value, int len);
++int sqlcipher_memcmp(const void *v0, const void *v1, int len);
++void sqlcipher_free(void *, int);
++
++/* provider interfaces */
++int sqlcipher_register_provider(sqlcipher_provider *p);
++sqlcipher_provider* sqlcipher_get_provider();
++
++#endif
++#endif
++/* END SQLCIPHER */
++
++
++/************** End of sqlcipher.h *******************************************/
++/************** Continuing where we left off in crypto_impl.c ****************/
+#ifndef OMIT_MEMLOCK
+#if defined(__unix__) || defined(__APPLE__)
+#include <sys/mman.h>
@@ -1532,9 +2290,6 @@
+ struct and associated functions are defined here */
+typedef struct {
+ int derive_key;
-+ EVP_CIPHER *evp_cipher;
-+ EVP_CIPHER_CTX ectx;
-+ HMAC_CTX hctx;
+ int kdf_iter;
+ int fast_kdf_iter;
+ int key_sz;
@@ -1547,23 +2302,14 @@
+ unsigned char *key;
+ unsigned char *hmac_key;
+ char *pass;
++ sqlcipher_provider *provider;
++ void *provider_ctx;
+} cipher_ctx;
+
-+void sqlcipher_cipher_ctx_free(cipher_ctx **);
-+int sqlcipher_cipher_ctx_cmp(cipher_ctx *, cipher_ctx *);
-+int sqlcipher_cipher_ctx_copy(cipher_ctx *, cipher_ctx *);
-+int sqlcipher_cipher_ctx_init(cipher_ctx **);
-+int sqlcipher_cipher_ctx_set_pass(cipher_ctx *, const void *, int);
-+int sqlcipher_cipher_ctx_key_derive(codec_ctx *, cipher_ctx *);
-+
-+/* prototype for pager HMAC function */
-+int sqlcipher_page_hmac(cipher_ctx *, Pgno, unsigned char *, int, unsigned char *);
-+
+static unsigned int default_flags = DEFAULT_CIPHER_FLAGS;
+static unsigned char hmac_salt_mask = HMAC_SALT_MASK;
+
-+static unsigned int openssl_external_init = 0;
-+static unsigned int openssl_init_count = 0;
++static sqlcipher_provider *default_provider = NULL;
+
+struct codec_ctx {
+ int kdf_salt_sz;
@@ -1574,90 +2320,328 @@
+ Btree *pBt;
+ cipher_ctx *read_ctx;
+ cipher_ctx *write_ctx;
-+};
-+
-+/* 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.
-+ Thus it performs some basic counting to ensure that only the last and final
-+ sqlcipher_deactivate() will free the EVP structures.
-+*/
+ };
+-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 */
+- 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.nChanges) */
+-};
+-
+-#define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))])
++int sqlcipher_register_provider(sqlcipher_provider *p) {
++ if(default_provider != NULL && default_provider != p) {
++ /* only free the current registerd provider if it has been initialized
++ and it isn't a pointer to the same provider passed to the function
++ (i.e. protect against a caller calling register twice for the same provider) */
++ sqlcipher_free(default_provider, sizeof(sqlcipher_provider));
++ }
++ default_provider = p;
++ return SQLITE_OK;
++}
+
+-/*
+-** A value for VdbeCursor.cacheValid that means the cache is always invalid.
+-*/
+-#define CACHE_STALE 0
++/* 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;
++}
+
+-/*
+-** 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 {
+- sqlite3 *db; /* The associated database connection */
+- char *z; /* String or BLOB value */
+- double r; /* Real value */
+- union {
+- 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 type; /* One of SQLITE_NULL, SQLITE_TEXT, SQLITE_INTEGER, etc */
+- u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */
+-#ifdef SQLITE_DEBUG
+- Mem *pScopyFrom; /* This Mem is a shallow copy of pScopyFrom */
+- void *pFiller; /* So that sizeof(Mem) is a multiple of 8 */
+void sqlcipher_activate() {
++ sqlcipher_provider *p;
+ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
-+
-+ /* we'll initialize openssl and increment the internal init counter
-+ but only if it hasn't been initalized outside of SQLCipher by this program
-+ e.g. on startup */
-+ if(openssl_init_count == 0 && EVP_get_cipherbyname(CIPHER) != NULL) {
-+ openssl_external_init = 1;
++ p = sqlcipher_malloc(sizeof(sqlcipher_provider));
++ {
++#if defined (SQLCIPHER_CRYPTO_CC)
++ extern int sqlcipher_cc_setup(sqlcipher_provider *p);
++ sqlcipher_cc_setup(p);
++#elif defined (SQLCIPHER_CRYPTO_LIBTOMCRYPT)
++ extern int sqlcipher_ltc_setup(sqlcipher_provider *p);
++ sqlcipher_ltc_setup(p);
++#elif defined (SQLCIPHER_CRYPTO_OPENSSL)
++ extern int sqlcipher_openssl_setup(sqlcipher_provider *p);
++ sqlcipher_openssl_setup(p);
++#else
++#error "NO DEFAULT SQLCIPHER CRYPTO PROVIDER DEFINED"
+ #endif
+- void (*xDel)(void *); /* If not null, call this function to delete Mem.z */
+- char *zMalloc; /* Dynamic buffer allocated by sqlite3_malloc() */
+-};
+ }
-+
-+ if(openssl_external_init == 0) {
-+ if(openssl_init_count == 0) {
-+ OpenSSL_add_all_algorithms();
-+ }
-+ openssl_init_count++;
-+ }
++ sqlcipher_register_provider(p);
+
+-/* 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_RowSet 0x0020 /* Value is a RowSet object */
+-#define MEM_Frame 0x0040 /* Value is a VdbeFrame object */
+-#define MEM_Invalid 0x0080 /* Value is undefined */
+-#define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */
+-#define MEM_TypeMask 0x01ff /* Mask of type bits */
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+}
-+
-+/* deactivate SQLCipher, most imporantly decremeting the activation count and
-+ freeing the EVP structures on the final deactivation to ensure that
-+ OpenSSL memory is cleaned up */
+
+void sqlcipher_deactivate() {
+ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
-+ /* If it is initialized externally, then the init counter should never be greater than zero.
-+ This should prevent SQLCipher from "cleaning up" openssl
-+ when something else in the program might be using it. */
-+ if(openssl_external_init == 0) {
-+ openssl_init_count--;
-+ /* if the counter reaches zero after it's decremented release EVP memory
-+ Note: this code will only be reached if OpensSSL_add_all_algorithms()
-+ is called by SQLCipher internally. */
-+ if(openssl_init_count == 0) {
-+ EVP_cleanup();
-+ }
++ if(default_provider != NULL) {
++ sqlcipher_free(default_provider, sizeof(sqlcipher_provider));
++ default_provider = NULL;
+ }
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+}
-+
+
+-/* 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
+/* 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)
-+*/
+ */
+-#define MEM_Term 0x0200 /* String rep is nul terminated */
+-#define MEM_Dyn 0x0400 /* Need to call sqliteFree() 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_memset(void *v, unsigned char value, int len) {
+ int i = 0;
+ volatile unsigned char *a = v;
-+
+
+-/*
+-** 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 (v == NULL) return v;
-+
+
+-/*
+-** 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_Invalid)==0
+-#endif
+ for(i = 0; i < len; i++) {
+ a[i] = value;
+ }
-+
+
+ return v;
+}
-+
+
+-/* A VdbeFunc is just a FuncDef (defined in sqliteInt.h) that contains
+-** additional information about auxiliary information bound to arguments
+-** of the function. This is used to implement the sqlite3_get_auxdata()
+-** and sqlite3_set_auxdata() APIs. The "auxdata" is some auxiliary data
+-** that can be associated with a constant argument to a function. This
+-** allows functions such as "regexp" to compile their constant regular
+-** expression argument once and reused the compiled code for multiple
+-** invocations.
+-*/
+-struct VdbeFunc {
+- FuncDef *pFunc; /* The definition of the function */
+- int nAux; /* Number of entries allocated for apAux[] */
+- struct AuxData {
+- void *pAux; /* Aux data for the i-th argument */
+- void (*xDelete)(void *); /* Destructor for the aux data */
+- } apAux[1]; /* One slot for each function argument */
+-};
+/* 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;
-+
+
+-/*
+-** The "context" argument for a 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 {
+- FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */
+- VdbeFunc *pVdbeFunc; /* Auxilary data, if created. */
+- Mem s; /* The return value is stored here */
+- Mem *pMem; /* Memory cell used to store aggregate context */
+- CollSeq *pColl; /* Collating sequence */
+- int isError; /* Error code returned by the function. */
+- int skipFlag; /* Skip skip accumulator loading if true */
+-};
+ for(i = 0; i < len; i++) {
+ result |= a[i] ^ value;
+ }
-+
+
+-/*
+-** 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 */
+-};
+ return (result != 0);
+}
-+
+
+-/* 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 */
+/* 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;
-+
+
+-/*
+-** 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 */
+- 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 */
+- int nMem; /* Number of memory locations currently allocated */
+- int nOp; /* Number of instructions in the program */
+- int nOpAlloc; /* Number of slots allocated for aOp[] */
+- int nLabel; /* Number of labels used */
+- int *aLabel; /* Space to hold the labels */
+- u16 nResColumn; /* Number of columns in one row of the result set */
+- 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 */
+- 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 */
+- bft usesStmtJournal:1; /* True if uses a statement journal */
+- bft readOnly:1; /* True for read-only statements */
+- 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) */
+- int aCounter[3]; /* Counters used by sqlite3_stmt_status() */
+-#ifndef SQLITE_OMIT_TRACE
+- i64 startTime; /* Time when query started - used for profiling */
+ for(i = 0; i < len; i++) {
+ result |= a0[i] ^ a1[i];
+ }
@@ -1665,11 +2649,6 @@
+ return (result != 0);
+}
+
-+/* generate a defined number of pseudorandom bytes */
-+int sqlcipher_random (void *buffer, int length) {
-+ return RAND_bytes((unsigned char *)buffer, length);
-+}
-+
+/**
+ * Free and wipe memory. Uses SQLites internal sqlite3_free so that memory
+ * can be countend and memory leak detection works in the test suite.
@@ -1687,8 +2666,17 @@
+ munlock(ptr, sz);
+#elif defined(_WIN32)
+ VirtualUnlock(ptr, sz);
-+#endif
-+#endif
+ #endif
+- i64 nFkConstraint; /* Number of imm. FK constraints this VM */
+- i64 nStmtDefCons; /* Number of def. constraints when stmt started */
+- char *zSql; /* Text of the SQL statement that generated this */
+- void *pFree; /* Free this when deleting the vdbe */
+-#ifdef SQLITE_DEBUG
+- FILE *trace; /* Write an execution trace here, if not NULL */
+ #endif
+-#ifdef SQLITE_ENABLE_TREE_EXPLAIN
+- Explain *pExplain; /* The explainer */
+- char *zExplain; /* Explanation of data structures */
+ }
+ sqlite3_free(ptr);
+ }
@@ -1708,13 +2696,42 @@
+ mlock(ptr, sz);
+#elif defined(_WIN32)
+ VirtualLock(ptr, sz);
-+#endif
+ #endif
+- 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 */
+-};
+ }
+#endif
+ return ptr;
+}
-+
-+
+
+-/*
+-** 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*);
+-#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*, int, Mem*, int);
+-SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
+-SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(VdbeFunc*, int);
+/**
+ * Initialize new cipher_ctx struct. This function will allocate memory
+ * for the cipher context and for the key
@@ -1722,29 +2739,96 @@
+ * returns SQLITE_OK if initialization was successful
+ * returns SQLITE_NOMEM if an error occured allocating memory
+ */
-+int sqlcipher_cipher_ctx_init(cipher_ctx **iCtx) {
++static int sqlcipher_cipher_ctx_init(cipher_ctx **iCtx) {
++ int rc;
+ cipher_ctx *ctx;
+ *iCtx = (cipher_ctx *) sqlcipher_malloc(sizeof(cipher_ctx));
+ ctx = *iCtx;
+ if(ctx == NULL) return SQLITE_NOMEM;
+
-+ ctx->key = (unsigned char *) sqlcipher_malloc(EVP_MAX_KEY_LENGTH);
-+ ctx->hmac_key = (unsigned char *) sqlcipher_malloc(EVP_MAX_KEY_LENGTH);
++ ctx->provider = (sqlcipher_provider *) sqlcipher_malloc(sizeof(sqlcipher_provider));
++ if(ctx->provider == NULL) return SQLITE_NOMEM;
++ memcpy(ctx->provider, default_provider, sizeof(sqlcipher_provider));
++
++ if((rc = ctx->provider->ctx_init(&ctx->provider_ctx)) != SQLITE_OK) return rc;
++ ctx->key = (unsigned char *) sqlcipher_malloc(CIPHER_MAX_KEY_SZ);
++ 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;
-+
+
+-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 sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
+-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 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 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 int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*);
+-SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p);
+-SQLITE_PRIVATE void sqlite3VdbeMemReleaseExternal(Mem *p);
+-#define VdbeMemRelease(X) \
+- if((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame)) \
+- 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 sqlite3VdbeCloseStatement(Vdbe *, int);
+-SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*);
+-SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *);
+-SQLITE_PRIVATE void sqlite3VdbeMemStoreType(Mem *pMem);
+-SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p);
+ /* setup default flags */
+ ctx->flags = default_flags;
-+
+
+-SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *, VdbeCursor *);
+-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 sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int *);
+ return SQLITE_OK;
+}
-+
+
+-#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
+/**
+ * Free and wipe memory associated with a cipher_ctx
+ */
-+void sqlcipher_cipher_ctx_free(cipher_ctx **iCtx) {
++static void sqlcipher_cipher_ctx_free(cipher_ctx **iCtx) {
+ cipher_ctx *ctx = *iCtx;
+ CODEC_TRACE(("cipher_ctx_free: entered iCtx=%p\n", iCtx));
++ ctx->provider->ctx_free(&ctx->provider_ctx);
++ sqlcipher_free(ctx->provider, sizeof(sqlcipher_provider));
+ sqlcipher_free(ctx->key, ctx->key_sz);
+ sqlcipher_free(ctx->hmac_key, ctx->key_sz);
+ sqlcipher_free(ctx->pass, ctx->pass_sz);
@@ -1757,18 +2841,18 @@
+ * returns 0 if all the parameters (except the derived key data) are the same
+ * returns 1 otherwise
+ */
-+int sqlcipher_cipher_ctx_cmp(cipher_ctx *c1, cipher_ctx *c2) {
++static int sqlcipher_cipher_ctx_cmp(cipher_ctx *c1, cipher_ctx *c2) {
+ CODEC_TRACE(("sqlcipher_cipher_ctx_cmp: entered c1=%p c2=%p\n", c1, c2));
+
+ if(
-+ c1->evp_cipher == c2->evp_cipher
-+ && c1->iv_sz == c2->iv_sz
++ c1->iv_sz == c2->iv_sz
+ && c1->kdf_iter == c2->kdf_iter
+ && c1->fast_kdf_iter == c2->fast_kdf_iter
+ && c1->key_sz == c2->key_sz
+ && c1->pass_sz == c2->pass_sz
+ && c1->flags == c2->flags
+ && c1->hmac_sz == c2->hmac_sz
++ && c1->provider->ctx_cmp(c1->provider_ctx, c2->provider_ctx)
+ && (
+ c1->pass == c2->pass
+ || !sqlcipher_memcmp((const unsigned char*)c1->pass,
@@ -1778,7 +2862,10 @@
+ ) return 0;
+ return 1;
+}
-+
+
+-#ifdef SQLITE_DEBUG
+-SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe*,Mem*);
+-#endif
+/**
+ * Copy one cipher_ctx to another. For instance, assuming that read_ctx is a
+ * fully initialized context, you could copy it to write_ctx and all yet data
@@ -1787,28 +2874,65 @@
+ * returns SQLITE_OK if initialization was successful
+ * returns SQLITE_NOMEM if an error occured allocating memory
+ */
-+int sqlcipher_cipher_ctx_copy(cipher_ctx *target, cipher_ctx *source) {
++static int sqlcipher_cipher_ctx_copy(cipher_ctx *target, cipher_ctx *source) {
+ void *key = target->key;
+ void *hmac_key = target->hmac_key;
++ void *provider = target->provider;
++ void *provider_ctx = target->provider_ctx;
+
+ CODEC_TRACE(("sqlcipher_cipher_ctx_copy: entered target=%p, source=%p\n", target, source));
+ sqlcipher_free(target->pass, target->pass_sz);
+ memcpy(target, source, sizeof(cipher_ctx));
+
+ target->key = key; //restore pointer to previously allocated key data
-+ memcpy(target->key, source->key, EVP_MAX_KEY_LENGTH);
-+
++ memcpy(target->key, source->key, CIPHER_MAX_KEY_SZ);
+
+-#ifndef SQLITE_OMIT_FOREIGN_KEY
+-SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *, int);
+-#else
+-# define sqlite3VdbeCheckFk(p,i) 0
+-#endif
+ target->hmac_key = hmac_key; //restore pointer to previously allocated hmac key data
-+ memcpy(target->hmac_key, source->hmac_key, EVP_MAX_KEY_LENGTH);
-+
++ memcpy(target->hmac_key, source->hmac_key, CIPHER_MAX_KEY_SZ);
+
+-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);
++ target->provider = provider; // restore pointer to previouly allocated provider;
++ memcpy(target->provider, source->provider, sizeof(sqlcipher_provider));
+
+-#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
++ target->provider_ctx = provider_ctx; // restore pointer to previouly allocated provider context;
++ target->provider->ctx_copy(target->provider_ctx, source->provider_ctx);
+
+-#endif /* !defined(_VDBEINT_H_) */
+ target->pass = sqlcipher_malloc(source->pass_sz);
+ if(target->pass == NULL) return SQLITE_NOMEM;
+ memcpy(target->pass, source->pass, source->pass_sz);
-+
+
+-/************** End of vdbeInt.h *********************************************/
+-/************** Continuing where we left off in status.c *********************/
+ return SQLITE_OK;
+}
-+
-+
+
+-/*
+-** Variables in which to record status information.
+-*/
+-typedef struct sqlite3StatType sqlite3StatType;
+-static SQLITE_WSD struct sqlite3StatType {
+- int nowValue[10]; /* Current value */
+- int mxValue[10]; /* Maximum value */
+-} sqlite3Stat = { {0,}, {0,} };
+
+/**
+ * Set the raw password / key data for a cipher context
+ *
@@ -1816,7 +2940,7 @@
+ * returns SQLITE_NOMEM if an error occured allocating memory
+ * returns SQLITE_ERROR if the key couldn't be set because the pass was null or size was zero
+ */
-+int sqlcipher_cipher_ctx_set_pass(cipher_ctx *ctx, const void *zKey, int nKey) {
++static int sqlcipher_cipher_ctx_set_pass(cipher_ctx *ctx, const void *zKey, int nKey) {
+ sqlcipher_free(ctx->pass, ctx->pass_sz);
+ ctx->pass_sz = nKey;
+ if(zKey && nKey) {
@@ -1831,10 +2955,30 @@
+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;
-+
+
+-/* 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
+ if((rc = sqlcipher_cipher_ctx_set_pass(c_ctx, zKey, nKey)) != SQLITE_OK) return rc;
+ c_ctx->derive_key = 1;
-+
+
+-/*
+-** Return the current value of a status parameter.
+-*/
+-SQLITE_PRIVATE int sqlite3StatusValue(int op){
+- wsdStatInit;
+- assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
+- return wsdStat.nowValue[op];
+ if(for_ctx == 2)
+ if((rc = sqlcipher_cipher_ctx_copy( for_ctx ? ctx->read_ctx : ctx->write_ctx, c_ctx)) != SQLITE_OK)
+ return rc;
@@ -1846,11 +2990,12 @@
+ cipher_ctx *c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
+ int rc;
+
-+ c_ctx->evp_cipher = (EVP_CIPHER *) EVP_get_cipherbyname(cipher_name);
-+ c_ctx->key_sz = EVP_CIPHER_key_length(c_ctx->evp_cipher);
-+ c_ctx->iv_sz = EVP_CIPHER_iv_length(c_ctx->evp_cipher);
-+ c_ctx->block_sz = EVP_CIPHER_block_size(c_ctx->evp_cipher);
-+ c_ctx->hmac_sz = EVP_MD_size(EVP_sha1());
++ c_ctx->provider->set_cipher(c_ctx->provider_ctx, cipher_name);
++
++ c_ctx->key_sz = c_ctx->provider->get_key_sz(c_ctx->provider_ctx);
++ c_ctx->iv_sz = c_ctx->provider->get_iv_sz(c_ctx->provider_ctx);
++ c_ctx->block_sz = c_ctx->provider->get_block_sz(c_ctx->provider_ctx);
++ c_ctx->hmac_sz = c_ctx->provider->get_hmac_sz(c_ctx->provider_ctx);
+ c_ctx->derive_key = 1;
+
+ if(for_ctx == 2)
@@ -1858,14 +3003,34 @@
+ return rc;
+
+ return SQLITE_OK;
-+}
-+
+ }
+
+-/*
+-** Add N to the value of a status record. It is assumed that the
+-** caller holds appropriate locks.
+-*/
+-SQLITE_PRIVATE void sqlite3StatusAdd(int op, int N){
+- wsdStatInit;
+- assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
+- wsdStat.nowValue[op] += N;
+- if( wsdStat.nowValue[op]>wsdStat.mxValue[op] ){
+- wsdStat.mxValue[op] = wsdStat.nowValue[op];
+- }
+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;
-+ EVP_CIPHER *evp_cipher = c_ctx->evp_cipher;
-+ return EVP_CIPHER_name(evp_cipher);
-+}
-+
++ return c_ctx->provider->get_cipher(c_ctx->provider_ctx);
+ }
+
+-/*
+-** Set the value of a status to X.
+-*/
+-SQLITE_PRIVATE void sqlite3StatusSet(int op, int X){
+- wsdStatInit;
+- assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
+- wsdStat.nowValue[op] = X;
+- if( wsdStat.nowValue[op]>wsdStat.mxValue[op] ){
+- wsdStat.mxValue[op] = wsdStat.nowValue[op];
+- }
+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;
@@ -1878,8 +3043,25 @@
+ return rc;
+
+ return SQLITE_OK;
-+}
-+
+ }
+
+-/*
+-** 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){
+- wsdStatInit;
+- if( op<0 || op>=ArraySize(wsdStat.nowValue) ){
+- return SQLITE_MISUSE_BKPT;
+- }
+- *pCurrent = wsdStat.nowValue[op];
+- *pHighwater = wsdStat.mxValue[op];
+- if( resetFlag ){
+- wsdStat.mxValue[op] = wsdStat.nowValue[op];
+- }
+int sqlcipher_codec_ctx_get_kdf_iter(codec_ctx *ctx, int for_ctx) {
+ cipher_ctx *c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
+ return c_ctx->kdf_iter;
@@ -1896,46 +3078,157 @@
+ 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;
+ }
+
+-/*
+-** Query status information for a single database connection
+-*/
+-SQLITE_API int 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 */
+- 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;
+- }
+int sqlcipher_codec_ctx_get_fast_kdf_iter(codec_ctx *ctx, int for_ctx) {
+ cipher_ctx *c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
+ return c_ctx->fast_kdf_iter;
+}
-+
+
+- 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;
+- }
+/* set the global default flag for HMAC */
+void sqlcipher_set_default_use_hmac(int use) {
+ if(use) default_flags |= CIPHER_FLAG_HMAC;
+ else default_flags &= ~CIPHER_FLAG_HMAC;
+}
-+
+
+- /*
+- ** 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;
+- }
+int sqlcipher_get_default_use_hmac() {
+ return (default_flags & CIPHER_FLAG_HMAC) != 0;
+}
-+
+
+- /*
+- ** *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 */
+void sqlcipher_set_hmac_salt_mask(unsigned char mask) {
+ hmac_salt_mask = 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;
+unsigned char sqlcipher_get_hmac_salt_mask() {
+ return hmac_salt_mask;
+}
-+
+
+- 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);
+/* set the codec flag for whether this individual database should be using hmac */
+int sqlcipher_codec_ctx_set_use_hmac(codec_ctx *ctx, int use) {
-+ int reserve = EVP_MAX_IV_LENGTH; /* base reserve size will be IV only */
-+
++ int reserve = CIPHER_MAX_IV_SZ; /* base reserve size will be IV only */
+
+- 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);
+ if(use) reserve += ctx->read_ctx->hmac_sz; /* if reserve will include hmac, update that size */
-+
+
+- *pHighwater = 0;
+- *pCurrent = nByte;
+- break;
+- }
+ /* calculate the amount of reserve needed in even increments of the cipher block size */
-+
+
+- /*
+- ** *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 */
+ reserve = ((reserve % ctx->read_ctx->block_sz) == 0) ? reserve :
+ ((reserve / ctx->read_ctx->block_sz) + 1) * ctx->read_ctx->block_sz;
-+
+
+- db->pnBytesFreed = &nByte;
+- for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){
+- sqlite3VdbeClearObject(db, pVdbe);
+- sqlite3DbFree(db, pVdbe);
+- }
+- db->pnBytesFreed = 0;
+ CODEC_TRACE(("sqlcipher_codec_ctx_set_use_hmac: use=%d block_sz=%d md_size=%d reserve=%d\n",
+ use, ctx->read_ctx->block_sz, ctx->read_ctx->hmac_sz, reserve));
-+
+
+- *pHighwater = 0;
+- *pCurrent = nByte;
+
+ if(use) {
+ sqlcipher_codec_ctx_set_flag(ctx, CIPHER_FLAG_HMAC);
@@ -1944,55 +3237,234 @@
+ }
+
+ ctx->write_ctx->reserve_sz = ctx->read_ctx->reserve_sz = reserve;
-+
+
+- break;
+- }
+ return SQLITE_OK;
+}
-+
+
+- /*
+- ** 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 );
+int sqlcipher_codec_ctx_get_use_hmac(codec_ctx *ctx, int for_ctx) {
+ cipher_ctx * c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
+ return (c_ctx->flags & CIPHER_FLAG_HMAC) != 0;
+}
-+
+
+- 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;
+- *pCurrent = nRet;
+- break;
+- }
+int sqlcipher_codec_ctx_set_flag(codec_ctx *ctx, unsigned int flag) {
+ ctx->write_ctx->flags |= flag;
+ ctx->read_ctx->flags |= flag;
+ return SQLITE_OK;
+}
-+
+
+- default: {
+- rc = SQLITE_ERROR;
+- }
+- }
+- sqlite3_mutex_leave(db->mutex);
+- return rc;
+int sqlcipher_codec_ctx_unset_flag(codec_ctx *ctx, unsigned int flag) {
+ ctx->write_ctx->flags &= ~flag;
+ ctx->read_ctx->flags &= ~flag;
+ return SQLITE_OK;
-+}
-+
+ }
+
+-/************** 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 implemention 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>
+int sqlcipher_codec_ctx_get_flag(codec_ctx *ctx, unsigned int flag, int for_ctx) {
+ cipher_ctx * c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
+ return (c_ctx->flags & flag) != 0;
+}
-+
+
+-#ifndef SQLITE_OMIT_DATETIME_FUNCS
+void sqlcipher_codec_ctx_set_error(codec_ctx *ctx, int error) {
+ CODEC_TRACE(("sqlcipher_codec_ctx_set_error: ctx=%p, error=%d\n", ctx, error));
+ sqlite3pager_sqlite3PagerSetError(ctx->pBt->pBt->pPager, error);
+ ctx->pBt->pBt->db->errCode = error;
+}
-+
+
+int sqlcipher_codec_ctx_get_reservesize(codec_ctx *ctx) {
+ return ctx->read_ctx->reserve_sz;
+}
-+
+
+-/*
+-** 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 */
+-};
+void* sqlcipher_codec_ctx_get_data(codec_ctx *ctx) {
+ return ctx->buffer;
+}
-+
+
+void* sqlcipher_codec_ctx_get_kdf_salt(codec_ctx *ctx) {
+ return ctx->kdf_salt;
+}
-+
+
+-/*
+-** 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;
+void sqlcipher_codec_get_pass(codec_ctx *ctx, void **zKey, int *nKey) {
+ *zKey = ctx->read_ctx->pass;
+ *nKey = ctx->read_ctx->pass_sz;
-+}
-+
+ }
+
+-/*
+-** 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;
+int sqlcipher_codec_ctx_set_pagesize(codec_ctx *ctx, int size) {
+ /* attempt to free the existing page buffer */
+ sqlcipher_free(ctx->buffer,ctx->page_sz);
@@ -2048,8 +3520,13 @@
+
+ if(fd == NULL || sqlite3OsRead(fd, ctx->kdf_salt, FILE_HEADER_SZ, 0) != SQLITE_OK) {
+ /* if unable to read the bytes, generate random salt */
-+ if(sqlcipher_random(ctx->kdf_salt, FILE_HEADER_SZ) != 1) return SQLITE_ERROR;
-+ }
++ if(ctx->read_ctx->provider->random(ctx->read_ctx->provider_ctx, ctx->kdf_salt, FILE_HEADER_SZ) !=
SQLITE_OK) return SQLITE_ERROR;
+ }
+- zDate += 5;
+- p->tz = sgn*(nMn + nHr*60);
+-zulu_time:
+- while( sqlite3Isspace(*zDate) ){ zDate++; }
+- return *zDate!=0;
+
+ if((rc = sqlcipher_codec_ctx_set_cipher(ctx, CIPHER, 0)) != SQLITE_OK) return rc;
+ if((rc = sqlcipher_codec_ctx_set_kdf_iter(ctx, PBKDF2_ITER, 0)) != SQLITE_OK) return rc;
@@ -2088,7 +3565,7 @@
+ p[3] = (u8)(v>>24);
+}
+
-+int sqlcipher_page_hmac(cipher_ctx *ctx, Pgno pgno, unsigned char *in, int in_sz, unsigned char *out) {
++static int sqlcipher_page_hmac(cipher_ctx *ctx, Pgno pgno, unsigned char *in, int in_sz, unsigned char
*out) {
+ unsigned char pgno_raw[sizeof(pgno)];
+ /* we may convert page number to consistent representation before calculating MAC for
+ compatibility across big-endian and little-endian platforms.
@@ -2106,20 +3583,35 @@
+ memcpy(pgno_raw, &pgno, sizeof(pgno));
+ }
+
-+ HMAC_CTX_init(&ctx->hctx);
-+ HMAC_Init_ex(&ctx->hctx, ctx->hmac_key, ctx->key_sz, EVP_sha1(), NULL);
-+
+ /* include the encrypted page data, initialization vector, and page number in HMAC. This will
+ prevent both tampering with the ciphertext, manipulation of the IV, or resequencing otherwise
+ valid pages out of order in a database */
-+ HMAC_Update(&ctx->hctx, in, in_sz);
-+ HMAC_Update(&ctx->hctx, (const unsigned char*) pgno_raw, sizeof(pgno));
-+ HMAC_Final(&ctx->hctx, out, NULL);
-+ HMAC_CTX_cleanup(&ctx->hctx);
++ ctx->provider->hmac(
++ ctx->provider_ctx, ctx->hmac_key,
++ ctx->key_sz, in,
++ in_sz, (unsigned char*) &pgno_raw,
++ sizeof(pgno), out);
+ 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;
+- }
+- zDate += 5;
+- if( *zDate==':' ){
+- zDate++;
+- if( getDigits(zDate, 2, 0, 59, 0, &s)!=1 ){
+- return 1;
+ * ctx - codec context
+ * pgno - page number in database
+ * size - size in bytes of input and output buffers
@@ -2130,7 +3622,7 @@
+int sqlcipher_page_cipher(codec_ctx *ctx, int for_ctx, Pgno pgno, int mode, int page_sz, unsigned char *in,
unsigned char *out) {
+ cipher_ctx *c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
+ unsigned char *iv_in, *iv_out, *hmac_in, *hmac_out, *out_start;
-+ int tmp_csz, csz, size;
++ int size;
+
+ /* calculate some required positions into various buffers */
+ size = page_sz - c_ctx->reserve_sz; /* adjust size to useable size and memset reserve at end of page */
@@ -2155,7 +3647,7 @@
+
+ if(mode == CIPHER_ENCRYPT) {
+ /* start at front of the reserve block, write random data to the end */
-+ if(sqlcipher_random(iv_out, c_ctx->reserve_sz) != 1) return SQLITE_ERROR;
++ if(c_ctx->provider->random(c_ctx->provider_ctx, iv_out, c_ctx->reserve_sz) != SQLITE_OK) return
SQLITE_ERROR;
+ } else { /* CIPHER_DECRYPT */
+ memcpy(iv_out, iv_in, c_ctx->iv_sz); /* copy the iv from the input to output buffer */
+ }
@@ -2165,7 +3657,15 @@
+ sqlcipher_memset(out, 0, page_sz);
+ CODEC_TRACE(("codec_cipher: hmac operations failed for pgno=%d\n", pgno));
+ return SQLITE_ERROR;
-+ }
+ }
+- 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++;
+
+ 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 */
@@ -2184,30 +3684,40 @@
+ CODEC_TRACE(("codec_cipher: hmac check failed for pgno=%d returning SQLITE_ERROR\n", pgno));
+ sqlcipher_memset(out, 0, page_sz);
+ return SQLITE_ERROR;
-+ }
-+ }
+ }
+- ms /= rScale;
+ }
+- }else{
+- s = 0;
+ }
-+
-+ EVP_CipherInit(&c_ctx->ectx, c_ctx->evp_cipher, NULL, NULL, mode);
-+ EVP_CIPHER_CTX_set_padding(&c_ctx->ectx, 0);
-+ EVP_CipherInit(&c_ctx->ectx, NULL, c_ctx->key, iv_out, mode);
-+ EVP_CipherUpdate(&c_ctx->ectx, out, &tmp_csz, in, size);
-+ csz = tmp_csz;
-+ out += tmp_csz;
-+ EVP_CipherFinal(&c_ctx->ectx, out, &tmp_csz);
-+ csz += tmp_csz;
-+ EVP_CIPHER_CTX_cleanup(&c_ctx->ectx);
-+ assert(size == csz);
++
++ c_ctx->provider->cipher(c_ctx->provider_ctx, mode, c_ctx->key, c_ctx->key_sz, iv_out, in, size, out);
+
+ 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);
-+ }
+ }
+- 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;
+
+ CODEC_HEXDUMP("codec_cipher: output page data", out_start, page_sz);
+
+ return SQLITE_OK;
-+}
-+
+ }
+
+-/*
+-** 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;
+/**
+ * Derive an encryption key for a cipher contex key based on the raw password.
+ *
@@ -2219,7 +3729,7 @@
+ * returns SQLITE_OK if initialization was successful
+ * returns SQLITE_ERROR if the key could't be derived (for instance if pass is NULL or pass_sz is 0)
+ */
-+int sqlcipher_cipher_ctx_key_derive(codec_ctx *ctx, cipher_ctx *c_ctx) {
++static int sqlcipher_cipher_ctx_key_derive(codec_ctx *ctx, cipher_ctx *c_ctx) {
+ CODEC_TRACE(("codec_key_derive: entered c_ctx->pass=%s, c_ctx->pass_sz=%d \
+ ctx->kdf_salt=%p ctx->kdf_salt_sz=%d c_ctx->kdf_iter=%d \
+ ctx->hmac_kdf_salt=%p, c_ctx->fast_kdf_iter=%d c_ctx->key_sz=%d\n",
@@ -2235,9 +3745,9 @@
+ cipher_hex2bin(z, n, c_ctx->key);
+ } else {
+ CODEC_TRACE(("codec_key_derive: deriving key using full PBKDF2 with %d iterations\n",
c_ctx->kdf_iter));
-+ PKCS5_PBKDF2_HMAC_SHA1( c_ctx->pass, c_ctx->pass_sz,
-+ ctx->kdf_salt, ctx->kdf_salt_sz,
-+ c_ctx->kdf_iter, c_ctx->key_sz, c_ctx->key);
++ c_ctx->provider->kdf(c_ctx->provider_ctx, (const char*) c_ctx->pass, c_ctx->pass_sz,
++ ctx->kdf_salt, ctx->kdf_salt_sz, c_ctx->kdf_iter,
++ c_ctx->key_sz, c_ctx->key);
+
+ }
+
@@ -2246,7 +3756,20 @@
+ this KDF run. This ensures a distinct but predictable HMAC key. */
+ if(c_ctx->flags & CIPHER_FLAG_HMAC) {
+ int i;
-+
+
+- 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;
+ /* 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
@@ -2259,9 +3782,11 @@
+
+ CODEC_TRACE(("codec_key_derive: deriving hmac key from encryption key using PBKDF2 with %d
iterations\n",
+ c_ctx->fast_kdf_iter));
-+ PKCS5_PBKDF2_HMAC_SHA1( (const char*)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);
++
++
++ c_ctx->provider->kdf(c_ctx->provider_ctx, (const char*)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);
+ }
+
+ c_ctx->derive_key = 0;
@@ -2274,7 +3799,20 @@
+ /* derive key on first use if necessary */
+ if(ctx->read_ctx->derive_key) {
+ if(sqlcipher_cipher_ctx_key_derive(ctx, ctx->read_ctx) != SQLITE_OK) return SQLITE_ERROR;
-+ }
+ }
+- 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;
+
+ if(ctx->write_ctx->derive_key) {
+ if(sqlcipher_cipher_ctx_cmp(ctx->write_ctx, ctx->read_ctx) == 0) {
@@ -2282,8 +3820,8 @@
+ 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;
-+ }
-+ }
+ }
+ }
+ return SQLITE_OK;
+}
+
@@ -2295,209 +3833,1540 @@
+ }
+}
+
++const char* sqlcipher_codec_get_cipher_provider(codec_ctx *ctx) {
++ return ctx->read_ctx->provider->get_provider_name(ctx->read_ctx);
+ }
+
++#endif
++/* END SQLCIPHER */
+
-+#ifndef OMIT_EXPORT
++/************** End of crypto_impl.c *****************************************/
++/************** Begin file crypto_libtomcrypt.c ******************************/
+ /*
+-** Parse dates of the form
++** SQLCipher
++** http://sqlcipher.net
+ **
+-** YYYY-MM-DD HH:MM:SS.FFF
+-** YYYY-MM-DD HH:MM:SS
+-** YYYY-MM-DD HH:MM
+-** YYYY-MM-DD
++** Copyright (c) 2008 - 2013, ZETETIC LLC
++** All rights reserved.
++**
++** 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
++** notice, this list of conditions and the following disclaimer.
++** * Redistributions in binary form must reproduce the above copyright
++** notice, this list of conditions and the following disclaimer in the
++** documentation and/or other materials provided with the distribution.
++** * 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.
++**
++** 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
++** DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY
++** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++** 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.
+ **
+-** 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;
++/* BEGIN SQLCIPHER */
++#ifdef SQLITE_HAS_CODEC
++#ifdef SQLCIPHER_CRYPTO_LIBTOMCRYPT
++#include <tomcrypt.h>
+
+- if( zDate[0]=='-' ){
+- zDate++;
+- neg = 1;
+- }else{
+- neg = 0;
++typedef struct {
++ prng_state prng;
++} ltc_ctx;
+
-+/*
-+ * 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:
-+ *
-+ * 1. migrate from an non-encrypted database to an encrypted database
-+ * 2. move from an encrypted database to a non-encrypted database
-+ * 3. convert beween the various flavors of encrypted databases.
-+ *
-+ * This implementation is based heavily on the procedure and code used
-+ * in vacuum.c, but is exposed as a function that allows export to any
-+ * named attached database.
-+ */
++static unsigned int ltc_init = 0;
+
-+/*
-+** 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
-+*/
-+static int sqlcipher_finalize(sqlite3 *db, sqlite3_stmt *pStmt, char **pzErrMsg){
-+ int rc;
-+ rc = sqlite3VdbeFinalize((Vdbe*)pStmt);
-+ if( rc ){
-+ sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db));
-+ }
-+ return rc;
++static int sqlcipher_ltc_add_random(void *ctx, void *buffer, int length) {
++ ltc_ctx *ltc = (ltc_ctx*)ctx;
++ int rc = fortuna_add_entropy(buffer, length, &(ltc->prng));
++ return rc != CRYPT_OK ? SQLITE_ERROR : SQLITE_OK;
+}
+
-+/*
-+** Execute zSql on database db. Return an error code.
-+**
-+** Based on execSql from vacuum.c
-+*/
-+static int sqlcipher_execSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
-+ sqlite3_stmt *pStmt;
-+ VVA_ONLY( int rc; )
-+ if( !zSql ){
-+ return SQLITE_NOMEM;
-+ }
-+ if( SQLITE_OK!=sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){
-+ sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db));
-+ return sqlite3_errcode(db);
++static int sqlcipher_ltc_activate(void *ctx) {
++ ltc_ctx *ltc = (ltc_ctx*)ctx;
++ int random_buffer_sz = 32;
++ unsigned char random_buffer[random_buffer_sz];
++
++ if(ltc_init == 0) {
++ if(register_prng(&fortuna_desc) != CRYPT_OK) return SQLITE_ERROR;
++ if(register_cipher(&rijndael_desc) != CRYPT_OK) return SQLITE_ERROR;
++ if(register_hash(&sha1_desc) != CRYPT_OK) return SQLITE_ERROR;
++ ltc_init = 1;
+ }
+- if( getDigits(zDate,4,0,9999,'-',&Y,2,1,12,'-',&M,2,1,31,0,&D)!=3 ){
+- return 1;
++ if(fortuna_start(&(ltc->prng)) != CRYPT_OK) {
++ return SQLITE_ERROR;
+ }
+- 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;
++ sqlite3_randomness(random_buffer_sz, &random_buffer);
++ if(sqlcipher_ltc_add_random(ctx, random_buffer, random_buffer_sz) != SQLITE_OK) {
++ return SQLITE_ERROR;
+ }
+- p->validJD = 0;
+- p->validYMD = 1;
+- p->Y = neg ? -Y : Y;
+- p->M = M;
+- p->D = D;
+- if( p->validTZ ){
+- computeJD(p);
++ if(sqlcipher_ltc_add_random(ctx, <c, sizeof(ltc_ctx*)) != SQLITE_OK) {
++ return SQLITE_ERROR;
+ }
+- return 0;
++ if(fortuna_ready(&(ltc->prng)) != CRYPT_OK) {
++ return SQLITE_ERROR;
+ }
-+ VVA_ONLY( rc = ) sqlite3_step(pStmt);
-+ assert( rc!=SQLITE_ROW );
-+ return sqlcipher_finalize(db, pStmt, pzErrMsg);
++ return SQLITE_OK;
+ }
+
+-/*
+-** Set the time to the current time reported by the VFS.
+-**
+-** Return the number of errors.
+-*/
+-static int setDateTimeToCurrent(sqlite3_context *context, DateTime *p){
+- sqlite3 *db = sqlite3_context_db_handle(context);
+- if( sqlite3OsCurrentTimeInt64(db->pVfs, &p->iJD)==SQLITE_OK ){
+- p->validJD = 1;
+- return 0;
+- }else{
+- return 1;
++static int sqlcipher_ltc_deactivate(void *ctx) {
++ ltc_ctx *ltc = (ltc_ctx*)ctx;
++ fortuna_done(&(ltc->prng));
+}
+
-+/*
-+** 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
-+*/
-+static int sqlcipher_execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
-+ sqlite3_stmt *pStmt;
++static const char* sqlcipher_ltc_get_provider_name(void *ctx) {
++ return "libtomcrypt";
++}
++
++static int sqlcipher_ltc_random(void *ctx, void *buffer, int length) {
++ ltc_ctx *ltc = (ltc_ctx*)ctx;
+ int rc;
++
++ if((rc = fortuna_ready(&(ltc->prng))) != CRYPT_OK) {
++ return SQLITE_ERROR;
+ }
++ fortuna_read(buffer, length, &(ltc->prng));
++ return SQLITE_OK;
+ }
+
+-/*
+-** 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;
++static int sqlcipher_ltc_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) {
++ int rc, hash_idx;
++ hmac_state hmac;
++ unsigned long outlen = key_sz;
+
-+ rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
-+ if( rc!=SQLITE_OK ) return rc;
++ hash_idx = find_hash("sha1");
++ if((rc = hmac_init(&hmac, hash_idx, hmac_key, key_sz)) != CRYPT_OK) return SQLITE_ERROR;
++ if((rc = hmac_process(&hmac, in, in_sz)) != CRYPT_OK) return SQLITE_ERROR;
++ if((rc = hmac_process(&hmac, in2, in2_sz)) != CRYPT_OK) return SQLITE_ERROR;
++ if((rc = hmac_done(&hmac, out, &outlen)) != CRYPT_OK) return SQLITE_ERROR;
++ return SQLITE_OK;
++}
+
-+ while( SQLITE_ROW==sqlite3_step(pStmt) ){
-+ rc = sqlcipher_execSql(db, pzErrMsg, (char*)sqlite3_column_text(pStmt, 0));
-+ if( rc!=SQLITE_OK ){
-+ sqlcipher_finalize(db, pStmt, pzErrMsg);
-+ return rc;
-+ }
++static int sqlcipher_ltc_kdf(void *ctx, const char *pass, int pass_sz, unsigned char* salt, int salt_sz,
int workfactor, int key_sz, unsigned char *key) {
++ int rc, hash_idx;
++ unsigned long outlen = key_sz;
++ unsigned long random_buffer_sz = 256;
++ char random_buffer[random_buffer_sz];
++ ltc_ctx *ltc = (ltc_ctx*)ctx;
++
++ hash_idx = find_hash("sha1");
++ if((rc = pkcs_5_alg2(pass, pass_sz, salt, salt_sz,
++ workfactor, hash_idx, key, &outlen)) != CRYPT_OK) {
++ return SQLITE_ERROR;
+ }
+- return 1;
++ if((rc = pkcs_5_alg2(key, key_sz, salt, salt_sz,
++ 1, hash_idx, random_buffer, &random_buffer_sz)) != CRYPT_OK) {
++ return SQLITE_ERROR;
+ }
++ sqlcipher_ltc_add_random(ctx, random_buffer, random_buffer_sz);
++ 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;
++static const char* sqlcipher_ltc_get_cipher(void *ctx) {
++ return "rijndael";
+ }
+
+-/*
+-** 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 int sqlcipher_ltc_cipher(void *ctx, int mode, unsigned char *key, int key_sz, unsigned char *iv,
unsigned char *in, int in_sz, unsigned char *out) {
++ int rc, cipher_idx, hash_idx;
++ symmetric_CBC cbc;
+
-+ return sqlcipher_finalize(db, pStmt, pzErrMsg);
++ if((cipher_idx = find_cipher(sqlcipher_ltc_get_cipher(ctx))) == -1) return SQLITE_ERROR;
++ if((rc = cbc_start(cipher_idx, iv, key, key_sz, 0, &cbc)) != CRYPT_OK) return SQLITE_ERROR;
++ rc = mode == 1 ? cbc_encrypt(in, out, in_sz, &cbc) : cbc_decrypt(in, out, in_sz, &cbc);
++ if(rc != CRYPT_OK) return SQLITE_ERROR;
++ cbc_done(&cbc);
++ return SQLITE_OK;
+ }
+
+-/*
+-** Compute both YMD and HMS
+-*/
+-static void computeYMD_HMS(DateTime *p){
+- computeYMD(p);
+- computeHMS(p);
++static int sqlcipher_ltc_set_cipher(void *ctx, const char *cipher_name) {
++ 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_ltc_get_key_sz(void *ctx) {
++ int cipher_idx = find_cipher(sqlcipher_ltc_get_cipher(ctx));
++ return cipher_descriptor[cipher_idx].max_key_length;
+ }
+
+-/*
+-** 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 !defined(HAVE_LOCALTIME_R) && !defined(HAVE_LOCALTIME_S) && \
+- defined(_MSC_VER) && defined(_CRT_INSECURE_DEPRECATE)
+-#define HAVE_LOCALTIME_S 1
+-#endif
++static int sqlcipher_ltc_get_iv_sz(void *ctx) {
++ int cipher_idx = find_cipher(sqlcipher_ltc_get_cipher(ctx));
++ return cipher_descriptor[cipher_idx].block_length;
++}
+
+-#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.
+-*/
+-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)
+- 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 defined(HAVE_LOCALTIME_R) && 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;
++static int sqlcipher_ltc_get_block_sz(void *ctx) {
++ int cipher_idx = find_cipher(sqlcipher_ltc_get_cipher(ctx));
++ return cipher_descriptor[cipher_idx].block_length;
+ }
+-#endif /* SQLITE_OMIT_LOCALTIME */
+
++static int sqlcipher_ltc_get_hmac_sz(void *ctx) {
++ int hash_idx = find_hash("sha1");
++ return hash_descriptor[hash_idx].hashsize;
++}
+
+-#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;
++static int sqlcipher_ltc_ctx_copy(void *target_ctx, void *source_ctx) {
++ memcpy(target_ctx, source_ctx, sizeof(ltc_ctx));
++ return SQLITE_OK;
++}
+
+- /* Initialize the contents of sLocal to avoid a compiler warning. */
+- memset(&sLocal, 0, sizeof(sLocal));
++static int sqlcipher_ltc_ctx_cmp(void *c1, void *c2) {
++ return 1;
++}
+
+- x = *p;
+- computeYMD_HMS(&x);
+- if( x.Y<1971 || x.Y>=2038 ){
+- 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;
++static int sqlcipher_ltc_ctx_init(void **ctx) {
++ *ctx = sqlcipher_malloc(sizeof(ltc_ctx));
++ if(*ctx == NULL) return SQLITE_NOMEM;
++ sqlcipher_ltc_activate(*ctx);
++ return SQLITE_OK;
+}
+
-+/*
-+ * copy database and schema from the main database to an attached database
-+ *
-+ * Based on sqlite3RunVacuum from vacuum.c
-+*/
-+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]);
-+ int saved_flags; /* Saved value of the db->flags */
-+ int saved_nChange; /* Saved value of db->nChange */
-+ int saved_nTotalChange; /* Saved value of db->nTotalChange */
-+ void (*saved_xTrace)(void*,const char*); /* Saved db->xTrace */
-+ int rc = SQLITE_OK; /* Return code from service routines */
-+ char *zSql = NULL; /* SQL statements */
-+ char *pzErrMsg = NULL;
-+
-+ saved_flags = db->flags;
-+ saved_nChange = db->nChange;
-+ saved_nTotalChange = db->nTotalChange;
-+ saved_xTrace = db->xTrace;
-+ db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks | SQLITE_PreferBuiltin;
-+ db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder);
-+ db->xTrace = 0;
-+
-+ /* Query the schema of the main database. Create a mirror schema
-+ ** in the temporary database.
-+ */
-+ zSql = sqlite3_mprintf(
-+ "SELECT 'CREATE TABLE %s.' || substr(sql,14) "
-+ " FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'"
-+ " AND rootpage>0"
-+ , attachedDb);
-+ rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
-+ if( rc!=SQLITE_OK ) goto end_of_export;
-+ sqlite3_free(zSql);
-+
-+ zSql = sqlite3_mprintf(
-+ "SELECT 'CREATE INDEX %s.' || substr(sql,14)"
-+ " FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %%' "
-+ , attachedDb);
-+ rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
-+ if( rc!=SQLITE_OK ) goto end_of_export;
-+ sqlite3_free(zSql);
++static int sqlcipher_ltc_ctx_free(void **ctx) {
++ sqlcipher_ltc_deactivate(&ctx);
++ sqlcipher_free(*ctx, sizeof(ltc_ctx));
++ return SQLITE_OK;
++}
+
-+ zSql = sqlite3_mprintf(
-+ "SELECT 'CREATE UNIQUE INDEX %s.' || substr(sql,21) "
-+ " FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %%'"
-+ , attachedDb);
-+ rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
-+ if( rc!=SQLITE_OK ) goto end_of_export;
-+ sqlite3_free(zSql);
++int sqlcipher_ltc_setup(sqlcipher_provider *p) {
++ p->activate = sqlcipher_ltc_activate;
++ p->deactivate = sqlcipher_ltc_deactivate;
++ p->get_provider_name = sqlcipher_ltc_get_provider_name;
++ p->random = sqlcipher_ltc_random;
++ p->hmac = sqlcipher_ltc_hmac;
++ p->kdf = sqlcipher_ltc_kdf;
++ p->cipher = sqlcipher_ltc_cipher;
++ p->set_cipher = sqlcipher_ltc_set_cipher;
++ p->get_cipher = sqlcipher_ltc_get_cipher;
++ p->get_key_sz = sqlcipher_ltc_get_key_sz;
++ p->get_iv_sz = sqlcipher_ltc_get_iv_sz;
++ p->get_block_sz = sqlcipher_ltc_get_block_sz;
++ p->get_hmac_sz = sqlcipher_ltc_get_hmac_sz;
++ p->ctx_copy = sqlcipher_ltc_ctx_copy;
++ p->ctx_cmp = sqlcipher_ltc_ctx_cmp;
++ p->ctx_init = sqlcipher_ltc_ctx_init;
++ p->ctx_free = sqlcipher_ltc_ctx_free;
++ p->add_random = sqlcipher_ltc_add_random;
+ }
+-#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;
++/* END SQLCIPHER */
+
-+ /* Loop through the tables in the main database. For each, do
-+ ** an "INSERT INTO rekey_db.xxx SELECT * FROM main.xxx;" to copy
-+ ** the contents to the temporary database.
-+ */
-+ zSql = sqlite3_mprintf(
-+ "SELECT 'INSERT INTO %s.' || quote(name) "
-+ "|| ' SELECT * FROM main.' || quote(name) || ';'"
-+ "FROM main.sqlite_master "
-+ "WHERE type = 'table' AND name!='sqlite_sequence' "
-+ " AND rootpage>0"
-+ , attachedDb);
-+ rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
-+ if( rc!=SQLITE_OK ) goto end_of_export;
-+ sqlite3_free(zSql);
++/************** End of crypto_libtomcrypt.c **********************************/
++/************** Begin file crypto_openssl.c **********************************/
++/*
++** SQLCipher
++** http://sqlcipher.net
++**
++** Copyright (c) 2008 - 2013, ZETETIC LLC
++** All rights reserved.
++**
++** 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
++** notice, this list of conditions and the following disclaimer.
++** * Redistributions in binary form must reproduce the above copyright
++** notice, this list of conditions and the following disclaimer in the
++** documentation and/or other materials provided with the distribution.
++** * 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.
++**
++** 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
++** DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY
++** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++** 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.
++**
++*/
++/* BEGIN SQLCIPHER */
++#ifdef SQLITE_HAS_CODEC
++#ifdef SQLCIPHER_CRYPTO_OPENSSL
++#include <openssl/rand.h>
++#include <openssl/evp.h>
++#include <openssl/hmac.h>
+
-+ /* Copy over the sequence table
-+ */
-+ zSql = sqlite3_mprintf(
-+ "SELECT 'DELETE FROM %s.' || quote(name) || ';' "
-+ "FROM %s.sqlite_master WHERE name='sqlite_sequence' "
-+ , attachedDb, attachedDb);
-+ rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
-+ if( rc!=SQLITE_OK ) goto end_of_export;
-+ sqlite3_free(zSql);
++typedef struct {
++ EVP_CIPHER *evp_cipher;
++} openssl_ctx;
+
-+ zSql = sqlite3_mprintf(
-+ "SELECT 'INSERT INTO %s.' || quote(name) "
-+ "|| ' SELECT * FROM main.' || quote(name) || ';' "
-+ "FROM %s.sqlite_master WHERE name=='sqlite_sequence';"
-+ , attachedDb, attachedDb);
-+ rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
-+ if( rc!=SQLITE_OK ) goto end_of_export;
-+ sqlite3_free(zSql);
+
-+ /* Copy the triggers, views, and virtual tables from the main database
-+ ** over to the temporary database. None of these objects has any
-+ ** associated storage, so all we have to do is copy their entries
-+ ** from the SQLITE_MASTER table.
-+ */
-+ zSql = sqlite3_mprintf(
-+ "INSERT INTO %s.sqlite_master "
-+ " SELECT type, name, tbl_name, rootpage, sql"
-+ " FROM main.sqlite_master"
-+ " WHERE type='view' OR type='trigger'"
-+ " OR (type='table' AND rootpage=0)"
-+ , attachedDb);
-+ rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execSql(db, &pzErrMsg, zSql);
-+ if( rc!=SQLITE_OK ) goto end_of_export;
-+ sqlite3_free(zSql);
++static unsigned int openssl_external_init = 0;
++static unsigned int openssl_init_count = 0;
+
-+ zSql = NULL;
-+end_of_export:
-+ db->flags = saved_flags;
-+ db->nChange = saved_nChange;
-+ db->nTotalChange = saved_nTotalChange;
-+ db->xTrace = saved_xTrace;
+
-+ sqlite3_free(zSql);
++static int sqlcipher_openssl_add_random(void *ctx, void *buffer, int length) {
++ RAND_add(buffer, length, 0);
++ return SQLITE_OK;
++}
+
-+ if(rc) {
-+ if(pzErrMsg != NULL) {
-+ sqlite3_result_error(context, pzErrMsg, -1);
-+ sqlite3DbFree(db, pzErrMsg);
-+ } else {
-+ sqlite3_result_error(context, sqlite3ErrStr(rc), -1);
-+ }
++/* 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.
++ Thus it performs some basic counting to ensure that only the last and final
++ sqlcipher_openssl_deactivate() will free the EVP structures.
++*/
++static int sqlcipher_openssl_activate(void *ctx) {
++ /* we'll initialize openssl and increment the internal init counter
++ but only if it hasn't been initalized outside of SQLCipher by this program
++ e.g. on startup */
++ if(openssl_init_count == 0 && EVP_get_cipherbyname(CIPHER) != NULL) {
++ openssl_external_init = 1;
+ }
++
++ if(openssl_external_init == 0) {
++ if(openssl_init_count == 0) {
++ OpenSSL_add_all_algorithms();
+ }
+- }
+- return rc;
++ openssl_init_count++;
++ }
++ return SQLITE_OK;
+ }
+
+-/*
+-** 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;
++/* deactivate SQLCipher, most imporantly decremeting the activation count and
++ freeing the EVP structures on the final deactivation to ensure that
++ OpenSSL memory is cleaned up */
++static int sqlcipher_openssl_deactivate(void *ctx) {
++ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
++ /* If it is initialized externally, then the init counter should never be greater than zero.
++ This should prevent SQLCipher from "cleaning up" openssl
++ when something else in the program might be using it. */
++ if(openssl_external_init == 0) {
++ openssl_init_count--;
++ /* if the counter reaches zero after it's decremented release EVP memory
++ Note: this code will only be reached if OpensSSL_add_all_algorithms()
++ is called by SQLCipher internally. */
++ if(openssl_init_count == 0) {
++ EVP_cleanup();
+ }
+ }
+- for(i=1; i<argc; i++){
+- z = sqlite3_value_text(argv[i]);
+- if( z==0 || parseModifier(context, (char*)z, p) ) return 1;
+- }
+- return 0;
++ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
++ return SQLITE_OK;
+ }
+
++static const char* sqlcipher_openssl_get_provider_name(void *ctx) {
++ return "openssl";
++}
+
+-/*
+-** The following routines implement the various date and time functions
+-** of SQLite.
+-*/
++/* generate a defined number of random bytes */
++static int sqlcipher_openssl_random (void *ctx, void *buffer, int length) {
++ return (RAND_bytes((unsigned char *)buffer, length) == 1) ? SQLITE_OK : SQLITE_ERROR;
+}
+
++static int sqlcipher_openssl_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) {
++ HMAC_CTX hctx;
++ unsigned int outlen;
++ HMAC_CTX_init(&hctx);
++ HMAC_Init_ex(&hctx, hmac_key, key_sz, EVP_sha1(), NULL);
++ HMAC_Update(&hctx, in, in_sz);
++ HMAC_Update(&hctx, in2, in2_sz);
++ HMAC_Final(&hctx, out, &outlen);
++ HMAC_CTX_cleanup(&hctx);
++ return SQLITE_OK;
++}
+
+-/*
+-** 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);
+- }
++static int sqlcipher_openssl_kdf(void *ctx, const char *pass, int pass_sz, unsigned char* salt, int
salt_sz, int workfactor, int key_sz, unsigned char *key) {
++ PKCS5_PBKDF2_HMAC_SHA1(pass, pass_sz, salt, salt_sz, workfactor, key_sz, key);
++ return SQLITE_OK;
+ }
+
+-/*
+-** 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);
+- }
++static int sqlcipher_openssl_cipher(void *ctx, int mode, unsigned char *key, int key_sz, unsigned char *iv,
unsigned char *in, int in_sz, unsigned char *out) {
++ EVP_CIPHER_CTX ectx;
++ int tmp_csz, csz;
++
++ EVP_CipherInit(&ectx, ((openssl_ctx *)ctx)->evp_cipher, NULL, NULL, mode);
++ EVP_CIPHER_CTX_set_padding(&ectx, 0); // no padding
++ EVP_CipherInit(&ectx, NULL, key, iv, mode);
++ EVP_CipherUpdate(&ectx, out, &tmp_csz, in, in_sz);
++ csz = tmp_csz;
++ out += tmp_csz;
++ EVP_CipherFinal(&ectx, out, &tmp_csz);
++ csz += tmp_csz;
++ EVP_CIPHER_CTX_cleanup(&ectx);
++ assert(in_sz == csz);
++ return SQLITE_OK;
+ }
+
+-/*
+-** 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);
+- }
++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;
+ }
+
+-/*
+-** 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);
+- }
++static const char* sqlcipher_openssl_get_cipher(void *ctx) {
++ return EVP_CIPHER_name(((openssl_ctx *)ctx)->evp_cipher);
+ }
+
+-/*
+-** 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 = (const char*)sqlite3_value_text(argv[0]);
+- char zBuf[100];
+- 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);
++static int sqlcipher_openssl_get_key_sz(void *ctx) {
++ return EVP_CIPHER_key_length(((openssl_ctx *)ctx)->evp_cipher);
+ }
+
+-/*
+-** 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);
++static int sqlcipher_openssl_get_iv_sz(void *ctx) {
++ return EVP_CIPHER_iv_length(((openssl_ctx *)ctx)->evp_cipher);
+ }
+
+-/*
+-** 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);
++static int sqlcipher_openssl_get_block_sz(void *ctx) {
++ return EVP_CIPHER_block_size(((openssl_ctx *)ctx)->evp_cipher);
+ }
+
+-/*
+-** 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);
++static int sqlcipher_openssl_get_hmac_sz(void *ctx) {
++ return EVP_MD_size(EVP_sha1());
+ }
+-#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];
++static int sqlcipher_openssl_ctx_copy(void *target_ctx, void *source_ctx) {
++ memcpy(target_ctx, source_ctx, sizeof(openssl_ctx));
++ return SQLITE_OK;
++}
+
+- UNUSED_PARAMETER(argc);
+- UNUSED_PARAMETER(argv);
++static int sqlcipher_openssl_ctx_cmp(void *c1, void *c2) {
++ return ((openssl_ctx *)c1)->evp_cipher == ((openssl_ctx *)c2)->evp_cipher;
++}
+
+- db = sqlite3_context_db_handle(context);
+- if( sqlite3OsCurrentTimeInt64(db->pVfs, &iT) ) return;
+- t = iT/1000 - 10000*(sqlite3_int64)21086676;
+-#ifdef 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);
+- }
++static int sqlcipher_openssl_ctx_init(void **ctx) {
++ *ctx = sqlcipher_malloc(sizeof(openssl_ctx));
++ if(*ctx == NULL) return SQLITE_NOMEM;
++ sqlcipher_openssl_activate(*ctx);
++ return SQLITE_OK;
+ }
+-#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);
++static int sqlcipher_openssl_ctx_free(void **ctx) {
++ sqlcipher_openssl_deactivate(*ctx);
++ sqlcipher_free(*ctx, sizeof(openssl_ctx));
++ return SQLITE_OK;
++}
+
+- for(i=0; i<ArraySize(aDateTimeFuncs); i++){
+- sqlite3FuncDefInsert(pHash, &aFunc[i]);
+- }
++int sqlcipher_openssl_setup(sqlcipher_provider *p) {
++ p->activate = sqlcipher_openssl_activate;
++ p->deactivate = sqlcipher_openssl_deactivate;
++ p->get_provider_name = sqlcipher_openssl_get_provider_name;
++ p->random = sqlcipher_openssl_random;
++ p->hmac = sqlcipher_openssl_hmac;
++ p->kdf = sqlcipher_openssl_kdf;
++ p->cipher = sqlcipher_openssl_cipher;
++ p->set_cipher = sqlcipher_openssl_set_cipher;
++ p->get_cipher = sqlcipher_openssl_get_cipher;
++ p->get_key_sz = sqlcipher_openssl_get_key_sz;
++ p->get_iv_sz = sqlcipher_openssl_get_iv_sz;
++ p->get_block_sz = sqlcipher_openssl_get_block_sz;
++ p->get_hmac_sz = sqlcipher_openssl_get_hmac_sz;
++ p->ctx_copy = sqlcipher_openssl_ctx_copy;
++ p->ctx_cmp = sqlcipher_openssl_ctx_cmp;
++ p->ctx_init = sqlcipher_openssl_ctx_init;
++ p->ctx_free = sqlcipher_openssl_ctx_free;
++ p->add_random = sqlcipher_openssl_add_random;
++ return SQLITE_OK;
+ }
+
+-/************** 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_
+#endif
+#endif
++/* END SQLCIPHER */
+
++/************** End of crypto_openssl.c **************************************/
++/************** Begin file crypto_cc.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.
++** SQLCipher
++** http://sqlcipher.net
+ **
+-** The following functions are instrumented for malloc() failure
+-** testing:
+-**
+-** sqlite3OsRead()
+-** sqlite3OsWrite()
+-** sqlite3OsSync()
+-** sqlite3OsFileSize()
+-** sqlite3OsLock()
+-** sqlite3OsCheckReservedLock()
+-** sqlite3OsFileControl()
+-** sqlite3OsShmMap()
+-** sqlite3OsOpen()
+-** sqlite3OsDelete()
+-** sqlite3OsAccess()
+-** sqlite3OsFullPathname()
++** Copyright (c) 2008 - 2013, ZETETIC LLC
++** All rights reserved.
++**
++** 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
++** notice, this list of conditions and the following disclaimer.
++** * Redistributions in binary form must reproduce the above copyright
++** notice, this list of conditions and the following disclaimer in the
++** documentation and/or other materials provided with the distribution.
++** * 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.
++**
++** 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
++** DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY
++** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++** 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.
+ **
+ */
+-#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
++/* BEGIN SQLCIPHER */
++#ifdef SQLITE_HAS_CODEC
++#ifdef SQLCIPHER_CRYPTO_CC
++#include <CommonCrypto/CommonCrypto.h>
++#include <Security/SecRandom.h>
+
+-/*
+-** 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);
++/* 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;
+ }
+-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);
+
-+/************** End of crypto_impl.c *****************************************/
++static const char* sqlcipher_cc_get_provider_name(void *ctx) {
++ return "commoncrypto";
+ }
+-SQLITE_PRIVATE int sqlite3OsUnlock(sqlite3_file *id, int lockType){
+- return id->pMethods->xUnlock(id, lockType);
++
++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);
++ CCHmacUpdate(&hmac_context, in, in_sz);
++ CCHmacUpdate(&hmac_context, in2, in2_sz);
++ CCHmacFinal(&hmac_context, out);
++ return SQLITE_OK;
+ }
+-SQLITE_PRIVATE int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut){
+- DO_OS_MALLOC_TEST(id);
+- return id->pMethods->xCheckReservedLock(id, pResOut);
++
++static int sqlcipher_cc_kdf(void *ctx, const char *pass, int pass_sz, unsigned char* salt, int salt_sz, int
workfactor, int key_sz, unsigned char *key) {
++ CCKeyDerivationPBKDF(kCCPBKDF2, pass, pass_sz, salt, salt_sz, kCCPRFHmacAlgSHA1, workfactor, key, key_sz);
++ return SQLITE_OK;
+ }
+
+-/*
+-** 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){
+- DO_OS_MALLOC_TEST(id);
+- return id->pMethods->xFileControl(id, op, pArg);
++static int sqlcipher_cc_cipher(void *ctx, int mode, unsigned char *key, int key_sz, unsigned char *iv,
unsigned char *in, int in_sz, unsigned char *out) {
++ CCCryptorRef cryptor;
++ size_t tmp_csz, csz;
++ CCOperation op = mode == CIPHER_ENCRYPT ? kCCEncrypt : kCCDecrypt;
++
++ CCCryptorCreate(op, kCCAlgorithmAES128, 0, key, kCCKeySizeAES256, iv, &cryptor);
++ CCCryptorUpdate(cryptor, in, in_sz, out, in_sz, &tmp_csz);
++ csz = tmp_csz;
++ out += tmp_csz;
++ CCCryptorFinal(cryptor, out, in_sz - csz, &tmp_csz);
++ csz += tmp_csz;
++ CCCryptorRelease(cryptor);
++ assert(size == csz);
++
++ return SQLITE_OK;
+ }
+-SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file *id, int op, void *pArg){
+- (void)id->pMethods->xFileControl(id, op, pArg);
++
++static int sqlcipher_cc_set_cipher(void *ctx, const char *cipher_name) {
++ return SQLITE_OK;
+ }
+
+-SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id){
+- int (*xSectorSize)(sqlite3_file*) = id->pMethods->xSectorSize;
+- return (xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE);
++static const char* sqlcipher_cc_get_cipher(void *ctx) {
++ return "aes-256-cbc";
+ }
+-SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id){
+- return id->pMethods->xDeviceCharacteristics(id);
++
++static int sqlcipher_cc_get_key_sz(void *ctx) {
++ return kCCKeySizeAES256;
+ }
+-SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int offset, int n, int flags){
+- return id->pMethods->xShmLock(id, offset, n, flags);
++
++static int sqlcipher_cc_get_iv_sz(void *ctx) {
++ return kCCBlockSizeAES128;
+ }
+-SQLITE_PRIVATE void sqlite3OsShmBarrier(sqlite3_file *id){
+- id->pMethods->xShmBarrier(id);
++
++static int sqlcipher_cc_get_block_sz(void *ctx) {
++ return kCCBlockSizeAES128;
+ }
+-SQLITE_PRIVATE int sqlite3OsShmUnmap(sqlite3_file *id, int deleteFlag){
+- return id->pMethods->xShmUnmap(id, deleteFlag);
++
++static int sqlcipher_cc_get_hmac_sz(void *ctx) {
++ return CC_SHA1_DIGEST_LENGTH;
+ }
+-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);
++
++static int sqlcipher_cc_ctx_copy(void *target_ctx, void *source_ctx) {
++ return SQLITE_OK;
+ }
+
+-#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);
++static int sqlcipher_cc_ctx_cmp(void *c1, void *c2) {
++ return SQLITE_OK;
+ }
+-SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *id, i64 iOff, void *p){
+- return id->pMethods->xUnfetch(id, iOff, p);
++
++static int sqlcipher_cc_ctx_init(void **ctx) {
++ return SQLITE_OK;
+ }
+-#else
+-/* No-op stubs to use when memory-mapped I/O is disabled */
+-SQLITE_PRIVATE int sqlite3OsFetch(sqlite3_file *id, i64 iOff, int iAmt, void **pp){
+- *pp = 0;
++
++static int sqlcipher_cc_ctx_free(void **ctx) {
+ return SQLITE_OK;
+ }
+-SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *id, i64 iOff, void *p){
++
++int sqlcipher_cc_setup(sqlcipher_provider *p) {
++ p->random = sqlcipher_cc_random;
++ p->get_provider_name = sqlcipher_cc_get_provider_name;
++ p->hmac = sqlcipher_cc_hmac;
++ p->kdf = sqlcipher_cc_kdf;
++ p->cipher = sqlcipher_cc_cipher;
++ p->set_cipher = sqlcipher_cc_set_cipher;
++ p->get_cipher = sqlcipher_cc_get_cipher;
++ p->get_key_sz = sqlcipher_cc_get_key_sz;
++ p->get_iv_sz = sqlcipher_cc_get_iv_sz;
++ p->get_block_sz = sqlcipher_cc_get_block_sz;
++ p->get_hmac_sz = sqlcipher_cc_get_hmac_sz;
++ p->ctx_copy = sqlcipher_cc_ctx_copy;
++ p->ctx_cmp = sqlcipher_cc_ctx_cmp;
++ p->ctx_init = sqlcipher_cc_ctx_init;
++ p->ctx_free = sqlcipher_cc_ctx_free;
+ return SQLITE_OK;
+ }
++
++#endif
+ #endif
++/* END SQLCIPHER */
+
++/************** End of crypto_cc.c *******************************************/
+/************** Begin file global.c ******************************************/
-+/*
+ /*
+-** The next group of routines are convenience wrappers around the
+-** VFS methods.
+** 2008 June 13
+**
+** The author disclaims copyright to this source code. In place of
@@ -2510,15 +5379,194 @@
+*************************************************************************
+**
+** This file contains definitions of global variables and contants.
-+*/
-+
+ */
+-SQLITE_PRIVATE int sqlite3OsOpen(
+- sqlite3_vfs *pVfs,
+- const char *zPath,
+- sqlite3_file *pFile,
+- int flags,
+- int *pFlagsOut
+-){
+- int rc;
+- DO_OS_MALLOC_TEST(0);
+- /* 0x87f7f is a mask of SQLITE_OPEN_ flags that are valid to be passed
+- ** down into the VFS layer. Some SQLITE_OPEN_ flags (for example,
+- ** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before
+- ** reaching the VFS. */
+- rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x87f7f, pFlagsOut);
+- assert( rc==SQLITE_OK || pFile->pMethods==0 );
+- return rc;
+-}
+-SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
+- DO_OS_MALLOC_TEST(0);
+- assert( dirSync==0 || dirSync==1 );
+- return pVfs->xDelete(pVfs, zPath, dirSync);
+-}
+-SQLITE_PRIVATE int sqlite3OsAccess(
+- sqlite3_vfs *pVfs,
+- const char *zPath,
+- int flags,
+- int *pResOut
+-){
+- DO_OS_MALLOC_TEST(0);
+- return pVfs->xAccess(pVfs, zPath, flags, pResOut);
+-}
+-SQLITE_PRIVATE int sqlite3OsFullPathname(
+- sqlite3_vfs *pVfs,
+- const char *zPath,
+- int nPathOut,
+- char *zPathOut
+-){
+- DO_OS_MALLOC_TEST(0);
+- zPathOut[0] = 0;
+- return pVfs->xFullPathname(pVfs, zPath, nPathOut, zPathOut);
+-}
+-#ifndef SQLITE_OMIT_LOAD_EXTENSION
+-SQLITE_PRIVATE void *sqlite3OsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
+- return pVfs->xDlOpen(pVfs, zPath);
+-}
+-SQLITE_PRIVATE void sqlite3OsDlError(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
+- pVfs->xDlError(pVfs, nByte, zBufOut);
+-}
+-SQLITE_PRIVATE void (*sqlite3OsDlSym(sqlite3_vfs *pVfs, void *pHdle, const char *zSym))(void){
+- return pVfs->xDlSym(pVfs, pHdle, zSym);
+-}
+-SQLITE_PRIVATE void sqlite3OsDlClose(sqlite3_vfs *pVfs, void *pHandle){
+- pVfs->xDlClose(pVfs, pHandle);
+-}
+-#endif /* SQLITE_OMIT_LOAD_EXTENSION */
+-SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
+- return pVfs->xRandomness(pVfs, nByte, zBufOut);
+-}
+-SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *pVfs, int nMicro){
+- return pVfs->xSleep(pVfs, nMicro);
+-}
+-SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
+- int rc;
+- /* IMPLEMENTATION-OF: R-49045-42493 SQLite will use the xCurrentTimeInt64()
+- ** method to get the current date and time if that method is available
+- ** (if iVersion is 2 or greater and the function pointer is not NULL) and
+- ** will fall back to xCurrentTime() if xCurrentTimeInt64() is
+- ** unavailable.
+- */
+- if( pVfs->iVersion>=2 && pVfs->xCurrentTimeInt64 ){
+- rc = pVfs->xCurrentTimeInt64(pVfs, pTimeOut);
+- }else{
+- double r;
+- rc = pVfs->xCurrentTime(pVfs, &r);
+- *pTimeOut = (sqlite3_int64)(r*86400000.0);
+- }
+- return rc;
+-}
+-
+-SQLITE_PRIVATE int sqlite3OsOpenMalloc(
+- sqlite3_vfs *pVfs,
+- const char *zFile,
+- sqlite3_file **ppFile,
+- int flags,
+- int *pOutFlags
+-){
+- int rc = SQLITE_NOMEM;
+- sqlite3_file *pFile;
+- pFile = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile);
+- if( pFile ){
+- rc = sqlite3OsOpen(pVfs, zFile, pFile, flags, pOutFlags);
+- if( rc!=SQLITE_OK ){
+- sqlite3_free(pFile);
+- }else{
+- *ppFile = pFile;
+- }
+- }
+- return rc;
+-}
+-SQLITE_PRIVATE int sqlite3OsCloseFree(sqlite3_file *pFile){
+- int rc = SQLITE_OK;
+- assert( pFile );
+- rc = sqlite3OsClose(pFile);
+- sqlite3_free(pFile);
+- return rc;
+-}
+-
+-/*
+-** This function is a wrapper around the OS specific implementation of
+-** sqlite3_os_init(). The purpose of the wrapper is to provide the
+-** ability to simulate a malloc failure, so that the handling of an
+-** error in sqlite3_os_init() by the upper layers can be tested.
+-*/
+-SQLITE_PRIVATE int sqlite3OsInit(void){
+- void *p = sqlite3_malloc(10);
+- if( p==0 ) return SQLITE_NOMEM;
+- sqlite3_free(p);
+- return sqlite3_os_init();
+-}
+-
+-/*
+-** The list of all registered VFS implementations.
+-*/
+-static sqlite3_vfs * SQLITE_WSD vfsList = 0;
+-#define vfsList GLOBAL(sqlite3_vfs *, vfsList)
+-
+-/*
+-** 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){
+- sqlite3_vfs *pVfs = 0;
+-#if SQLITE_THREADSAFE
+- sqlite3_mutex *mutex;
+-#endif
+-#ifndef SQLITE_OMIT_AUTOINIT
+- int rc = sqlite3_initialize();
+- if( rc ) return 0;
+-#endif
+-#if SQLITE_THREADSAFE
+- mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
+-#endif
+- sqlite3_mutex_enter(mutex);
+- for(pVfs = vfsList; pVfs; pVfs=pVfs->pNext){
+- if( zVfs==0 ) break;
+- if( strcmp(zVfs, pVfs->zName)==0 ) break;
+- }
+- sqlite3_mutex_leave(mutex);
+- return pVfs;
+-}
+-
+-/*
+-** Unlink a VFS from the linked list
+-*/
+-static void vfsUnlink(sqlite3_vfs *pVfs){
+- assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)) );
+- if( pVfs==0 ){
+- /* No-op */
+- }else if( vfsList==pVfs ){
+- vfsList = pVfs->pNext;
+- }else if( vfsList ){
+- sqlite3_vfs *p = vfsList;
+- while( p->pNext && p->pNext!=pVfs ){
+- p = p->pNext;
+- }
+- if( p->pNext==pVfs ){
+- p->pNext = pVfs->pNext;
+- }
+- }
+-}
+
+-/*
+-** Register a VFS with the system. It is harmless to register the same
+-** VFS multiple times. The new VFS becomes the default if makeDflt is
+-** true.
+/* An array to map all upper-case characters into their corresponding
+** lower-case character.
+**
+** 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.
-+*/
+ */
+-SQLITE_API int 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;
+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,
@@ -2536,7 +5584,28 @@
+ 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
+- MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
+- sqlite3_mutex_enter(mutex);
+- vfsUnlink(pVfs);
+- if( makeDflt || vfsList==0 ){
+- pVfs->pNext = vfsList;
+- vfsList = pVfs;
+- }else{
+- pVfs->pNext = vfsList->pNext;
+- vfsList->pNext = pVfs;
+- }
+- assert(vfsList);
+- sqlite3_mutex_leave(mutex);
+- return SQLITE_OK;
+-}
+-
+-/*
+-** Unregister a VFS so that it is no longer accessible.
+-*/
+-SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs *pVfs){
+-#if SQLITE_THREADSAFE
+- sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
+#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 */
@@ -2554,13 +5623,23 @@
+ 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 */
-+#endif
+ #endif
+- sqlite3_mutex_enter(mutex);
+- vfsUnlink(pVfs);
+- sqlite3_mutex_leave(mutex);
+- return SQLITE_OK;
+-}
+};
-+
-+/*
+
+-/************** End of os.c **************************************************/
+-/************** Begin file fault.c *******************************************/
+ /*
+-** 2008 Jan 22
+** The following 256 byte lookup table is used to support SQLites built-in
+** equivalents to the following standard library functions:
-+**
+ **
+-** The author disclaims copyright to this source code. In place of
+-** a legal notice, here is a blessing:
+** isspace() 0x01
+** isalpha() 0x02
+** isdigit() 0x04
@@ -2568,17 +5647,32 @@
+** isxdigit() 0x08
+** toupper() 0x20
+** SQLite identifier character 0x40
-+**
+ **
+-** 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.
+** Bit 0x20 is set if the mapped character requires translation to upper
+** case. i.e. if the character is a lower-case ASCII character.
+** If x is a lower-case ASCII character, then its upper-case equivalent
+** is (x - 0x20). Therefore toupper() can be implemented as:
-+**
+ **
+-*************************************************************************
+** (x & ~(map[x]&0x20))
-+**
+ **
+-** This file contains code to support the concept of "benign"
+-** malloc failures (when the xMalloc() or xRealloc() method of the
+-** sqlite3_mem_methods structure fails to allocate a block of memory
+-** and returns 0).
+** Standard function tolower() is implemented using the sqlite3UpperToLower[]
+** array. tolower() is used more often than toupper() by SQLite.
-+**
+ **
+-** Most malloc failures are non-benign. After they occur, SQLite
+-** abandons the current operation and returns an error code (usually
+-** SQLITE_NOMEM) to the user. However, sometimes a fault is not necessarily
+-** fatal. For example, if a malloc fails while resizing a hash table, this
+-** is completely recoverable simply by not carrying out the resize. The
+-** hash table will continue to function normally. So a malloc failure
+-** during a hash table resize is a benign fault.
+** Bit 0x40 is set if the character non-alphanumeric and can be used in an
+** SQLite identifier. Identifiers are alphanumerics, "_", "$", and any
+** non-ASCII UTF character. Hence the test for whether or not a character is
@@ -2586,7 +5680,7 @@
+**
+** 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 ........ */
@@ -2597,7 +5691,7 @@
+ 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 */
@@ -2606,7 +5700,17 @@
+ 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{|}~. */
-+
+
+-#ifndef SQLITE_OMIT_BUILTIN_TEST
+-
+-/*
+-** Global variables.
+-*/
+-typedef struct BenignMallocHooks BenignMallocHooks;
+-static SQLITE_WSD struct BenignMallocHooks {
+- void (*xBenignBegin)(void);
+- void (*xBenignEnd)(void);
+-} sqlite3Hooks = { 0, 0 };
+ 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 ........ */
@@ -2615,7 +5719,20 @@
+ 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 ........ */
-+
+
+-/* The "wsdHooks" macro will resolve to the appropriate BenignMallocHooks
+-** structure. 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, wsdHooks can refer directly
+-** to the "sqlite3Hooks" state vector declared above.
+-*/
+-#ifdef SQLITE_OMIT_WSD
+-# define wsdHooksInit \
+- BenignMallocHooks *x = &GLOBAL(BenignMallocHooks,sqlite3Hooks)
+-# define wsdHooks x[0]
+-#else
+-# define wsdHooksInit
+-# define wsdHooks sqlite3Hooks
+ 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 ........ */
@@ -2625,21 +5742,53 @@
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* f0..f7 ........ */
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 /* f8..ff ........ */
+};
-+#endif
-+
+ #endif
+
+#ifndef SQLITE_USE_URI
+# define SQLITE_USE_URI 0
+#endif
-+
-+/*
+
+-/*
+-** Register hooks to call when sqlite3BeginBenignMalloc() and
+-** sqlite3EndBenignMalloc() are called, respectively.
+-*/
+-SQLITE_PRIVATE void sqlite3BenignMallocHooks(
+- void (*xBenignBegin)(void),
+- void (*xBenignEnd)(void)
+-){
+- wsdHooksInit;
+- wsdHooks.xBenignBegin = xBenignBegin;
+- wsdHooks.xBenignEnd = xBenignEnd;
+-}
++#ifndef SQLITE_ALLOW_COVERING_INDEX_SCAN
++# define SQLITE_ALLOW_COVERING_INDEX_SCAN 1
++#endif
+
+ /*
+-** This (sqlite3EndBenignMalloc()) is called by SQLite code to indicate that
+-** subsequent malloc failures are benign. A call to sqlite3EndBenignMalloc()
+-** indicates that subsequent malloc failures are non-benign.
+** The following singleton contains the global configuration for
+** the SQLite library.
-+*/
+ */
+-SQLITE_PRIVATE void sqlite3BeginBenignMalloc(void){
+- wsdHooksInit;
+- if( wsdHooks.xBenignBegin ){
+- wsdHooks.xBenignBegin();
+- }
+-}
+-SQLITE_PRIVATE void sqlite3EndBenignMalloc(void){
+- wsdHooksInit;
+- if( wsdHooks.xBenignEnd ){
+- wsdHooks.xBenignEnd();
+- }
+-}
+SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
+ SQLITE_DEFAULT_MEMSTATUS, /* bMemstat */
+ 1, /* bCoreMutex */
+ SQLITE_THREADSAFE==1, /* bFullMutex */
+ SQLITE_USE_URI, /* bOpenUri */
++ SQLITE_ALLOW_COVERING_INDEX_SCAN, /* bUseCis */
+ 0x7ffffffe, /* mxStrlen */
+ 128, /* szLookaside */
+ 500, /* nLookaside */
@@ -2649,6 +5798,8 @@
+ (void*)0, /* pHeap */
+ 0, /* nHeap */
+ 0, 0, /* mnHeap, mxHeap */
++ SQLITE_DEFAULT_MMAP_SIZE, /* szMmap */
++ SQLITE_MAX_MMAP_SIZE, /* mxMmap */
+ (void*)0, /* pScratch */
+ 0, /* szScratch */
+ 0, /* nScratch */
@@ -2668,32 +5819,72 @@
+ 0, /* xLog */
+ 0, /* pLogArg */
+ 0, /* bLocaltimeFault */
++#ifdef SQLITE_ENABLE_SQLLOG
++ 0, /* xSqllog */
++ 0 /* pSqllogArg */
++#endif
+};
-+
-+
-+/*
+
+-#endif /* #ifndef SQLITE_OMIT_BUILTIN_TEST */
+
+-/************** End of fault.c ***********************************************/
+-/************** Begin file mem0.c ********************************************/
+ /*
+-** 2008 October 28
+-**
+-** 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 a no-op memory allocation drivers for use when
+-** SQLITE_ZERO_MALLOC is defined. The allocation drivers implemented
+-** here always fail. SQLite will not operate with these drivers. These
+-** are merely placeholders. Real drivers must be substituted using
+-** sqlite3_config() before SQLite will operate.
+** Hash table for global functions - functions common to all
+** database connections. After initialization, this table is
+** read-only.
-+*/
+ */
+SQLITE_PRIVATE SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;
-+
-+/*
+
+ /*
+-** This version of the memory allocator is the default. It is
+-** used when no other memory allocator is specified using compile-time
+-** macros.
+** Constant tokens for values 0 and 1.
-+*/
+ */
+-#ifdef SQLITE_ZERO_MALLOC
+SQLITE_PRIVATE const Token sqlite3IntTokens[] = {
+ { "0", 1 },
+ { "1", 1 }
+};
-+
-+
-+/*
+
+-/*
+-** No-op versions of all memory allocation routines
+-*/
+-static void *sqlite3MemMalloc(int nByte){ return 0; }
+-static void sqlite3MemFree(void *pPrior){ return; }
+-static void *sqlite3MemRealloc(void *pPrior, int nByte){ return 0; }
+-static int sqlite3MemSize(void *pPrior){ return 0; }
+-static int sqlite3MemRoundup(int n){ return n; }
+-static int sqlite3MemInit(void *NotUsed){ return SQLITE_OK; }
+-static void sqlite3MemShutdown(void *NotUsed){ return; }
+
+ /*
+-** This routine is the only routine in this file with external linkage.
+** 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.
-+**
+ **
+-** Populate the low-level memory allocation function pointers in
+-** sqlite3GlobalConfig.m with pointers to the routines in this file.
+** 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
@@ -2704,11 +5895,25 @@
+** 0x40000000 results in an incompatible database file format!
+** Changing the pending byte during operating results in undefined
+** and dileterious behavior.
-+*/
+ */
+-SQLITE_PRIVATE void sqlite3MemSetDefault(void){
+- static const sqlite3_mem_methods defaultMethods = {
+- sqlite3MemMalloc,
+- sqlite3MemFree,
+- sqlite3MemRealloc,
+- sqlite3MemSize,
+- sqlite3MemRoundup,
+- sqlite3MemInit,
+- sqlite3MemShutdown,
+- 0
+- };
+- sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods);
+-}
+#ifndef SQLITE_OMIT_WSD
+SQLITE_PRIVATE int sqlite3PendingByte = 0x40000000;
+#endif
-+
+
+-#endif /* SQLITE_ZERO_MALLOC */
+/*
+** Properties of opcodes. The OPFLG_INITIALIZER macro is
+** created by mkopcodeh.awk during compilation. Data is obtained
@@ -2716,70 +5921,57720 @@
+** the vdbe.c file.
+*/
+SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[] = OPFLG_INITIALIZER;
-+
+
+-/************** End of mem0.c ************************************************/
+-/************** Begin file mem1.c ********************************************/
+/************** End of global.c **********************************************/
+/************** Begin file ctime.c *******************************************/
-+/*
+ /*
+-** 2007 August 14
+** 2010 February 23
+ **
+ ** The author disclaims copyright to this source code. In place of
+ ** a legal notice, here is a blessing:
+@@ -15633,807 +15800,1140 @@
+ **
+ *************************************************************************
+ **
+-** This file contains low-level memory allocation drivers for when
+-** SQLite will use the standard C-library malloc/realloc/free interface
+-** to obtain the memory it needs.
+-**
+-** This file contains implementations of the low-level memory allocation
+-** routines specified in the sqlite3_mem_methods object. The content of
+-** this file is only used if SQLITE_SYSTEM_MALLOC is defined. The
+-** SQLITE_SYSTEM_MALLOC macro is defined automatically if neither the
+-** SQLITE_MEMDEBUG nor the SQLITE_WIN32_MALLOC macros are defined. The
+-** default configuration is to use memory allocation routines in this
+-** file.
+-**
+-** C-preprocessor macro summary:
+-**
+-** HAVE_MALLOC_USABLE_SIZE The configure script sets this symbol if
+-** the malloc_usable_size() interface exists
+-** on the target platform. Or, this symbol
+-** can be set manually, if desired.
+-** If an equivalent interface exists by
+-** a different name, using a separate -D
+-** option to rename it.
+-**
+-** SQLITE_WITHOUT_ZONEMALLOC Some older macs lack support for the zone
+-** memory allocator. Set this symbol to enable
+-** building on older macs.
+-**
+-** SQLITE_WITHOUT_MSIZE Set this symbol to disable the use of
+-** _msize() on windows systems. This might
+-** be necessary when compiling for Delphi,
+-** for example.
+-*/
+-
+-/*
+-** This version of the memory allocator is the default. It is
+-** used when no other memory allocator is specified using compile-time
+-** macros.
++** This file implements routines used to report what compile-time options
++** SQLite was built with.
+ */
+-#ifdef SQLITE_SYSTEM_MALLOC
+
+-/*
+-** The MSVCRT has malloc_usable_size() but it is called _msize().
+-** The use of _msize() is automatic, but can be disabled by compiling
+-** with -DSQLITE_WITHOUT_MSIZE
+-*/
+-#if defined(_MSC_VER) && !defined(SQLITE_WITHOUT_MSIZE)
+-# define SQLITE_MALLOCSIZE _msize
+-#endif
++#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
+
+-#if defined(__APPLE__) && !defined(SQLITE_WITHOUT_ZONEMALLOC)
+
+ /*
+-** Use the zone allocator available on apple products unless the
+-** SQLITE_WITHOUT_ZONEMALLOC symbol is defined.
++** 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.
+ */
+-#include <sys/sysctl.h>
+-#include <malloc/malloc.h>
+-#include <libkern/OSAtomic.h>
+-static malloc_zone_t* _sqliteZone_;
+-#define SQLITE_MALLOC(x) malloc_zone_malloc(_sqliteZone_, (x))
+-#define SQLITE_FREE(x) malloc_zone_free(_sqliteZone_, (x));
+-#define SQLITE_REALLOC(x,y) malloc_zone_realloc(_sqliteZone_, (x), (y))
+-#define SQLITE_MALLOCSIZE(x) \
+- (_sqliteZone_ ? _sqliteZone_->size(_sqliteZone_,x) : malloc_size(x))
++static const char * const azCompileOpt[] = {
+
+-#else /* if not __APPLE__ */
++/* 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)
+
+-/*
+-** Use standard C library malloc and free on non-Apple systems.
+-** Also used by Apple systems if SQLITE_WITHOUT_ZONEMALLOC is defined.
+-*/
+-#define SQLITE_MALLOC(x) malloc(x)
+-#define SQLITE_FREE(x) free(x)
+-#define SQLITE_REALLOC(x,y) realloc((x),(y))
+-
+-#if (defined(_MSC_VER) && !defined(SQLITE_WITHOUT_MSIZE)) \
+- || (defined(HAVE_MALLOC_H) && defined(HAVE_MALLOC_USABLE_SIZE))
+-# include <malloc.h> /* Needed for malloc_usable_size on linux */
++#ifdef SQLITE_32BIT_ROWID
++ "32BIT_ROWID",
+ #endif
+-#ifdef HAVE_MALLOC_USABLE_SIZE
+-# ifndef SQLITE_MALLOCSIZE
+-# define SQLITE_MALLOCSIZE(x) malloc_usable_size(x)
+-# endif
+-#else
+-# undef SQLITE_MALLOCSIZE
++#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC
++ "4_BYTE_ALIGNED_MALLOC",
+ #endif
+-
+-#endif /* __APPLE__ or not __APPLE__ */
++#ifdef SQLITE_CASE_SENSITIVE_LIKE
++ "CASE_SENSITIVE_LIKE",
++#endif
++#ifdef SQLITE_CHECK_PAGES
++ "CHECK_PAGES",
++#endif
++#ifdef SQLITE_COVERAGE_TEST
++ "COVERAGE_TEST",
++#endif
++#ifdef SQLITE_DEBUG
++ "DEBUG",
++#endif
++#ifdef 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
++ "DISABLE_DIRSYNC",
++#endif
++#ifdef SQLITE_DISABLE_LFS
++ "DISABLE_LFS",
++#endif
++#ifdef SQLITE_ENABLE_ATOMIC_WRITE
++ "ENABLE_ATOMIC_WRITE",
++#endif
++#ifdef SQLITE_ENABLE_CEROD
++ "ENABLE_CEROD",
++#endif
++#ifdef SQLITE_ENABLE_COLUMN_METADATA
++ "ENABLE_COLUMN_METADATA",
++#endif
++#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
++ "ENABLE_EXPENSIVE_ASSERT",
++#endif
++#ifdef SQLITE_ENABLE_FTS1
++ "ENABLE_FTS1",
++#endif
++#ifdef SQLITE_ENABLE_FTS2
++ "ENABLE_FTS2",
++#endif
++#ifdef SQLITE_ENABLE_FTS3
++ "ENABLE_FTS3",
++#endif
++#ifdef SQLITE_ENABLE_FTS3_PARENTHESIS
++ "ENABLE_FTS3_PARENTHESIS",
++#endif
++#ifdef SQLITE_ENABLE_FTS4
++ "ENABLE_FTS4",
++#endif
++#ifdef SQLITE_ENABLE_ICU
++ "ENABLE_ICU",
++#endif
++#ifdef SQLITE_ENABLE_IOTRACE
++ "ENABLE_IOTRACE",
++#endif
++#ifdef SQLITE_ENABLE_LOAD_EXTENSION
++ "ENABLE_LOAD_EXTENSION",
++#endif
++#ifdef SQLITE_ENABLE_LOCKING_STYLE
++ "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE),
++#endif
++#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
++ "ENABLE_MEMORY_MANAGEMENT",
++#endif
++#ifdef SQLITE_ENABLE_MEMSYS3
++ "ENABLE_MEMSYS3",
++#endif
++#ifdef SQLITE_ENABLE_MEMSYS5
++ "ENABLE_MEMSYS5",
++#endif
++#ifdef SQLITE_ENABLE_OVERSIZE_CELL_CHECK
++ "ENABLE_OVERSIZE_CELL_CHECK",
++#endif
++#ifdef SQLITE_ENABLE_RTREE
++ "ENABLE_RTREE",
++#endif
++#ifdef SQLITE_ENABLE_STAT3
++ "ENABLE_STAT3",
++#endif
++#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
++ "ENABLE_UNLOCK_NOTIFY",
++#endif
++#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
++ "ENABLE_UPDATE_DELETE_LIMIT",
++#endif
++#ifdef SQLITE_HAS_CODEC
++ "HAS_CODEC",
++#endif
++#ifdef SQLITE_HAVE_ISNAN
++ "HAVE_ISNAN",
++#endif
++#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
++ "HOMEGROWN_RECURSIVE_MUTEX",
++#endif
++#ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS
++ "IGNORE_AFP_LOCK_ERRORS",
++#endif
++#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
++ "IGNORE_FLOCK_LOCK_ERRORS",
++#endif
++#ifdef SQLITE_INT64_TYPE
++ "INT64_TYPE",
++#endif
++#ifdef 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
++#ifdef SQLITE_MEMDEBUG
++ "MEMDEBUG",
++#endif
++#ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT
++ "MIXED_ENDIAN_64BIT_FLOAT",
++#endif
++#ifdef SQLITE_NO_SYNC
++ "NO_SYNC",
++#endif
++#ifdef SQLITE_OMIT_ALTERTABLE
++ "OMIT_ALTERTABLE",
++#endif
++#ifdef SQLITE_OMIT_ANALYZE
++ "OMIT_ANALYZE",
++#endif
++#ifdef SQLITE_OMIT_ATTACH
++ "OMIT_ATTACH",
++#endif
++#ifdef SQLITE_OMIT_AUTHORIZATION
++ "OMIT_AUTHORIZATION",
++#endif
++#ifdef SQLITE_OMIT_AUTOINCREMENT
++ "OMIT_AUTOINCREMENT",
++#endif
++#ifdef SQLITE_OMIT_AUTOINIT
++ "OMIT_AUTOINIT",
++#endif
++#ifdef SQLITE_OMIT_AUTOMATIC_INDEX
++ "OMIT_AUTOMATIC_INDEX",
++#endif
++#ifdef SQLITE_OMIT_AUTORESET
++ "OMIT_AUTORESET",
++#endif
++#ifdef SQLITE_OMIT_AUTOVACUUM
++ "OMIT_AUTOVACUUM",
++#endif
++#ifdef SQLITE_OMIT_BETWEEN_OPTIMIZATION
++ "OMIT_BETWEEN_OPTIMIZATION",
++#endif
++#ifdef SQLITE_OMIT_BLOB_LITERAL
++ "OMIT_BLOB_LITERAL",
++#endif
++#ifdef SQLITE_OMIT_BTREECOUNT
++ "OMIT_BTREECOUNT",
++#endif
++#ifdef SQLITE_OMIT_BUILTIN_TEST
++ "OMIT_BUILTIN_TEST",
++#endif
++#ifdef SQLITE_OMIT_CAST
++ "OMIT_CAST",
++#endif
++#ifdef SQLITE_OMIT_CHECK
++ "OMIT_CHECK",
++#endif
++#ifdef SQLITE_OMIT_COMPLETE
++ "OMIT_COMPLETE",
++#endif
++#ifdef SQLITE_OMIT_COMPOUND_SELECT
++ "OMIT_COMPOUND_SELECT",
++#endif
++#ifdef SQLITE_OMIT_DATETIME_FUNCS
++ "OMIT_DATETIME_FUNCS",
++#endif
++#ifdef SQLITE_OMIT_DECLTYPE
++ "OMIT_DECLTYPE",
++#endif
++#ifdef SQLITE_OMIT_DEPRECATED
++ "OMIT_DEPRECATED",
++#endif
++#ifdef SQLITE_OMIT_DISKIO
++ "OMIT_DISKIO",
++#endif
++#ifdef SQLITE_OMIT_EXPLAIN
++ "OMIT_EXPLAIN",
++#endif
++#ifdef SQLITE_OMIT_FLAG_PRAGMAS
++ "OMIT_FLAG_PRAGMAS",
++#endif
++#ifdef SQLITE_OMIT_FLOATING_POINT
++ "OMIT_FLOATING_POINT",
++#endif
++#ifdef SQLITE_OMIT_FOREIGN_KEY
++ "OMIT_FOREIGN_KEY",
++#endif
++#ifdef SQLITE_OMIT_GET_TABLE
++ "OMIT_GET_TABLE",
++#endif
++#ifdef SQLITE_OMIT_INCRBLOB
++ "OMIT_INCRBLOB",
++#endif
++#ifdef SQLITE_OMIT_INTEGRITY_CHECK
++ "OMIT_INTEGRITY_CHECK",
++#endif
++#ifdef SQLITE_OMIT_LIKE_OPTIMIZATION
++ "OMIT_LIKE_OPTIMIZATION",
++#endif
++#ifdef SQLITE_OMIT_LOAD_EXTENSION
++ "OMIT_LOAD_EXTENSION",
++#endif
++#ifdef SQLITE_OMIT_LOCALTIME
++ "OMIT_LOCALTIME",
++#endif
++#ifdef SQLITE_OMIT_LOOKASIDE
++ "OMIT_LOOKASIDE",
++#endif
++#ifdef SQLITE_OMIT_MEMORYDB
++ "OMIT_MEMORYDB",
++#endif
++#ifdef SQLITE_OMIT_OR_OPTIMIZATION
++ "OMIT_OR_OPTIMIZATION",
++#endif
++#ifdef SQLITE_OMIT_PAGER_PRAGMAS
++ "OMIT_PAGER_PRAGMAS",
++#endif
++#ifdef SQLITE_OMIT_PRAGMA
++ "OMIT_PRAGMA",
++#endif
++#ifdef SQLITE_OMIT_PROGRESS_CALLBACK
++ "OMIT_PROGRESS_CALLBACK",
++#endif
++#ifdef SQLITE_OMIT_QUICKBALANCE
++ "OMIT_QUICKBALANCE",
++#endif
++#ifdef SQLITE_OMIT_REINDEX
++ "OMIT_REINDEX",
++#endif
++#ifdef SQLITE_OMIT_SCHEMA_PRAGMAS
++ "OMIT_SCHEMA_PRAGMAS",
++#endif
++#ifdef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
++ "OMIT_SCHEMA_VERSION_PRAGMAS",
++#endif
++#ifdef SQLITE_OMIT_SHARED_CACHE
++ "OMIT_SHARED_CACHE",
++#endif
++#ifdef SQLITE_OMIT_SUBQUERY
++ "OMIT_SUBQUERY",
++#endif
++#ifdef SQLITE_OMIT_TCL_VARIABLE
++ "OMIT_TCL_VARIABLE",
++#endif
++#ifdef SQLITE_OMIT_TEMPDB
++ "OMIT_TEMPDB",
++#endif
++#ifdef SQLITE_OMIT_TRACE
++ "OMIT_TRACE",
++#endif
++#ifdef SQLITE_OMIT_TRIGGER
++ "OMIT_TRIGGER",
++#endif
++#ifdef SQLITE_OMIT_TRUNCATE_OPTIMIZATION
++ "OMIT_TRUNCATE_OPTIMIZATION",
++#endif
++#ifdef SQLITE_OMIT_UTF16
++ "OMIT_UTF16",
++#endif
++#ifdef SQLITE_OMIT_VACUUM
++ "OMIT_VACUUM",
++#endif
++#ifdef SQLITE_OMIT_VIEW
++ "OMIT_VIEW",
++#endif
++#ifdef SQLITE_OMIT_VIRTUALTABLE
++ "OMIT_VIRTUALTABLE",
++#endif
++#ifdef SQLITE_OMIT_WAL
++ "OMIT_WAL",
++#endif
++#ifdef SQLITE_OMIT_WSD
++ "OMIT_WSD",
++#endif
++#ifdef SQLITE_OMIT_XFER_OPT
++ "OMIT_XFER_OPT",
++#endif
++#ifdef SQLITE_PERFORMANCE_TRACE
++ "PERFORMANCE_TRACE",
++#endif
++#ifdef SQLITE_PROXY_DEBUG
++ "PROXY_DEBUG",
++#endif
++#ifdef SQLITE_RTREE_INT_ONLY
++ "RTREE_INT_ONLY",
++#endif
++#ifdef SQLITE_SECURE_DELETE
++ "SECURE_DELETE",
++#endif
++#ifdef SQLITE_SMALL_STACK
++ "SMALL_STACK",
++#endif
++#ifdef SQLITE_SOUNDEX
++ "SOUNDEX",
++#endif
++#ifdef 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
++ "TEST",
++#endif
++#if defined(SQLITE_THREADSAFE)
++ "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE),
++#endif
++#ifdef SQLITE_USE_ALLOCA
++ "USE_ALLOCA",
++#endif
++#ifdef SQLITE_ZERO_MALLOC
++ "ZERO_MALLOC"
++#endif
++};
+
+ /*
+-** Like malloc(), but remember the size of the allocation
+-** so that we can find it later using sqlite3MemSize().
++** Given the name of a compile-time option, return true if that option
++** was used and false if not.
+ **
+-** For this low-level routine, we are guaranteed that nByte>0 because
+-** cases of nByte<=0 will be intercepted and dealt with by higher level
+-** routines.
++** The name can optionally begin with "SQLITE_" but the "SQLITE_" prefix
++** is not required for a match.
+ */
+-static void *sqlite3MemMalloc(int nByte){
+-#ifdef SQLITE_MALLOCSIZE
+- void *p = SQLITE_MALLOC( nByte );
+- if( p==0 ){
+- testcase( sqlite3GlobalConfig.xLog!=0 );
+- sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes of memory", nByte);
+- }
+- return p;
+-#else
+- sqlite3_int64 *p;
+- assert( nByte>0 );
+- nByte = ROUND8(nByte);
+- p = SQLITE_MALLOC( nByte+8 );
+- if( p ){
+- p[0] = nByte;
+- p++;
+- }else{
+- testcase( sqlite3GlobalConfig.xLog!=0 );
+- sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes of memory", nByte);
++SQLITE_API int sqlite3_compileoption_used(const char *zOptName){
++ int i, n;
++ 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
++ && sqlite3CtypeMap[(unsigned char)azCompileOpt[i][n]]==0
++ ){
++ return 1;
++ }
+ }
+- return (void *)p;
+-#endif
++ return 0;
+ }
+
+ /*
+-** Like free() but works for allocations obtained from sqlite3MemMalloc()
+-** or sqlite3MemRealloc().
+-**
+-** For this low-level routine, we already know that pPrior!=0 since
+-** cases where pPrior==0 will have been intecepted and dealt with
+-** by higher-level routines.
++** Return the N-th compile-time option string. If N is out of range,
++** return a NULL pointer.
+ */
+-static void sqlite3MemFree(void *pPrior){
+-#ifdef SQLITE_MALLOCSIZE
+- SQLITE_FREE(pPrior);
+-#else
+- sqlite3_int64 *p = (sqlite3_int64*)pPrior;
+- assert( pPrior!=0 );
+- p--;
+- SQLITE_FREE(p);
+-#endif
++SQLITE_API const char *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 ******************************************/
+ /*
+-** Report the allocated size of a prior return from xMalloc()
+-** or xRealloc().
++** 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.
+ */
+-static int sqlite3MemSize(void *pPrior){
+-#ifdef SQLITE_MALLOCSIZE
+- return pPrior ? (int)SQLITE_MALLOCSIZE(pPrior) : 0;
+-#else
+- sqlite3_int64 *p;
+- if( pPrior==0 ) return 0;
+- p = (sqlite3_int64*)pPrior;
+- p--;
+- return (int)p[0];
+-#endif
+-}
+-
++/************** Include vdbeInt.h in the middle of status.c ******************/
++/************** Begin file vdbeInt.h *****************************************/
+ /*
+-** Like realloc(). Resize an allocation previously obtained from
+-** sqlite3MemMalloc().
++** 2003 September 6
+ **
+-** 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
+-** cases where nByte<=0 will have been intercepted by higher-level
+-** routines and redirected to xFree.
++** 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.
+ */
+-static void *sqlite3MemRealloc(void *pPrior, int nByte){
+-#ifdef SQLITE_MALLOCSIZE
+- void *p = SQLITE_REALLOC(pPrior, nByte);
+- if( p==0 ){
+- testcase( sqlite3GlobalConfig.xLog!=0 );
+- sqlite3_log(SQLITE_NOMEM,
+- "failed memory resize %u to %u bytes",
+- SQLITE_MALLOCSIZE(pPrior), nByte);
+- }
+- return p;
+-#else
+- sqlite3_int64 *p = (sqlite3_int64*)pPrior;
+- assert( pPrior!=0 && nByte>0 );
+- assert( nByte==ROUND8(nByte) ); /* EV: R-46199-30249 */
+- p--;
+- p = SQLITE_REALLOC(p, nByte+8 );
+- if( p ){
+- p[0] = nByte;
+- p++;
+- }else{
+- testcase( sqlite3GlobalConfig.xLog!=0 );
+- sqlite3_log(SQLITE_NOMEM,
+- "failed memory resize %u to %u bytes",
+- sqlite3MemSize(pPrior), nByte);
+- }
+- return (void*)p;
++#ifndef _VDBEINT_H_
++#define _VDBEINT_H_
++
++/*
++** 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
+-}
+
+ /*
+-** Round up a request size to the next valid allocation size.
++** SQL is translated into a sequence of instructions to be
++** executed by a virtual machine. Each instruction is an instance
++** of the following structure.
+ */
+-static int sqlite3MemRoundup(int n){
+- return ROUND8(n);
+-}
++typedef struct VdbeOp Op;
+
+ /*
+-** Initialize this module.
++** Boolean values
+ */
+-static int sqlite3MemInit(void *NotUsed){
+-#if defined(__APPLE__) && !defined(SQLITE_WITHOUT_ZONEMALLOC)
+- int cpuCount;
+- size_t len;
+- if( _sqliteZone_ ){
+- return SQLITE_OK;
+- }
+- len = sizeof(cpuCount);
+- /* One usually wants to use hw.acctivecpu for MT decisions, but not here */
+- sysctlbyname("hw.ncpu", &cpuCount, &len, NULL, 0);
+- if( cpuCount>1 ){
+- /* defer MT decisions to system malloc */
+- _sqliteZone_ = malloc_default_zone();
+- }else{
+- /* only 1 core, use our own zone to contention over global locks,
+- ** e.g. we have our own dedicated locks */
+- bool success;
+- malloc_zone_t* newzone = malloc_create_zone(4096, 0);
+- malloc_set_zone_name(newzone, "Sqlite_Heap");
+- do{
+- success = OSAtomicCompareAndSwapPtrBarrier(NULL, newzone,
+- (void * volatile *)&_sqliteZone_);
+- }while(!_sqliteZone_);
+- if( !success ){
+- /* somebody registered a zone first */
+- malloc_destroy_zone(newzone);
+- }
+- }
+-#endif
+- UNUSED_PARAMETER(NotUsed);
+- return SQLITE_OK;
+-}
++typedef unsigned char Bool;
+
+-/*
+-** Deinitialize this module.
+-*/
+-static void sqlite3MemShutdown(void *NotUsed){
+- UNUSED_PARAMETER(NotUsed);
+- return;
+-}
++/* Opaque type used by code in vdbesort.c */
++typedef struct VdbeSorter VdbeSorter;
++
++/* Opaque type used by the explainer */
++typedef struct Explain Explain;
+
+ /*
+-** This routine is the only routine in this file with external linkage.
+-**
+-** Populate the low-level memory allocation function pointers in
+-** sqlite3GlobalConfig.m with pointers to the routines in this file.
++** 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.
++**
++** Every cursor that the virtual machine has open is represented by an
++** instance of the following structure.
+ */
+-SQLITE_PRIVATE void sqlite3MemSetDefault(void){
+- static const sqlite3_mem_methods defaultMethods = {
+- sqlite3MemMalloc,
+- sqlite3MemFree,
+- sqlite3MemRealloc,
+- sqlite3MemSize,
+- sqlite3MemRoundup,
+- sqlite3MemInit,
+- sqlite3MemShutdown,
+- 0
+- };
+- sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods);
+-}
++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 iDb; /* Index of cursor database in db->aDb[] (or -1) */
++ int pseudoTableReg; /* Register holding pseudotable content. */
++ int nField; /* Number of fields in the header */
++ Bool zeroed; /* True if zeroed out and ready for reuse */
++ Bool rowidIsValid; /* True if lastRowid is valid */
++ Bool atFirst; /* True if pointing to first entry */
++ Bool useRandomRowid; /* Generate new record numbers semi-randomly */
++ Bool nullRow; /* True if pointing to a row with no data */
++ Bool deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
++ Bool isTable; /* True if a table requiring integer keys */
++ Bool isIndex; /* True if an index containing keys only - no data */
++ Bool isOrdered; /* True if the underlying table is BTREE_UNORDERED */
++ Bool isSorter; /* True if a new-style sorter */
++ Bool multiPseudo; /* Multi-register pseudo-cursor */
++ sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */
++ const sqlite3_module *pModule; /* Module for cursor pVtabCursor */
++ i64 seqCount; /* Sequence counter */
++ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
++ i64 lastRowid; /* Last rowid from a Next or NextIdx operation */
++ VdbeSorter *pSorter; /* Sorter object for OP_SorterOpen cursors */
+
+-#endif /* SQLITE_SYSTEM_MALLOC */
++ /* Result of last sqlite3BtreeMoveto() done by an OP_NotExists or
++ ** OP_IsUnique opcode on this cursor. */
++ int seekResult;
++
++ /* 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 */
++ int payloadSize; /* Total number of bytes in the record */
++ u32 *aType; /* Type values for all entries in the record */
++ u32 *aOffset; /* Cached offsets to the start of each columns data */
++ u8 *aRow; /* Data for the current row, if all on one page */
++};
++typedef struct VdbeCursor VdbeCursor;
+
+-/************** End of mem1.c ************************************************/
+-/************** Begin file mem2.c ********************************************/
+ /*
+-** 2007 August 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.
+-**
+-*************************************************************************
++** 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.
+ **
+-** This file contains low-level memory allocation drivers for when
+-** SQLite will use the standard C-library malloc/realloc/free interface
+-** to obtain the memory it needs while adding lots of additional debugging
+-** information to each allocation in order to help detect and fix memory
+-** leaks and memory usage errors.
++** 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.
+ **
+-** This file contains implementations of the low-level memory allocation
+-** routines specified in the sqlite3_mem_methods object.
++** 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 */
++ 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.nChanges) */
++};
++
++#define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))])
+
+ /*
+-** This version of the memory allocator is used only if the
+-** SQLITE_MEMDEBUG macro is defined
++** A value for VdbeCursor.cacheValid that means the cache is always invalid.
+ */
+-#ifdef SQLITE_MEMDEBUG
++#define CACHE_STALE 0
+
+ /*
+-** The backtrace functionality is only available with GLIBC
++** 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.
+ */
+-#ifdef __GLIBC__
+- extern int backtrace(void**,int);
+- extern void backtrace_symbols_fd(void*const*,int,int);
+-#else
+-# define backtrace(A,B) 1
+-# define backtrace_symbols_fd(A,B,C)
++struct Mem {
++ sqlite3 *db; /* The associated database connection */
++ char *z; /* String or BLOB value */
++ double r; /* Real value */
++ union {
++ 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 type; /* One of SQLITE_NULL, SQLITE_TEXT, SQLITE_INTEGER, etc */
++ u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */
++#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
+-/* #include <stdio.h> */
++ void (*xDel)(void *); /* If not null, call this function to delete Mem.z */
++ char *zMalloc; /* Dynamic buffer allocated by sqlite3_malloc() */
++};
+
+-/*
+-** Each memory allocation looks like this:
++/* One or more of the following flags are set to indicate the validOK
++** representations of the value stored in the Mem struct.
+ **
+-** ------------------------------------------------------------------------
+-** | Title | backtrace pointers | MemBlockHdr | allocation | EndGuard |
+-** ------------------------------------------------------------------------
++** If the MEM_Null flag is set, then the value is an SQL NULL value.
++** No other flags may be set in this case.
+ **
+-** The application code sees only a pointer to the allocation. We have
+-** to back up from the allocation pointer to find the MemBlockHdr. The
+-** MemBlockHdr tells us the size of the allocation and the number of
+-** backtrace pointers. There is also a guard word at the end of the
+-** MemBlockHdr.
++** 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.
+ */
+-struct MemBlockHdr {
+- i64 iSize; /* Size of this allocation */
+- struct MemBlockHdr *pNext, *pPrev; /* Linked list of all unfreed memory */
+- char nBacktrace; /* Number of backtraces on this alloc */
+- char nBacktraceSlots; /* Available backtrace slots */
+- u8 nTitle; /* Bytes of title; includes '\0' */
+- u8 eType; /* Allocation type code */
+- int iForeGuard; /* Guard word for sanity */
+-};
++#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_RowSet 0x0020 /* Value is a RowSet object */
++#define MEM_Frame 0x0040 /* Value is a VdbeFrame object */
++#define MEM_Invalid 0x0080 /* Value is undefined */
++#define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */
++#define MEM_TypeMask 0x01ff /* Mask of type bits */
+
+-/*
+-** Guard words
++
++/* 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 FOREGUARD 0x80F5E153
+-#define REARGUARD 0xE4676B53
++#define MEM_Term 0x0200 /* String rep is nul terminated */
++#define MEM_Dyn 0x0400 /* Need to call sqliteFree() 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
+
+ /*
+-** Number of malloc size increments to track.
++** Clear any existing type flags from a Mem and replace them with f
+ */
+-#define NCSIZE 1000
++#define MemSetTypeFlag(p, f) \
++ ((p)->flags = ((p)->flags&~(MEM_TypeMask|MEM_Zero))|f)
+
+ /*
+-** All of the static variables used by this module are collected
+-** into a single structure named "mem". This is to keep the
+-** static variables organized and to reduce namespace pollution
+-** when this module is combined with other in the amalgamation.
++** Return true if a memory cell is not marked as invalid. This macro
++** is for use inside assert() statements only.
+ */
+-static struct {
+-
+- /*
+- ** Mutex to control access to the memory allocation subsystem.
+- */
+- sqlite3_mutex *mutex;
+-
+- /*
+- ** Head and tail of a linked list of all outstanding allocations
+- */
+- struct MemBlockHdr *pFirst;
+- struct MemBlockHdr *pLast;
+-
+- /*
+- ** The number of levels of backtrace to save in new allocations.
+- */
+- int nBacktrace;
+- void (*xBacktrace)(int, int, void **);
+-
+- /*
+- ** Title text to insert in front of each block
+- */
+- int nTitle; /* Bytes of zTitle to save. Includes '\0' and padding */
+- char zTitle[100]; /* The title text */
+-
+- /*
+- ** sqlite3MallocDisallow() increments the following counter.
+- ** sqlite3MallocAllow() decrements it.
+- */
+- int disallow; /* Do not allow memory allocation */
+-
+- /*
+- ** Gather statistics on the sizes of memory allocations.
+- ** nAlloc[i] is the number of allocation attempts of i*8
+- ** bytes. i==NCSIZE is the number of allocation attempts for
+- ** sizes more than NCSIZE*8 bytes.
+- */
+- int nAlloc[NCSIZE]; /* Total number of allocations */
+- int nCurrent[NCSIZE]; /* Current number of allocations */
+- int mxCurrent[NCSIZE]; /* Highwater mark for nCurrent */
+-
+-} mem;
++#ifdef SQLITE_DEBUG
++#define memIsValid(M) ((M)->flags & MEM_Invalid)==0
++#endif
+
+
+-/*
+-** Adjust memory usage statistics
++/* A VdbeFunc is just a FuncDef (defined in sqliteInt.h) that contains
++** additional information about auxiliary information bound to arguments
++** of the function. This is used to implement the sqlite3_get_auxdata()
++** and sqlite3_set_auxdata() APIs. The "auxdata" is some auxiliary data
++** that can be associated with a constant argument to a function. This
++** allows functions such as "regexp" to compile their constant regular
++** expression argument once and reused the compiled code for multiple
++** invocations.
+ */
+-static void adjustStats(int iSize, int increment){
+- int i = ROUND8(iSize)/8;
+- if( i>NCSIZE-1 ){
+- i = NCSIZE - 1;
+- }
+- if( increment>0 ){
+- mem.nAlloc[i]++;
+- mem.nCurrent[i]++;
+- if( mem.nCurrent[i]>mem.mxCurrent[i] ){
+- mem.mxCurrent[i] = mem.nCurrent[i];
+- }
+- }else{
+- mem.nCurrent[i]--;
+- assert( mem.nCurrent[i]>=0 );
+- }
+-}
++struct VdbeFunc {
++ FuncDef *pFunc; /* The definition of the function */
++ int nAux; /* Number of entries allocated for apAux[] */
++ struct AuxData {
++ void *pAux; /* Aux data for the i-th argument */
++ void (*xDelete)(void *); /* Destructor for the aux data */
++ } apAux[1]; /* One slot for each function argument */
++};
+
+ /*
+-** Given an allocation, find the MemBlockHdr for that allocation.
++** The "context" argument for a installable function. A pointer to an
++** instance of this structure is the first argument to the routines used
++** implement the SQL functions.
+ **
+-** This routine checks the guards at either end of the allocation and
+-** if they are incorrect it asserts.
++** 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.
+ */
+-static struct MemBlockHdr *sqlite3MemsysGetHeader(void *pAllocation){
+- struct MemBlockHdr *p;
+- int *pInt;
+- u8 *pU8;
+- int nReserve;
+-
+- p = (struct MemBlockHdr*)pAllocation;
+- p--;
+- assert( p->iForeGuard==(int)FOREGUARD );
+- nReserve = ROUND8(p->iSize);
+- pInt = (int*)pAllocation;
+- pU8 = (u8*)pAllocation;
+- assert( pInt[nReserve/sizeof(int)]==(int)REARGUARD );
+- /* This checks any of the "extra" bytes allocated due
+- ** to rounding up to an 8 byte boundary to ensure
+- ** they haven't been overwritten.
+- */
+- while( nReserve-- > p->iSize ) assert( pU8[nReserve]==0x65 );
+- return p;
+-}
++struct sqlite3_context {
++ FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */
++ VdbeFunc *pVdbeFunc; /* Auxilary data, if created. */
++ Mem s; /* The return value is stored here */
++ Mem *pMem; /* Memory cell used to store aggregate context */
++ CollSeq *pColl; /* Collating sequence */
++ int isError; /* Error code returned by the function. */
++ int skipFlag; /* Skip skip accumulator loading if true */
++};
+
+ /*
+-** Return the number of bytes currently allocated at address p.
++** An Explain object accumulates indented output which is helpful
++** in describing recursive data structures.
+ */
+-static int sqlite3MemSize(void *p){
+- struct MemBlockHdr *pHdr;
+- if( !p ){
+- return 0;
+- }
+- pHdr = sqlite3MemsysGetHeader(p);
+- return pHdr->iSize;
+-}
++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 */
++};
+
+-/*
+-** Initialize the memory allocation subsystem.
++/* A bitfield type for use inside of structures. Always follow with :N where
++** N is the number of bits.
+ */
+-static int sqlite3MemInit(void *NotUsed){
+- UNUSED_PARAMETER(NotUsed);
+- assert( (sizeof(struct MemBlockHdr)&7) == 0 );
+- if( !sqlite3GlobalConfig.bMemstat ){
+- /* If memory status is enabled, then the malloc.c wrapper will already
+- ** hold the STATIC_MEM mutex when the routines here are invoked. */
+- mem.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
+- }
+- return SQLITE_OK;
+-}
++typedef unsigned bft; /* Bit Field Type */
+
+ /*
+-** Deinitialize the memory allocation subsystem.
++** 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.
+ */
+-static void sqlite3MemShutdown(void *NotUsed){
+- UNUSED_PARAMETER(NotUsed);
+- mem.mutex = 0;
+-}
++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 */
++ int nMem; /* Number of memory locations currently allocated */
++ int nOp; /* Number of instructions in the program */
++ int nOpAlloc; /* Number of slots allocated for aOp[] */
++ int nLabel; /* Number of labels used */
++ int *aLabel; /* Space to hold the labels */
++ u16 nResColumn; /* Number of columns in one row of the result set */
++ 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 */
++ 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 */
++ bft usesStmtJournal:1; /* True if uses a statement journal */
++ bft readOnly:1; /* True for read-only statements */
++ 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) */
++ int aCounter[3]; /* Counters used by sqlite3_stmt_status() */
++#ifndef SQLITE_OMIT_TRACE
++ i64 startTime; /* Time when query started - used for profiling */
++#endif
++ i64 nFkConstraint; /* Number of imm. FK constraints this VM */
++ i64 nStmtDefCons; /* Number of def. constraints when stmt started */
++ char *zSql; /* Text of the SQL statement that generated this */
++ void *pFree; /* Free this when deleting the vdbe */
++#ifdef SQLITE_DEBUG
++ FILE *trace; /* Write an execution trace here, if not NULL */
++#endif
++#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 */
++ 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 */
++};
+
+ /*
+-** Round up a request size to the next valid allocation size.
++** The following are allowed values for Vdbe.magic
+ */
+-static int sqlite3MemRoundup(int n){
+- return ROUND8(n);
+-}
++#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 */
+
+ /*
+-** Fill a buffer with pseudo-random bytes. This is used to preset
+-** the content of a new memory allocation to unpredictable values and
+-** to clear the content of a freed allocation to unpredictable values.
++** Function prototypes
+ */
+-static void randomFill(char *pBuf, int nByte){
+- unsigned int x, y, r;
+- x = SQLITE_PTR_TO_INT(pBuf);
+- y = nByte | 1;
+- while( nByte >= 4 ){
+- x = (x>>1) ^ (-(x&1) & 0xd0000001);
+- y = y*1103515245 + 12345;
+- r = x ^ y;
+- *(int*)pBuf = r;
+- pBuf += 4;
+- nByte -= 4;
+- }
+- while( nByte-- > 0 ){
+- x = (x>>1) ^ (-(x&1) & 0xd0000001);
+- y = y*1103515245 + 12345;
+- r = x ^ y;
+- *(pBuf++) = r & 0xff;
+- }
+-}
++SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*);
++void sqliteVdbePopStack(Vdbe*,int);
++SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(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*, int, Mem*, int);
++SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
++SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(VdbeFunc*, int);
+
+-/*
+-** Allocate nByte bytes of memory.
+-*/
+-static void *sqlite3MemMalloc(int nByte){
+- struct MemBlockHdr *pHdr;
+- void **pBt;
+- char *z;
+- int *pInt;
+- void *p = 0;
+- int totalSize;
+- int nReserve;
+- sqlite3_mutex_enter(mem.mutex);
+- assert( mem.disallow==0 );
+- nReserve = ROUND8(nByte);
+- totalSize = nReserve + sizeof(*pHdr) + sizeof(int) +
+- mem.nBacktrace*sizeof(void*) + mem.nTitle;
+- p = malloc(totalSize);
+- if( p ){
+- z = p;
+- pBt = (void**)&z[mem.nTitle];
+- pHdr = (struct MemBlockHdr*)&pBt[mem.nBacktrace];
+- pHdr->pNext = 0;
+- pHdr->pPrev = mem.pLast;
+- if( mem.pLast ){
+- mem.pLast->pNext = pHdr;
+- }else{
+- mem.pFirst = pHdr;
+- }
+- mem.pLast = pHdr;
+- pHdr->iForeGuard = FOREGUARD;
+- pHdr->eType = MEMTYPE_HEAP;
+- pHdr->nBacktraceSlots = mem.nBacktrace;
+- pHdr->nTitle = mem.nTitle;
+- if( mem.nBacktrace ){
+- void *aAddr[40];
+- pHdr->nBacktrace = backtrace(aAddr, mem.nBacktrace+1)-1;
+- memcpy(pBt, &aAddr[1], pHdr->nBacktrace*sizeof(void*));
+- assert(pBt[0]);
+- if( mem.xBacktrace ){
+- mem.xBacktrace(nByte, pHdr->nBacktrace-1, &aAddr[1]);
+- }
+- }else{
+- pHdr->nBacktrace = 0;
+- }
+- if( mem.nTitle ){
+- memcpy(z, mem.zTitle, mem.nTitle);
+- }
+- pHdr->iSize = nByte;
+- adjustStats(nByte, +1);
+- pInt = (int*)&pHdr[1];
+- pInt[nReserve/sizeof(int)] = REARGUARD;
+- randomFill((char*)pInt, nByte);
+- memset(((char*)pInt)+nByte, 0x65, nReserve-nByte);
+- p = (void*)pInt;
+- }
+- sqlite3_mutex_leave(mem.mutex);
+- return p;
+-}
++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 sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
++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 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 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 int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*);
++SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p);
++SQLITE_PRIVATE void sqlite3VdbeMemReleaseExternal(Mem *p);
++#define VdbeMemRelease(X) \
++ if((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame)) \
++ 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 sqlite3VdbeCloseStatement(Vdbe *, int);
++SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*);
++SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *);
++SQLITE_PRIVATE void sqlite3VdbeMemStoreType(Mem *pMem);
++SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p);
++
++SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *, VdbeCursor *);
++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 sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, 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*);
++#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 *********************/
+
+ /*
+-** Free memory.
++** Variables in which to record status information.
+ */
+-static void sqlite3MemFree(void *pPrior){
+- struct MemBlockHdr *pHdr;
+- void **pBt;
+- char *z;
+- assert( sqlite3GlobalConfig.bMemstat || sqlite3GlobalConfig.bCoreMutex==0
+- || mem.mutex!=0 );
+- pHdr = sqlite3MemsysGetHeader(pPrior);
+- pBt = (void**)pHdr;
+- pBt -= pHdr->nBacktraceSlots;
+- sqlite3_mutex_enter(mem.mutex);
+- if( pHdr->pPrev ){
+- assert( pHdr->pPrev->pNext==pHdr );
+- pHdr->pPrev->pNext = pHdr->pNext;
+- }else{
+- assert( mem.pFirst==pHdr );
+- mem.pFirst = pHdr->pNext;
+- }
+- if( pHdr->pNext ){
+- assert( pHdr->pNext->pPrev==pHdr );
+- pHdr->pNext->pPrev = pHdr->pPrev;
+- }else{
+- assert( mem.pLast==pHdr );
+- mem.pLast = pHdr->pPrev;
+- }
+- z = (char*)pBt;
+- z -= pHdr->nTitle;
+- adjustStats(pHdr->iSize, -1);
+- randomFill(z, sizeof(void*)*pHdr->nBacktraceSlots + sizeof(*pHdr) +
+- pHdr->iSize + sizeof(int) + pHdr->nTitle);
+- free(z);
+- sqlite3_mutex_leave(mem.mutex);
+-}
++typedef struct sqlite3StatType sqlite3StatType;
++static SQLITE_WSD struct sqlite3StatType {
++ int nowValue[10]; /* Current value */
++ int mxValue[10]; /* Maximum value */
++} sqlite3Stat = { {0,}, {0,} };
+
+-/*
+-** Change the size of an existing memory allocation.
+-**
+-** For this debugging implementation, we *always* make a copy of the
+-** allocation into a new place in memory. In this way, if the
+-** higher level code is using pointer to the old allocation, it is
+-** much more likely to break and we are much more liking to find
+-** the error.
++
++/* 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.
+ */
+-static void *sqlite3MemRealloc(void *pPrior, int nByte){
+- struct MemBlockHdr *pOldHdr;
+- void *pNew;
+- assert( mem.disallow==0 );
+- assert( (nByte & 7)==0 ); /* EV: R-46199-30249 */
+- pOldHdr = sqlite3MemsysGetHeader(pPrior);
+- pNew = sqlite3MemMalloc(nByte);
+- if( pNew ){
+- memcpy(pNew, pPrior, nByte<pOldHdr->iSize ? nByte : pOldHdr->iSize);
+- if( nByte>pOldHdr->iSize ){
+- randomFill(&((char*)pNew)[pOldHdr->iSize], nByte - pOldHdr->iSize);
+- }
+- sqlite3MemFree(pPrior);
+- }
+- return pNew;
+-}
++#ifdef SQLITE_OMIT_WSD
++# define wsdStatInit sqlite3StatType *x = &GLOBAL(sqlite3StatType,sqlite3Stat)
++# define wsdStat x[0]
++#else
++# define wsdStatInit
++# define wsdStat sqlite3Stat
++#endif
+
+ /*
+-** Populate the low-level memory allocation function pointers in
+-** sqlite3GlobalConfig.m with pointers to the routines in this file.
++** Return the current value of a status parameter.
+ */
+-SQLITE_PRIVATE void sqlite3MemSetDefault(void){
+- static const sqlite3_mem_methods defaultMethods = {
+- sqlite3MemMalloc,
+- sqlite3MemFree,
+- sqlite3MemRealloc,
+- sqlite3MemSize,
+- sqlite3MemRoundup,
+- sqlite3MemInit,
+- sqlite3MemShutdown,
+- 0
+- };
+- sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods);
++SQLITE_PRIVATE int sqlite3StatusValue(int op){
++ wsdStatInit;
++ assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
++ return wsdStat.nowValue[op];
+ }
+
+ /*
+-** Set the "type" of an allocation.
++** Add N to the value of a status record. It is assumed that the
++** caller holds appropriate locks.
+ */
+-SQLITE_PRIVATE void sqlite3MemdebugSetType(void *p, u8 eType){
+- if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){
+- struct MemBlockHdr *pHdr;
+- pHdr = sqlite3MemsysGetHeader(p);
+- assert( pHdr->iForeGuard==FOREGUARD );
+- pHdr->eType = eType;
++SQLITE_PRIVATE void sqlite3StatusAdd(int op, int N){
++ wsdStatInit;
++ assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
++ wsdStat.nowValue[op] += N;
++ if( wsdStat.nowValue[op]>wsdStat.mxValue[op] ){
++ wsdStat.mxValue[op] = wsdStat.nowValue[op];
+ }
+ }
+
+ /*
+-** Return TRUE if the mask of type in eType matches the type of the
+-** allocation p. Also return true if p==NULL.
+-**
+-** This routine is designed for use within an assert() statement, to
+-** verify the type of an allocation. For example:
+-**
+-** assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) );
++** Set the value of a status to X.
+ */
+-SQLITE_PRIVATE int sqlite3MemdebugHasType(void *p, u8 eType){
+- int rc = 1;
+- if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){
+- struct MemBlockHdr *pHdr;
+- pHdr = sqlite3MemsysGetHeader(p);
+- assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */
+- if( (pHdr->eType&eType)==0 ){
+- rc = 0;
+- }
++SQLITE_PRIVATE void sqlite3StatusSet(int op, int X){
++ wsdStatInit;
++ assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
++ wsdStat.nowValue[op] = X;
++ if( wsdStat.nowValue[op]>wsdStat.mxValue[op] ){
++ wsdStat.mxValue[op] = wsdStat.nowValue[op];
+ }
+- return rc;
+ }
+
+ /*
+-** Return TRUE if the mask of type in eType matches no bits of the type of the
+-** allocation p. Also return true if p==NULL.
+-**
+-** This routine is designed for use within an assert() statement, to
+-** verify the type of an allocation. For example:
++** Query status information.
+ **
+-** assert( sqlite3MemdebugNoType(p, MEMTYPE_DB) );
++** 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_PRIVATE int sqlite3MemdebugNoType(void *p, u8 eType){
+- int rc = 1;
+- if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){
+- struct MemBlockHdr *pHdr;
+- pHdr = sqlite3MemsysGetHeader(p);
+- assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */
+- if( (pHdr->eType&eType)!=0 ){
+- rc = 0;
+- }
++SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){
++ wsdStatInit;
++ if( op<0 || op>=ArraySize(wsdStat.nowValue) ){
++ return SQLITE_MISUSE_BKPT;
+ }
+- return rc;
+-}
+-
+-/*
+-** Set the number of backtrace levels kept for each allocation.
+-** A value of zero turns off backtracing. The number is always rounded
+-** up to a multiple of 2.
+-*/
+-SQLITE_PRIVATE void sqlite3MemdebugBacktrace(int depth){
+- if( depth<0 ){ depth = 0; }
+- if( depth>20 ){ depth = 20; }
+- depth = (depth+1)&0xfe;
+- mem.nBacktrace = depth;
+-}
+-
+-SQLITE_PRIVATE void sqlite3MemdebugBacktraceCallback(void (*xBacktrace)(int, int, void **)){
+- mem.xBacktrace = xBacktrace;
+-}
+-
+-/*
+-** Set the title string for subsequent allocations.
+-*/
+-SQLITE_PRIVATE void sqlite3MemdebugSettitle(const char *zTitle){
+- unsigned int n = sqlite3Strlen30(zTitle) + 1;
+- sqlite3_mutex_enter(mem.mutex);
+- if( n>=sizeof(mem.zTitle) ) n = sizeof(mem.zTitle)-1;
+- memcpy(mem.zTitle, zTitle, n);
+- mem.zTitle[n] = 0;
+- mem.nTitle = ROUND8(n);
+- sqlite3_mutex_leave(mem.mutex);
+-}
+-
+-SQLITE_PRIVATE void sqlite3MemdebugSync(){
+- struct MemBlockHdr *pHdr;
+- for(pHdr=mem.pFirst; pHdr; pHdr=pHdr->pNext){
+- void **pBt = (void**)pHdr;
+- pBt -= pHdr->nBacktraceSlots;
+- mem.xBacktrace(pHdr->iSize, pHdr->nBacktrace-1, &pBt[1]);
++ *pCurrent = wsdStat.nowValue[op];
++ *pHighwater = wsdStat.mxValue[op];
++ if( resetFlag ){
++ wsdStat.mxValue[op] = wsdStat.nowValue[op];
+ }
++ return SQLITE_OK;
+ }
+
+ /*
+-** Open the file indicated and write a log of all unfreed memory
+-** allocations into that log.
++** Query status information for a single database connection
+ */
+-SQLITE_PRIVATE void sqlite3MemdebugDump(const char *zFilename){
+- FILE *out;
+- struct MemBlockHdr *pHdr;
+- void **pBt;
+- int i;
+- out = fopen(zFilename, "w");
+- if( out==0 ){
+- fprintf(stderr, "** Unable to output memory debug output log: %s **\n",
+- zFilename);
+- return;
+- }
+- for(pHdr=mem.pFirst; pHdr; pHdr=pHdr->pNext){
+- char *z = (char*)pHdr;
+- z -= pHdr->nBacktraceSlots*sizeof(void*) + pHdr->nTitle;
+- fprintf(out, "**** %lld bytes at %p from %s ****\n",
+- pHdr->iSize, &pHdr[1], pHdr->nTitle ? z : "???");
+- if( pHdr->nBacktrace ){
+- fflush(out);
+- pBt = (void**)pHdr;
+- pBt -= pHdr->nBacktraceSlots;
+- backtrace_symbols_fd(pBt, pHdr->nBacktrace, fileno(out));
+- fprintf(out, "\n");
++SQLITE_API int 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 */
++ 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;
+ }
+- }
+- fprintf(out, "COUNTS:\n");
+- for(i=0; i<NCSIZE-1; i++){
+- if( mem.nAlloc[i] ){
+- fprintf(out, " %5d: %10d %10d %10d\n",
+- i*8, mem.nAlloc[i], mem.nCurrent[i], mem.mxCurrent[i]);
++
++ 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;
+ }
+- }
+- if( mem.nAlloc[NCSIZE-1] ){
+- fprintf(out, " %5d: %10d %10d %10d\n",
+- NCSIZE*8-8, mem.nAlloc[NCSIZE-1],
+- mem.nCurrent[NCSIZE-1], mem.mxCurrent[NCSIZE-1]);
+- }
+- fclose(out);
+-}
+
+-/*
+-** Return the number of times sqlite3MemMalloc() has been called.
+-*/
+-SQLITE_PRIVATE int sqlite3MemdebugMallocCount(){
+- int i;
+- int nTotal = 0;
+- for(i=0; i<NCSIZE; i++){
+- nTotal += mem.nAlloc[i];
+- }
+- return nTotal;
+-}
++ /*
++ ** 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 */
+
+-#endif /* SQLITE_MEMDEBUG */
++ sqlite3BtreeEnterAll(db);
++ db->pnBytesFreed = &nByte;
++ for(i=0; i<db->nDb; i++){
++ Schema *pSchema = db->aDb[i].pSchema;
++ if( ALWAYS(pSchema!=0) ){
++ HashElem *p;
+
+-/************** End of mem2.c ************************************************/
+-/************** Begin file mem3.c ********************************************/
++ 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;
++ *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;
++ *pCurrent = nRet;
++ break;
++ }
++
++ default: {
++ rc = SQLITE_ERROR;
++ }
++ }
++ sqlite3_mutex_leave(db->mutex);
++ return rc;
++}
++
++/************** End of status.c **********************************************/
++/************** Begin file date.c ********************************************/
+ /*
+-** 2007 October 14
++** 2003 October 31
+ **
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
+@@ -16443,1269 +16943,1505 @@
+ ** May you share freely, never taking more than you give.
**
-@@ -22677,7 +24991,7 @@
- #include <sys/time.h>
- #include <errno.h>
- #ifndef SQLITE_OMIT_WAL
+ *************************************************************************
+-** This file contains the C functions that implement a memory
+-** allocation subsystem for use by SQLite.
++** This file contains the C functions that implement date and time
++** functions for SQLite.
+ **
+-** This version of the memory allocation subsystem omits all
+-** use of malloc(). The SQLite user supplies a block of memory
+-** before calling sqlite3_initialize() from which allocations
+-** are made and returned by the xMalloc() and xRealloc()
+-** implementations. Once sqlite3_initialize() has been called,
+-** the amount of memory available to SQLite is fixed and cannot
+-** be changed.
++** 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.
+ **
+-** This version of the memory allocation subsystem is included
+-** in the build only if SQLITE_ENABLE_MEMSYS3 is defined.
++** 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 implemention 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
+
+-/*
+-** This version of the memory allocator is only built into the library
+-** SQLITE_ENABLE_MEMSYS3 is defined. Defining this symbol does not
+-** mean that the library will use a memory-pool by default, just that
+-** it is available. The mempool allocator is activated by calling
+-** sqlite3_config().
+-*/
+-#ifdef SQLITE_ENABLE_MEMSYS3
+
+ /*
+-** Maximum size (in Mem3Blocks) of a "small" chunk.
++** A structure for holding a single date and time.
+ */
+-#define MX_SMALL 10
++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 */
++};
+
+
+ /*
+-** Number of freelist hash slots
++** 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.
+ */
+-#define N_HASH 61
++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;
++}
+
+ /*
+-** A memory allocation (also called a "chunk") consists of two or
+-** more blocks where each block is 8 bytes. The first 8 bytes are
+-** a header that is not returned to the user.
++** Parse a timezone extension on the end of a date-time.
++** The extension is of the form:
+ **
+-** A chunk is two or more blocks that is either checked out or
+-** free. The first block has format u.hdr. u.hdr.size4x is 4 times the
+-** size of the allocation in blocks if the allocation is free.
+-** The u.hdr.size4x&1 bit is true if the chunk is checked out and
+-** false if the chunk is on the freelist. The u.hdr.size4x&2 bit
+-** is true if the previous chunk is checked out and false if the
+-** previous chunk is free. The u.hdr.prevSize field is the size of
+-** the previous chunk in blocks if the previous chunk is on the
+-** freelist. If the previous chunk is checked out, then
+-** u.hdr.prevSize can be part of the data for that chunk and should
+-** not be read or written.
++** (+/-)HH:MM
+ **
+-** We often identify a chunk by its index in mem3.aPool[]. When
+-** this is done, the chunk index refers to the second block of
+-** the chunk. In this way, the first chunk has an index of 1.
+-** A chunk index of 0 means "no such chunk" and is the equivalent
+-** of a NULL pointer.
++** Or the "zulu" notation:
+ **
+-** The second block of free chunks is of the form u.list. The
+-** two fields form a double-linked list of chunks of related sizes.
+-** Pointers to the head of the list are stored in mem3.aiSmall[]
+-** for smaller chunks and mem3.aiHash[] for larger chunks.
++** Z
+ **
+-** The second block of a chunk is user data if the chunk is checked
+-** out. If a chunk is checked out, the user data may extend into
+-** the u.hdr.prevSize value of the following chunk.
+-*/
+-typedef struct Mem3Block Mem3Block;
+-struct Mem3Block {
+- union {
+- struct {
+- u32 prevSize; /* Size of previous chunk in Mem3Block elements */
+- u32 size4x; /* 4x the size of current chunk in Mem3Block elements */
+- } hdr;
+- struct {
+- u32 next; /* Index in mem3.aPool[] of next free chunk */
+- u32 prev; /* Index in mem3.aPool[] of previous free chunk */
+- } list;
+- } u;
+-};
+-
+-/*
+-** All of the static variables used by this module are collected
+-** into a single structure named "mem3". This is to keep the
+-** static variables organized and to reduce namespace pollution
+-** when this module is combined with other in the amalgamation.
+-*/
+-static SQLITE_WSD struct Mem3Global {
+- /*
+- ** Memory available for allocation. nPool is the size of the array
+- ** (in Mem3Blocks) pointed to by aPool less 2.
+- */
+- u32 nPool;
+- Mem3Block *aPool;
+-
+- /*
+- ** True if we are evaluating an out-of-memory callback.
+- */
+- int alarmBusy;
+-
+- /*
+- ** Mutex to control access to the memory allocation subsystem.
+- */
+- sqlite3_mutex *mutex;
+-
+- /*
+- ** The minimum amount of free space that we have seen.
+- */
+- u32 mnMaster;
+-
+- /*
+- ** iMaster is the index of the master chunk. Most new allocations
+- ** occur off of this chunk. szMaster is the size (in Mem3Blocks)
+- ** of the current master. iMaster is 0 if there is not master chunk.
+- ** The master chunk is not in either the aiHash[] or aiSmall[].
+- */
+- u32 iMaster;
+- u32 szMaster;
+-
+- /*
+- ** Array of lists of free blocks according to the block size
+- ** for smaller chunks, or a hash on the block size for larger
+- ** chunks.
+- */
+- u32 aiSmall[MX_SMALL-1]; /* For sizes 2 through MX_SMALL, inclusive */
+- u32 aiHash[N_HASH]; /* For sizes MX_SMALL+1 and larger */
+-} mem3 = { 97535575 };
+-
+-#define mem3 GLOBAL(struct Mem3Global, mem3)
+-
+-/*
+-** Unlink the chunk at mem3.aPool[i] from list it is currently
+-** on. *pRoot is the list that i is a member of.
++** 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 void memsys3UnlinkFromList(u32 i, u32 *pRoot){
+- u32 next = mem3.aPool[i].u.list.next;
+- u32 prev = mem3.aPool[i].u.list.prev;
+- assert( sqlite3_mutex_held(mem3.mutex) );
+- if( prev==0 ){
+- *pRoot = next;
++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{
+- mem3.aPool[prev].u.list.next = next;
++ return c!=0;
+ }
+- if( next ){
+- mem3.aPool[next].u.list.prev = prev;
++ zDate++;
++ if( getDigits(zDate, 2, 0, 14, ':', &nHr, 2, 0, 59, 0, &nMn)!=2 ){
++ return 1;
+ }
+- mem3.aPool[i].u.list.next = 0;
+- mem3.aPool[i].u.list.prev = 0;
++ zDate += 5;
++ p->tz = sgn*(nMn + nHr*60);
++zulu_time:
++ while( sqlite3Isspace(*zDate) ){ zDate++; }
++ return *zDate!=0;
+ }
+
+ /*
+-** Unlink the chunk at index i from
+-** whatever list is currently a member of.
++** 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 void memsys3Unlink(u32 i){
+- u32 size, hash;
+- assert( sqlite3_mutex_held(mem3.mutex) );
+- assert( (mem3.aPool[i-1].u.hdr.size4x & 1)==0 );
+- assert( i>=1 );
+- size = mem3.aPool[i-1].u.hdr.size4x/4;
+- assert( size==mem3.aPool[i+size-1].u.hdr.prevSize );
+- assert( size>=2 );
+- if( size <= MX_SMALL ){
+- memsys3UnlinkFromList(i, &mem3.aiSmall[size-2]);
++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{
+- hash = size % N_HASH;
+- memsys3UnlinkFromList(i, &mem3.aiHash[hash]);
++ 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;
+ }
+
+ /*
+-** Link the chunk at mem3.aPool[i] so that is on the list rooted
+-** at *pRoot.
++** 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 memsys3LinkIntoList(u32 i, u32 *pRoot){
+- assert( sqlite3_mutex_held(mem3.mutex) );
+- mem3.aPool[i].u.list.next = *pRoot;
+- mem3.aPool[i].u.list.prev = 0;
+- if( *pRoot ){
+- mem3.aPool[*pRoot].u.list.prev = i;
++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;
++ }
+ }
+- *pRoot = i;
+ }
+
+ /*
+-** Link the chunk at index i into either the appropriate
+-** small chunk list, or into the large chunk hash table.
++** 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 void memsys3Link(u32 i){
+- u32 size, hash;
+- assert( sqlite3_mutex_held(mem3.mutex) );
+- assert( i>=1 );
+- assert( (mem3.aPool[i-1].u.hdr.size4x & 1)==0 );
+- size = mem3.aPool[i-1].u.hdr.size4x/4;
+- assert( size==mem3.aPool[i+size-1].u.hdr.prevSize );
+- assert( size>=2 );
+- if( size <= MX_SMALL ){
+- memsys3LinkIntoList(i, &mem3.aiSmall[size-2]);
++static int parseYyyyMmDd(const char *zDate, DateTime *p){
++ int Y, M, D, neg;
++
++ if( zDate[0]=='-' ){
++ zDate++;
++ neg = 1;
+ }else{
+- hash = size % N_HASH;
+- memsys3LinkIntoList(i, &mem3.aiHash[hash]);
++ 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;
+ }
+
+ /*
+-** If the STATIC_MEM mutex is not already held, obtain it now. The mutex
+-** will already be held (obtained by code in malloc.c) if
+-** sqlite3GlobalConfig.bMemStat is true.
++** Set the time to the current time reported by the VFS.
++**
++** Return the number of errors.
+ */
+-static void memsys3Enter(void){
+- if( sqlite3GlobalConfig.bMemstat==0 && mem3.mutex==0 ){
+- mem3.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
++static int setDateTimeToCurrent(sqlite3_context *context, DateTime *p){
++ sqlite3 *db = sqlite3_context_db_handle(context);
++ if( sqlite3OsCurrentTimeInt64(db->pVfs, &p->iJD)==SQLITE_OK ){
++ p->validJD = 1;
++ return 0;
++ }else{
++ return 1;
+ }
+- sqlite3_mutex_enter(mem3.mutex);
+-}
+-static void memsys3Leave(void){
+- sqlite3_mutex_leave(mem3.mutex);
+ }
+
+ /*
+-** Called when we are unable to satisfy an allocation of nBytes.
+-*/
+-static void memsys3OutOfMemory(int nByte){
+- if( !mem3.alarmBusy ){
+- mem3.alarmBusy = 1;
+- assert( sqlite3_mutex_held(mem3.mutex) );
+- sqlite3_mutex_leave(mem3.mutex);
+- sqlite3_release_memory(nByte);
+- sqlite3_mutex_enter(mem3.mutex);
+- mem3.alarmBusy = 0;
+- }
+-}
+-
+-
+-/*
+-** Chunk i is a free chunk that has been unlinked. Adjust its
+-** size parameters for check-out and return a pointer to the
+-** user portion of the chunk.
+-*/
+-static void *memsys3Checkout(u32 i, u32 nBlock){
+- u32 x;
+- assert( sqlite3_mutex_held(mem3.mutex) );
+- assert( i>=1 );
+- assert( mem3.aPool[i-1].u.hdr.size4x/4==nBlock );
+- assert( mem3.aPool[i+nBlock-1].u.hdr.prevSize==nBlock );
+- x = mem3.aPool[i-1].u.hdr.size4x;
+- mem3.aPool[i-1].u.hdr.size4x = nBlock*4 | 1 | (x&2);
+- mem3.aPool[i+nBlock-1].u.hdr.prevSize = nBlock;
+- mem3.aPool[i+nBlock-1].u.hdr.size4x |= 2;
+- return &mem3.aPool[i];
+-}
+-
+-/*
+-** Carve a piece off of the end of the mem3.iMaster free chunk.
+-** Return a pointer to the new allocation. Or, if the master chunk
+-** is not large enough, return 0.
+-*/
+-static void *memsys3FromMaster(u32 nBlock){
+- assert( sqlite3_mutex_held(mem3.mutex) );
+- assert( mem3.szMaster>=nBlock );
+- if( nBlock>=mem3.szMaster-1 ){
+- /* Use the entire master */
+- void *p = memsys3Checkout(mem3.iMaster, mem3.szMaster);
+- mem3.iMaster = 0;
+- mem3.szMaster = 0;
+- mem3.mnMaster = 0;
+- return p;
+- }else{
+- /* Split the master block. Return the tail. */
+- u32 newi, x;
+- newi = mem3.iMaster + mem3.szMaster - nBlock;
+- assert( newi > mem3.iMaster+1 );
+- mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = nBlock;
+- mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x |= 2;
+- mem3.aPool[newi-1].u.hdr.size4x = nBlock*4 + 1;
+- mem3.szMaster -= nBlock;
+- mem3.aPool[newi-1].u.hdr.prevSize = mem3.szMaster;
+- x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2;
+- mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x;
+- if( mem3.szMaster < mem3.mnMaster ){
+- mem3.mnMaster = mem3.szMaster;
+- }
+- return (void*)&mem3.aPool[newi];
+- }
+-}
+-
+-/*
+-** *pRoot is the head of a list of free chunks of the same size
+-** or same size hash. In other words, *pRoot is an entry in either
+-** mem3.aiSmall[] or mem3.aiHash[].
++** Attempt to parse the given string into a Julian Day Number. Return
++** the number of errors.
+ **
+-** This routine examines all entries on the given list and tries
+-** to coalesce each entries with adjacent free chunks.
++** The following are acceptable forms for the input string:
+ **
+-** If it sees a chunk that is larger than mem3.iMaster, it replaces
+-** the current mem3.iMaster with the new larger chunk. In order for
+-** this mem3.iMaster replacement to work, the master chunk must be
+-** linked into the hash tables. That is not the normal state of
+-** affairs, of course. The calling routine must link the master
+-** chunk before invoking this routine, then must unlink the (possibly
+-** changed) master chunk once this routine has finished.
++** 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 void memsys3Merge(u32 *pRoot){
+- u32 iNext, prev, size, i, x;
+-
+- assert( sqlite3_mutex_held(mem3.mutex) );
+- for(i=*pRoot; i>0; i=iNext){
+- iNext = mem3.aPool[i].u.list.next;
+- size = mem3.aPool[i-1].u.hdr.size4x;
+- assert( (size&1)==0 );
+- if( (size&2)==0 ){
+- memsys3UnlinkFromList(i, pRoot);
+- assert( i > mem3.aPool[i-1].u.hdr.prevSize );
+- prev = i - mem3.aPool[i-1].u.hdr.prevSize;
+- if( prev==iNext ){
+- iNext = mem3.aPool[prev].u.list.next;
+- }
+- memsys3Unlink(prev);
+- size = i + size/4 - prev;
+- x = mem3.aPool[prev-1].u.hdr.size4x & 2;
+- mem3.aPool[prev-1].u.hdr.size4x = size*4 | x;
+- mem3.aPool[prev+size-1].u.hdr.prevSize = size;
+- memsys3Link(prev);
+- i = prev;
+- }else{
+- size /= 4;
+- }
+- if( size>mem3.szMaster ){
+- mem3.iMaster = i;
+- mem3.szMaster = size;
+- }
++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;
+ }
+
+ /*
+-** Return a block of memory of at least nBytes in size.
+-** Return NULL if unable.
+-**
+-** This function assumes that the necessary mutexes, if any, are
+-** already held by the caller. Hence "Unsafe".
++** Compute the Year, Month, and Day from the julian day number.
+ */
+-static void *memsys3MallocUnsafe(int nByte){
+- u32 i;
+- u32 nBlock;
+- u32 toFree;
+-
+- assert( sqlite3_mutex_held(mem3.mutex) );
+- assert( sizeof(Mem3Block)==8 );
+- if( nByte<=12 ){
+- nBlock = 2;
+- }else{
+- nBlock = (nByte + 11)/8;
+- }
+- assert( nBlock>=2 );
+-
+- /* STEP 1:
+- ** Look for an entry of the correct size in either the small
+- ** chunk table or in the large chunk hash table. This is
+- ** successful most of the time (about 9 times out of 10).
+- */
+- if( nBlock <= MX_SMALL ){
+- i = mem3.aiSmall[nBlock-2];
+- if( i>0 ){
+- memsys3UnlinkFromList(i, &mem3.aiSmall[nBlock-2]);
+- return memsys3Checkout(i, nBlock);
+- }
++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{
+- int hash = nBlock % N_HASH;
+- for(i=mem3.aiHash[hash]; i>0; i=mem3.aPool[i].u.list.next){
+- if( mem3.aPool[i-1].u.hdr.size4x/4==nBlock ){
+- memsys3UnlinkFromList(i, &mem3.aiHash[hash]);
+- return memsys3Checkout(i, nBlock);
+- }
+- }
+- }
+-
+- /* STEP 2:
+- ** Try to satisfy the allocation by carving a piece off of the end
+- ** of the master chunk. This step usually works if step 1 fails.
+- */
+- if( mem3.szMaster>=nBlock ){
+- return memsys3FromMaster(nBlock);
+- }
+-
+-
+- /* STEP 3:
+- ** Loop through the entire memory pool. Coalesce adjacent free
+- ** chunks. Recompute the master chunk as the largest free chunk.
+- ** Then try again to satisfy the allocation by carving a piece off
+- ** of the end of the master chunk. This step happens very
+- ** rarely (we hope!)
+- */
+- for(toFree=nBlock*16; toFree<(mem3.nPool*16); toFree *= 2){
+- memsys3OutOfMemory(toFree);
+- if( mem3.iMaster ){
+- memsys3Link(mem3.iMaster);
+- mem3.iMaster = 0;
+- mem3.szMaster = 0;
+- }
+- for(i=0; i<N_HASH; i++){
+- memsys3Merge(&mem3.aiHash[i]);
+- }
+- for(i=0; i<MX_SMALL-1; i++){
+- memsys3Merge(&mem3.aiSmall[i]);
+- }
+- if( mem3.szMaster ){
+- memsys3Unlink(mem3.iMaster);
+- if( mem3.szMaster>=nBlock ){
+- return memsys3FromMaster(nBlock);
+- }
+- }
++ 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;
+ }
+-
+- /* If none of the above worked, then we fail. */
+- return 0;
++ p->validYMD = 1;
+ }
+
+ /*
+-** Free an outstanding memory allocation.
+-**
+-** This function assumes that the necessary mutexes, if any, are
+-** already held by the caller. Hence "Unsafe".
++** Compute the Hour, Minute, and Seconds from the julian day number.
+ */
+-static void memsys3FreeUnsafe(void *pOld){
+- Mem3Block *p = (Mem3Block*)pOld;
+- int i;
+- u32 size, x;
+- assert( sqlite3_mutex_held(mem3.mutex) );
+- assert( p>mem3.aPool && p<&mem3.aPool[mem3.nPool] );
+- i = p - mem3.aPool;
+- assert( (mem3.aPool[i-1].u.hdr.size4x&1)==1 );
+- size = mem3.aPool[i-1].u.hdr.size4x/4;
+- assert( i+size<=mem3.nPool+1 );
+- mem3.aPool[i-1].u.hdr.size4x &= ~1;
+- mem3.aPool[i+size-1].u.hdr.prevSize = size;
+- mem3.aPool[i+size-1].u.hdr.size4x &= ~2;
+- memsys3Link(i);
+-
+- /* Try to expand the master using the newly freed chunk */
+- if( mem3.iMaster ){
+- while( (mem3.aPool[mem3.iMaster-1].u.hdr.size4x&2)==0 ){
+- size = mem3.aPool[mem3.iMaster-1].u.hdr.prevSize;
+- mem3.iMaster -= size;
+- mem3.szMaster += size;
+- memsys3Unlink(mem3.iMaster);
+- x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2;
+- mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x;
+- mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = mem3.szMaster;
+- }
+- x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2;
+- while( (mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x&1)==0 ){
+- memsys3Unlink(mem3.iMaster+mem3.szMaster);
+- mem3.szMaster += mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x/4;
+- mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x;
+- mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = mem3.szMaster;
+- }
+- }
++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;
+ }
+
+ /*
+-** Return the size of an outstanding allocation, in bytes. The
+-** size returned omits the 8-byte header overhead. This only
+-** works for chunks that are currently checked out.
++** Compute both YMD and HMS
+ */
+-static int memsys3Size(void *p){
+- Mem3Block *pBlock;
+- if( p==0 ) return 0;
+- pBlock = (Mem3Block*)p;
+- assert( (pBlock[-1].u.hdr.size4x&1)!=0 );
+- return (pBlock[-1].u.hdr.size4x&~3)*2 - 4;
++static void computeYMD_HMS(DateTime *p){
++ computeYMD(p);
++ computeHMS(p);
+ }
+
+ /*
+-** Round up a request size to the next valid allocation size.
++** Clear the YMD and HMS and the TZ
+ */
+-static int memsys3Roundup(int n){
+- if( n<=12 ){
+- return 12;
+- }else{
+- return ((n+11)&~7) - 4;
+- }
++static void clearYMD_HMS_TZ(DateTime *p){
++ p->validYMD = 0;
++ p->validHMS = 0;
++ p->validTZ = 0;
+ }
+
+ /*
+-** Allocate nBytes of memory.
++** 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().
+ */
+-static void *memsys3Malloc(int nBytes){
+- sqlite3_int64 *p;
+- assert( nBytes>0 ); /* malloc.c filters out 0 byte requests */
+- memsys3Enter();
+- p = memsys3MallocUnsafe(nBytes);
+- memsys3Leave();
+- return (void*)p;
+-}
++#if !defined(HAVE_LOCALTIME_R) && !defined(HAVE_LOCALTIME_S) && \
++ defined(_MSC_VER) && defined(_CRT_INSECURE_DEPRECATE)
++#define HAVE_LOCALTIME_S 1
++#endif
+
++#ifndef SQLITE_OMIT_LOCALTIME
+ /*
+-** Free memory.
++** 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.
+ */
+-static void memsys3Free(void *pPrior){
+- assert( pPrior );
+- memsys3Enter();
+- memsys3FreeUnsafe(pPrior);
+- memsys3Leave();
++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)
++ 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 defined(HAVE_LOCALTIME_R) && 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
+ /*
+-** Change the size of an existing memory allocation
++** 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 void *memsys3Realloc(void *pPrior, int nBytes){
+- int nOld;
+- void *p;
+- if( pPrior==0 ){
+- return sqlite3_malloc(nBytes);
++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 ){
++ 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;
+ }
+- if( nBytes<=0 ){
+- sqlite3_free(pPrior);
++ 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;
+ }
+- nOld = memsys3Size(pPrior);
+- if( nBytes<=nOld && nBytes>=nOld-128 ){
+- return pPrior;
+- }
+- memsys3Enter();
+- p = memsys3MallocUnsafe(nBytes);
+- if( p ){
+- if( nOld<nBytes ){
+- memcpy(p, pPrior, nOld);
+- }else{
+- memcpy(p, pPrior, nBytes);
+- }
+- memsys3FreeUnsafe(pPrior);
+- }
+- memsys3Leave();
+- return p;
++ 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 */
+
+ /*
+-** Initialize this module.
++** 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 memsys3Init(void *NotUsed){
+- UNUSED_PARAMETER(NotUsed);
+- if( !sqlite3GlobalConfig.pHeap ){
+- return SQLITE_ERROR;
++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]];
+ }
+-
+- /* Store a pointer to the memory block in global structure mem3. */
+- assert( sizeof(Mem3Block)==8 );
+- mem3.aPool = (Mem3Block *)sqlite3GlobalConfig.pHeap;
+- mem3.nPool = (sqlite3GlobalConfig.nHeap / sizeof(Mem3Block)) - 2;
+-
+- /* Initialize the master block. */
+- mem3.szMaster = mem3.nPool;
+- mem3.mnMaster = mem3.szMaster;
+- mem3.iMaster = 1;
+- mem3.aPool[0].u.hdr.size4x = (mem3.szMaster<<2) + 2;
+- mem3.aPool[mem3.nPool].u.hdr.prevSize = mem3.nPool;
+- mem3.aPool[mem3.nPool].u.hdr.size4x = 1;
+-
+- return SQLITE_OK;
+-}
+-
+-/*
+-** Deinitialize this module.
+-*/
+-static void memsys3Shutdown(void *NotUsed){
+- UNUSED_PARAMETER(NotUsed);
+- mem3.mutex = 0;
+- return;
+-}
+-
+-
+-
+-/*
+-** Open the file indicated and write a log of all unfreed memory
+-** allocations into that log.
+-*/
+-SQLITE_PRIVATE void sqlite3Memsys3Dump(const char *zFilename){
+-#ifdef SQLITE_DEBUG
+- FILE *out;
+- u32 i, j;
+- u32 size;
+- if( zFilename==0 || zFilename[0]==0 ){
+- out = stdout;
+- }else{
+- out = fopen(zFilename, "w");
+- if( out==0 ){
+- fprintf(stderr, "** Unable to output memory debug output log: %s **\n",
+- zFilename);
+- return;
+- }
+- }
+- memsys3Enter();
+- fprintf(out, "CHUNKS:\n");
+- for(i=1; i<=mem3.nPool; i+=size/4){
+- size = mem3.aPool[i-1].u.hdr.size4x;
+- if( size/4<=1 ){
+- fprintf(out, "%p size error\n", &mem3.aPool[i]);
+- assert( 0 );
++ 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;
+ }
+- if( (size&1)==0 && mem3.aPool[i+size/4-1].u.hdr.prevSize!=size/4 ){
+- fprintf(out, "%p tail size does not match\n", &mem3.aPool[i]);
+- assert( 0 );
++#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;
+ }
+- if( ((mem3.aPool[i+size/4-1].u.hdr.size4x&2)>>1)!=(size&1) ){
+- fprintf(out, "%p tail checkout bit is incorrect\n", &mem3.aPool[i]);
+- assert( 0 );
++ 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;
+ }
+- if( size&1 ){
+- fprintf(out, "%p %6d bytes checked out\n", &mem3.aPool[i], (size/4)*8-8);
+- }else{
+- fprintf(out, "%p %6d bytes free%s\n", &mem3.aPool[i], (size/4)*8-8,
+- i==mem3.iMaster ? " **master**" : "");
++ 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;
+ }
+- }
+- for(i=0; i<MX_SMALL-1; i++){
+- if( mem3.aiSmall[i]==0 ) continue;
+- fprintf(out, "small(%2d):", i);
+- for(j = mem3.aiSmall[i]; j>0; j=mem3.aPool[j].u.list.next){
+- fprintf(out, " %p(%d)", &mem3.aPool[j],
+- (mem3.aPool[j-1].u.hdr.size4x/4)*8-8);
++ 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;
+ }
+- fprintf(out, "\n");
+- }
+- for(i=0; i<N_HASH; i++){
+- if( mem3.aiHash[i]==0 ) continue;
+- fprintf(out, "hash(%2d):", i);
+- for(j = mem3.aiHash[i]; j>0; j=mem3.aPool[j].u.list.next){
+- fprintf(out, " %p(%d)", &mem3.aPool[j],
+- (mem3.aPool[j-1].u.hdr.size4x/4)*8-8);
++ default: {
++ break;
+ }
+- fprintf(out, "\n");
+- }
+- fprintf(out, "master=%d\n", mem3.iMaster);
+- fprintf(out, "nowUsed=%d\n", mem3.nPool*8 - mem3.szMaster*8);
+- fprintf(out, "mxUsed=%d\n", mem3.nPool*8 - mem3.mnMaster*8);
+- sqlite3_mutex_leave(mem3.mutex);
+- if( out==stdout ){
+- fflush(stdout);
+- }else{
+- fclose(out);
+ }
+-#else
+- UNUSED_PARAMETER(zFilename);
+-#endif
++ return rc;
+ }
+
+ /*
+-** This routine is the only routine in this file with external
+-** linkage.
+-**
+-** 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.
++** 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.
+ **
+-** This routine is only called by sqlite3_config(), and therefore
+-** is not required to be threadsafe (it is not).
++** If there are zero parameters (if even argv[0] is undefined)
++** then assume a default value of "now" for argv[0].
+ */
+-SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void){
+- static const sqlite3_mem_methods mempoolMethods = {
+- memsys3Malloc,
+- memsys3Free,
+- memsys3Realloc,
+- memsys3Size,
+- memsys3Roundup,
+- memsys3Init,
+- memsys3Shutdown,
+- 0
+- };
+- return &mempoolMethods;
++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;
+ }
+
+-#endif /* SQLITE_ENABLE_MEMSYS3 */
+-
+-/************** End of mem3.c ************************************************/
+-/************** Begin file mem5.c ********************************************/
+-/*
+-** 2007 October 14
+-**
+-** The author disclaims copyright to this source code. In place of
+-** a legal notice, here is a blessing:
+-**
+-** May you do good and not evil.
+-** May you find forgiveness for yourself and forgive others.
+-** May you share freely, never taking more than you give.
+-**
+-*************************************************************************
+-** This file contains the C functions that implement a memory
+-** allocation subsystem for use by SQLite.
+-**
+-** This version of the memory allocation subsystem omits all
+-** use of malloc(). The application gives SQLite a block of memory
+-** before calling sqlite3_initialize() from which allocations
+-** are made and returned by the xMalloc() and xRealloc()
+-** implementations. Once sqlite3_initialize() has been called,
+-** the amount of memory available to SQLite is fixed and cannot
+-** be changed.
+-**
+-** This version of the memory allocation subsystem is included
+-** in the build only if SQLITE_ENABLE_MEMSYS5 is defined.
+-**
+-** This memory allocator uses the following algorithm:
+-**
+-** 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.
+-**
+-** 3. New memory is allocated from the first available free block.
+-**
+-** This algorithm is described in: J. M. Robson. "Bounds for Some Functions
+-** Concerning Dynamic Storage Allocation". Journal of the Association for
+-** Computing Machinery, Volume 21, Number 8, July 1974, pages 491-499.
+-**
+-** Let n be the size of the largest allocation divided by the minimum
+-** allocation size (after rounding all sizes up to a power of 2.) Let M
+-** be the maximum amount of memory ever outstanding at one time. Let
+-** N be the total amount of memory available for allocation. Robson
+-** proved that this memory allocator will never breakdown due to
+-** fragmentation as long as the following constraint holds:
+-**
+-** N >= M*(1 + log2(n)/2) - n + 1
+-**
+-** The sqlite3_status() logic tracks the maximum values of n and M so
+-** that an application can, at any time, verify this constraint.
+-*/
+
+ /*
+-** This version of the memory allocator is used only when
+-** SQLITE_ENABLE_MEMSYS5 is defined.
++** The following routines implement the various date and time functions
++** of SQLite.
+ */
+-#ifdef SQLITE_ENABLE_MEMSYS5
+
+ /*
+-** A minimum allocation is an instance of the following structure.
+-** Larger allocations are an array of these structures where the
+-** size of the array is a power of 2.
++** julianday( TIMESTRING, MOD, MOD, ...)
+ **
+-** The size of this object must be a power of two. That fact is
+-** verified in memsys5Init().
+-*/
+-typedef struct Mem5Link Mem5Link;
+-struct Mem5Link {
+- int next; /* Index of next free chunk */
+- int prev; /* Index of previous free chunk */
+-};
+-
+-/*
+-** Maximum size of any allocation is ((1<<LOGMAX)*mem5.szAtom). Since
+-** mem5.szAtom is always at least 8 and 32-bit integers are used,
+-** it is not actually possible to reach this limit.
+-*/
+-#define LOGMAX 30
+-
+-/*
+-** Masks used for mem5.aCtrl[] elements.
+-*/
+-#define CTRL_LOGSIZE 0x1f /* Log2 Size of this block */
+-#define CTRL_FREE 0x20 /* True if not checked out */
+-
+-/*
+-** All of the static variables used by this module are collected
+-** into a single structure named "mem5". This is to keep the
+-** static variables organized and to reduce namespace pollution
+-** when this module is combined with other in the amalgamation.
+-*/
+-static SQLITE_WSD struct Mem5Global {
+- /*
+- ** Memory available for allocation
+- */
+- int szAtom; /* Smallest possible allocation in bytes */
+- int nBlock; /* Number of szAtom sized blocks in zPool */
+- u8 *zPool; /* Memory available to be allocated */
+-
+- /*
+- ** Mutex to control access to the memory allocation subsystem.
+- */
+- sqlite3_mutex *mutex;
+-
+- /*
+- ** Performance statistics
+- */
+- u64 nAlloc; /* Total number of calls to malloc */
+- u64 totalAlloc; /* Total of all malloc calls - includes internal frag */
+- u64 totalExcess; /* Total internal fragmentation */
+- u32 currentOut; /* Current checkout, including internal fragmentation */
+- u32 currentCount; /* Current number of distinct checkouts */
+- u32 maxOut; /* Maximum instantaneous currentOut */
+- u32 maxCount; /* Maximum instantaneous currentCount */
+- u32 maxRequest; /* Largest allocation (exclusive of internal frag) */
+-
+- /*
+- ** Lists of free blocks. aiFreelist[0] is a list of free blocks of
+- ** size mem5.szAtom. aiFreelist[1] holds blocks of size szAtom*2.
+- ** and so forth.
+- */
+- int aiFreelist[LOGMAX+1];
+-
+- /*
+- ** Space for tracking which blocks are checked out and the size
+- ** of each block. One byte per block.
+- */
+- u8 *aCtrl;
+-
+-} mem5;
+-
+-/*
+-** Access the static variable through a macro for SQLITE_OMIT_WSD
+-*/
+-#define mem5 GLOBAL(struct Mem5Global, mem5)
+-
+-/*
+-** Assuming mem5.zPool is divided up into an array of Mem5Link
+-** structures, return a pointer to the idx-th such lik.
++** Return the julian day number of the date specified in the arguments
+ */
+-#define MEM5LINK(idx) ((Mem5Link *)(&mem5.zPool[(idx)*mem5.szAtom]))
++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);
++ }
++}
+
+ /*
+-** Unlink the chunk at mem5.aPool[i] from list it is currently
+-** on. It should be found on mem5.aiFreelist[iLogsize].
++** datetime( TIMESTRING, MOD, MOD, ...)
++**
++** Return YYYY-MM-DD HH:MM:SS
+ */
+-static void memsys5Unlink(int i, int iLogsize){
+- int next, prev;
+- assert( i>=0 && i<mem5.nBlock );
+- assert( iLogsize>=0 && iLogsize<=LOGMAX );
+- assert( (mem5.aCtrl[i] & CTRL_LOGSIZE)==iLogsize );
+-
+- next = MEM5LINK(i)->next;
+- prev = MEM5LINK(i)->prev;
+- if( prev<0 ){
+- mem5.aiFreelist[iLogsize] = next;
+- }else{
+- MEM5LINK(prev)->next = next;
+- }
+- if( next>=0 ){
+- MEM5LINK(next)->prev = prev;
++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);
+ }
+ }
+
+ /*
+-** Link the chunk at mem5.aPool[i] so that is on the iLogsize
+-** free list.
++** time( TIMESTRING, MOD, MOD, ...)
++**
++** Return HH:MM:SS
+ */
+-static void memsys5Link(int i, int iLogsize){
+- int x;
+- assert( sqlite3_mutex_held(mem5.mutex) );
+- assert( i>=0 && i<mem5.nBlock );
+- assert( iLogsize>=0 && iLogsize<=LOGMAX );
+- assert( (mem5.aCtrl[i] & CTRL_LOGSIZE)==iLogsize );
+-
+- x = MEM5LINK(i)->next = mem5.aiFreelist[iLogsize];
+- MEM5LINK(i)->prev = -1;
+- if( x>=0 ){
+- assert( x<mem5.nBlock );
+- MEM5LINK(x)->prev = i;
++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);
+ }
+- mem5.aiFreelist[iLogsize] = i;
+ }
+
+ /*
+-** If the STATIC_MEM mutex is not already held, obtain it now. The mutex
+-** will already be held (obtained by code in malloc.c) if
+-** sqlite3GlobalConfig.bMemStat is true.
++** date( TIMESTRING, MOD, MOD, ...)
++**
++** Return YYYY-MM-DD
+ */
+-static void memsys5Enter(void){
+- sqlite3_mutex_enter(mem5.mutex);
+-}
+-static void memsys5Leave(void){
+- sqlite3_mutex_leave(mem5.mutex);
+-}
+-
+-/*
+-** Return the size of an outstanding allocation, in bytes. The
+-** size returned omits the 8-byte header overhead. This only
+-** works for chunks that are currently checked out.
+-*/
+-static int memsys5Size(void *p){
+- int iSize = 0;
+- if( p ){
+- int i = ((u8 *)p-mem5.zPool)/mem5.szAtom;
+- assert( i>=0 && i<mem5.nBlock );
+- iSize = mem5.szAtom * (1 << (mem5.aCtrl[i]&CTRL_LOGSIZE));
+- }
+- return iSize;
+-}
+-
+-/*
+-** Find the first entry on the freelist iLogsize. Unlink that
+-** entry and return its index.
+-*/
+-static int memsys5UnlinkFirst(int iLogsize){
+- int i;
+- int iFirst;
+-
+- assert( iLogsize>=0 && iLogsize<=LOGMAX );
+- i = iFirst = mem5.aiFreelist[iLogsize];
+- assert( iFirst>=0 );
+- while( i>0 ){
+- if( i<iFirst ) iFirst = i;
+- i = MEM5LINK(i)->next;
++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);
+ }
+- memsys5Unlink(iFirst, iLogsize);
+- return iFirst;
+ }
+
+ /*
+-** Return a block of memory of at least nBytes in size.
+-** Return NULL if unable. Return NULL if nBytes==0.
++** strftime( FORMAT, TIMESTRING, MOD, MOD, ...)
+ **
+-** The caller guarantees that nByte positive.
++** Return a string described by FORMAT. Conversions as follows:
+ **
+-** The caller has obtained a mutex prior to invoking this
+-** routine so there is never any chance that two or more
+-** threads can be in this routine at the same time.
++** %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 *memsys5MallocUnsafe(int nByte){
+- int i; /* Index of a mem5.aPool[] slot */
+- int iBin; /* Index into mem5.aiFreelist[] */
+- int iFullSz; /* Size of allocation rounded up to power of 2 */
+- int iLogsize; /* Log2 of iFullSz/POW2_MIN */
+-
+- /* nByte must be a positive */
+- assert( nByte>0 );
+-
+- /* Keep track of the maximum allocation request. Even unfulfilled
+- ** requests are counted */
+- if( (u32)nByte>mem5.maxRequest ){
+- mem5.maxRequest = nByte;
+- }
+-
+- /* Abort if the requested allocation size is larger than the largest
+- ** power of two that we can represent using 32-bit signed integers.
+- */
+- if( nByte > 0x40000000 ){
+- return 0;
++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 = (const char*)sqlite3_value_text(argv[0]);
++ char zBuf[100];
++ 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++;
++ }
+ }
+-
+- /* Round nByte up to the next valid power of two */
+- for(iFullSz=mem5.szAtom, iLogsize=0; iFullSz<nByte; iFullSz *= 2, iLogsize++){}
+-
+- /* Make sure mem5.aiFreelist[iLogsize] contains at least one free
+- ** block. If not, then split a block of the next larger power of
+- ** two in order to create a new free block of size iLogsize.
+- */
+- for(iBin=iLogsize; mem5.aiFreelist[iBin]<0 && iBin<=LOGMAX; iBin++){}
+- if( iBin>LOGMAX ){
+- testcase( sqlite3GlobalConfig.xLog!=0 );
+- sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes", nByte);
+- return 0;
++ 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;
++ }
+ }
+- i = memsys5UnlinkFirst(iBin);
+- while( iBin>iLogsize ){
+- int newSize;
+-
+- iBin--;
+- newSize = 1 << iBin;
+- mem5.aCtrl[i+newSize] = CTRL_FREE | iBin;
+- memsys5Link(i+newSize, iBin);
++ 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;
++ }
++ }
+ }
+- mem5.aCtrl[i] = iLogsize;
+-
+- /* Update allocator performance statistics. */
+- mem5.nAlloc++;
+- mem5.totalAlloc += iFullSz;
+- mem5.totalExcess += iFullSz - nByte;
+- mem5.currentCount++;
+- mem5.currentOut += iFullSz;
+- if( mem5.maxCount<mem5.currentCount ) mem5.maxCount = mem5.currentCount;
+- if( mem5.maxOut<mem5.currentOut ) mem5.maxOut = mem5.currentOut;
+-
+- /* Return a pointer to the allocated memory. */
+- return (void*)&mem5.zPool[i*mem5.szAtom];
++ z[j] = 0;
++ sqlite3_result_text(context, z, -1,
++ z==zBuf ? SQLITE_TRANSIENT : SQLITE_DYNAMIC);
+ }
+
+ /*
+-** Free an outstanding memory allocation.
++** current_time()
++**
++** This function returns the same value as time('now').
+ */
+-static void memsys5FreeUnsafe(void *pOld){
+- u32 size, iLogsize;
+- int iBlock;
+-
+- /* Set iBlock to the index of the block pointed to by pOld in
+- ** the array of mem5.szAtom byte blocks pointed to by mem5.zPool.
+- */
+- iBlock = ((u8 *)pOld-mem5.zPool)/mem5.szAtom;
+-
+- /* Check that the pointer pOld points to a valid, non-free block. */
+- assert( iBlock>=0 && iBlock<mem5.nBlock );
+- assert( ((u8 *)pOld-mem5.zPool)%mem5.szAtom==0 );
+- assert( (mem5.aCtrl[iBlock] & CTRL_FREE)==0 );
+-
+- iLogsize = mem5.aCtrl[iBlock] & CTRL_LOGSIZE;
+- size = 1<<iLogsize;
+- assert( iBlock+size-1<(u32)mem5.nBlock );
+-
+- mem5.aCtrl[iBlock] |= CTRL_FREE;
+- mem5.aCtrl[iBlock+size-1] |= CTRL_FREE;
+- assert( mem5.currentCount>0 );
+- assert( mem5.currentOut>=(size*mem5.szAtom) );
+- mem5.currentCount--;
+- mem5.currentOut -= size*mem5.szAtom;
+- assert( mem5.currentOut>0 || mem5.currentCount==0 );
+- assert( mem5.currentCount>0 || mem5.currentOut==0 );
+-
+- mem5.aCtrl[iBlock] = CTRL_FREE | iLogsize;
+- while( ALWAYS(iLogsize<LOGMAX) ){
+- int iBuddy;
+- if( (iBlock>>iLogsize) & 1 ){
+- iBuddy = iBlock - size;
+- }else{
+- iBuddy = iBlock + size;
+- }
+- assert( iBuddy>=0 );
+- if( (iBuddy+(1<<iLogsize))>mem5.nBlock ) break;
+- if( mem5.aCtrl[iBuddy]!=(CTRL_FREE | iLogsize) ) break;
+- memsys5Unlink(iBuddy, iLogsize);
+- iLogsize++;
+- if( iBuddy<iBlock ){
+- mem5.aCtrl[iBuddy] = CTRL_FREE | iLogsize;
+- mem5.aCtrl[iBlock] = 0;
+- iBlock = iBuddy;
+- }else{
+- mem5.aCtrl[iBlock] = CTRL_FREE | iLogsize;
+- mem5.aCtrl[iBuddy] = 0;
+- }
+- size *= 2;
+- }
+- memsys5Link(iBlock, iLogsize);
++static void ctimeFunc(
++ sqlite3_context *context,
++ int NotUsed,
++ sqlite3_value **NotUsed2
++){
++ UNUSED_PARAMETER2(NotUsed, NotUsed2);
++ timeFunc(context, 0, 0);
+ }
+
+ /*
+-** Allocate nBytes of memory
++** current_date()
++**
++** This function returns the same value as date('now').
+ */
+-static void *memsys5Malloc(int nBytes){
+- sqlite3_int64 *p = 0;
+- if( nBytes>0 ){
+- memsys5Enter();
+- p = memsys5MallocUnsafe(nBytes);
+- memsys5Leave();
+- }
+- return (void*)p;
++static void cdateFunc(
++ sqlite3_context *context,
++ int NotUsed,
++ sqlite3_value **NotUsed2
++){
++ UNUSED_PARAMETER2(NotUsed, NotUsed2);
++ dateFunc(context, 0, 0);
+ }
+
+ /*
+-** Free memory.
++** current_timestamp()
+ **
+-** The outer layer memory allocator prevents this routine from
+-** being called with pPrior==0.
++** This function returns the same value as datetime('now').
+ */
+-static void memsys5Free(void *pPrior){
+- assert( pPrior!=0 );
+- memsys5Enter();
+- memsys5FreeUnsafe(pPrior);
+- memsys5Leave();
++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
+ /*
+-** Change the size of an existing memory allocation.
+-**
+-** The outer layer memory allocator prevents this routine from
+-** being called with pPrior==0.
++** 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.
+ **
+-** nBytes is always a value obtained from a prior call to
+-** memsys5Round(). Hence nBytes is always a non-negative power
+-** of two. If nBytes==0 that means that an oversize allocation
+-** (an allocation larger than 0x40000000) was requested and this
+-** routine should return 0 without freeing pPrior.
++** 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 *memsys5Realloc(void *pPrior, int nBytes){
+- int nOld;
+- void *p;
+- assert( pPrior!=0 );
+- assert( (nBytes&(nBytes-1))==0 ); /* EV: R-46199-30249 */
+- assert( nBytes>=0 );
+- if( nBytes==0 ){
+- return 0;
+- }
+- nOld = memsys5Size(pPrior);
+- if( nBytes<=nOld ){
+- return pPrior;
+- }
+- memsys5Enter();
+- p = memsys5MallocUnsafe(nBytes);
+- if( p ){
+- memcpy(p, pPrior, nOld);
+- memsys5FreeUnsafe(pPrior);
++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);
++
++ db = sqlite3_context_db_handle(context);
++ if( sqlite3OsCurrentTimeInt64(db->pVfs, &iT) ) return;
++ t = iT/1000 - 10000*(sqlite3_int64)21086676;
++#ifdef 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);
+ }
+- memsys5Leave();
+- return p;
+ }
++#endif
+
+ /*
+-** Round up a request size to the next valid allocation size. If
+-** the allocation is too large to be handled by this allocation system,
+-** return 0.
+-**
+-** All allocations must be a power of two and must be expressed by a
+-** 32-bit signed integer. Hence the largest allocation is 0x40000000
+-** or 1073741824 bytes.
++** This function registered all of the above C functions as SQL
++** functions. This should be the only routine in this file with
++** external linkage.
+ */
+-static int memsys5Roundup(int n){
+- int iFullSz;
+- if( n > 0x40000000 ) return 0;
+- for(iFullSz=mem5.szAtom; iFullSz<n; iFullSz *= 2);
+- return iFullSz;
++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 **********************************************/
+ /*
+-** Return the ceiling of the logarithm base 2 of iValue.
++** 2005 November 29
+ **
+-** Examples: memsys5Log(1) -> 0
+-** memsys5Log(2) -> 1
+-** memsys5Log(4) -> 2
+-** memsys5Log(5) -> 3
+-** memsys5Log(8) -> 3
+-** memsys5Log(9) -> 4
++** 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.
+ */
+-static int memsys5Log(int iValue){
+- int iLog;
+- for(iLog=0; (iLog<(int)((sizeof(int)*8)-1)) && (1<<iLog)<iValue; iLog++);
+- return iLog;
+-}
++#define _SQLITE_OS_C_ 1
++#undef _SQLITE_OS_C_
+
+ /*
+-** Initialize the memory allocator.
++** 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()
+ **
+-** This routine is not threadsafe. The caller must be holding a mutex
+-** to prevent multiple threads from entering at the same time.
+ */
+-static int memsys5Init(void *NotUsed){
+- int ii; /* Loop counter */
+- int nByte; /* Number of bytes of memory available to this allocator */
+- u8 *zByte; /* Memory usable by this allocator */
+- int nMinLog; /* Log base 2 of minimum allocation size in bytes */
+- int iOffset; /* An offset into mem5.aCtrl[] */
+-
+- UNUSED_PARAMETER(NotUsed);
+-
+- /* For the purposes of this routine, disable the mutex */
+- mem5.mutex = 0;
++#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 size of a Mem5Link object must be a power of two. Verify that
+- ** this is case.
+- */
+- assert( (sizeof(Mem5Link)&(sizeof(Mem5Link)-1))==0 );
++/*
++** 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);
++}
+
+- nByte = sqlite3GlobalConfig.nHeap;
+- zByte = (u8*)sqlite3GlobalConfig.pHeap;
+- assert( zByte!=0 ); /* sqlite3_config() does not allow otherwise */
++/*
++** 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){
++ DO_OS_MALLOC_TEST(id);
++ 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);
++}
+
+- /* boundaries on sqlite3GlobalConfig.mnReq are enforced in sqlite3_config() */
+- nMinLog = memsys5Log(sqlite3GlobalConfig.mnReq);
+- mem5.szAtom = (1<<nMinLog);
+- while( (int)sizeof(Mem5Link)>mem5.szAtom ){
+- mem5.szAtom = mem5.szAtom << 1;
+- }
++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);
++}
+
+- mem5.nBlock = (nByte / (mem5.szAtom+sizeof(u8)));
+- mem5.zPool = zByte;
+- mem5.aCtrl = (u8 *)&mem5.zPool[mem5.nBlock*mem5.szAtom];
++#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);
++}
++#else
++/* No-op stubs to use when memory-mapped I/O is disabled */
++SQLITE_PRIVATE int sqlite3OsFetch(sqlite3_file *id, i64 iOff, int iAmt, void **pp){
++ *pp = 0;
++ return SQLITE_OK;
++}
++SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *id, i64 iOff, void *p){
++ return SQLITE_OK;
++}
++#endif
+
+- for(ii=0; ii<=LOGMAX; ii++){
+- mem5.aiFreelist[ii] = -1;
++/*
++** The next group of routines are convenience wrappers around the
++** VFS methods.
++*/
++SQLITE_PRIVATE int sqlite3OsOpen(
++ sqlite3_vfs *pVfs,
++ const char *zPath,
++ sqlite3_file *pFile,
++ int flags,
++ int *pFlagsOut
++){
++ int rc;
++ DO_OS_MALLOC_TEST(0);
++ /* 0x87f7f is a mask of SQLITE_OPEN_ flags that are valid to be passed
++ ** down into the VFS layer. Some SQLITE_OPEN_ flags (for example,
++ ** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before
++ ** reaching the VFS. */
++ rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x87f7f, pFlagsOut);
++ assert( rc==SQLITE_OK || pFile->pMethods==0 );
++ return rc;
++}
++SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
++ DO_OS_MALLOC_TEST(0);
++ assert( dirSync==0 || dirSync==1 );
++ return pVfs->xDelete(pVfs, zPath, dirSync);
++}
++SQLITE_PRIVATE int sqlite3OsAccess(
++ sqlite3_vfs *pVfs,
++ const char *zPath,
++ int flags,
++ int *pResOut
++){
++ DO_OS_MALLOC_TEST(0);
++ return pVfs->xAccess(pVfs, zPath, flags, pResOut);
++}
++SQLITE_PRIVATE int sqlite3OsFullPathname(
++ sqlite3_vfs *pVfs,
++ const char *zPath,
++ int nPathOut,
++ char *zPathOut
++){
++ DO_OS_MALLOC_TEST(0);
++ zPathOut[0] = 0;
++ return pVfs->xFullPathname(pVfs, zPath, nPathOut, zPathOut);
++}
++#ifndef SQLITE_OMIT_LOAD_EXTENSION
++SQLITE_PRIVATE void *sqlite3OsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
++ return pVfs->xDlOpen(pVfs, zPath);
++}
++SQLITE_PRIVATE void sqlite3OsDlError(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
++ pVfs->xDlError(pVfs, nByte, zBufOut);
++}
++SQLITE_PRIVATE void (*sqlite3OsDlSym(sqlite3_vfs *pVfs, void *pHdle, const char *zSym))(void){
++ return pVfs->xDlSym(pVfs, pHdle, zSym);
++}
++SQLITE_PRIVATE void sqlite3OsDlClose(sqlite3_vfs *pVfs, void *pHandle){
++ pVfs->xDlClose(pVfs, pHandle);
++}
++#endif /* SQLITE_OMIT_LOAD_EXTENSION */
++SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
++ return pVfs->xRandomness(pVfs, nByte, zBufOut);
++}
++SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *pVfs, int nMicro){
++ return pVfs->xSleep(pVfs, nMicro);
++}
++SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
++ int rc;
++ /* IMPLEMENTATION-OF: R-49045-42493 SQLite will use the xCurrentTimeInt64()
++ ** method to get the current date and time if that method is available
++ ** (if iVersion is 2 or greater and the function pointer is not NULL) and
++ ** will fall back to xCurrentTime() if xCurrentTimeInt64() is
++ ** unavailable.
++ */
++ if( pVfs->iVersion>=2 && pVfs->xCurrentTimeInt64 ){
++ rc = pVfs->xCurrentTimeInt64(pVfs, pTimeOut);
++ }else{
++ double r;
++ rc = pVfs->xCurrentTime(pVfs, &r);
++ *pTimeOut = (sqlite3_int64)(r*86400000.0);
+ }
++ return rc;
++}
+
+- iOffset = 0;
+- for(ii=LOGMAX; ii>=0; ii--){
+- int nAlloc = (1<<ii);
+- if( (iOffset+nAlloc)<=mem5.nBlock ){
+- mem5.aCtrl[iOffset] = ii | CTRL_FREE;
+- memsys5Link(iOffset, ii);
+- iOffset += nAlloc;
++SQLITE_PRIVATE int sqlite3OsOpenMalloc(
++ sqlite3_vfs *pVfs,
++ const char *zFile,
++ sqlite3_file **ppFile,
++ int flags,
++ int *pOutFlags
++){
++ int rc = SQLITE_NOMEM;
++ sqlite3_file *pFile;
++ pFile = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile);
++ if( pFile ){
++ rc = sqlite3OsOpen(pVfs, zFile, pFile, flags, pOutFlags);
++ if( rc!=SQLITE_OK ){
++ sqlite3_free(pFile);
++ }else{
++ *ppFile = pFile;
+ }
+- assert((iOffset+nAlloc)>mem5.nBlock);
+- }
+-
+- /* If a mutex is required for normal operation, allocate one */
+- if( sqlite3GlobalConfig.bMemstat==0 ){
+- mem5.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
+ }
+-
+- return SQLITE_OK;
++ return rc;
++}
++SQLITE_PRIVATE int sqlite3OsCloseFree(sqlite3_file *pFile){
++ int rc = SQLITE_OK;
++ assert( pFile );
++ rc = sqlite3OsClose(pFile);
++ sqlite3_free(pFile);
++ return rc;
+ }
+
+ /*
+-** Deinitialize this module.
++** This function is a wrapper around the OS specific implementation of
++** sqlite3_os_init(). The purpose of the wrapper is to provide the
++** ability to simulate a malloc failure, so that the handling of an
++** error in sqlite3_os_init() by the upper layers can be tested.
+ */
+-static void memsys5Shutdown(void *NotUsed){
+- UNUSED_PARAMETER(NotUsed);
+- mem5.mutex = 0;
+- return;
++SQLITE_PRIVATE int sqlite3OsInit(void){
++ void *p = sqlite3_malloc(10);
++ if( p==0 ) return SQLITE_NOMEM;
++ sqlite3_free(p);
++ return sqlite3_os_init();
+ }
+
+-#ifdef SQLITE_TEST
+ /*
+-** Open the file indicated and write a log of all unfreed memory
+-** allocations into that log.
++** The list of all registered VFS implementations.
+ */
+-SQLITE_PRIVATE void sqlite3Memsys5Dump(const char *zFilename){
+- FILE *out;
+- int i, j, n;
+- int nMinLog;
++static sqlite3_vfs * SQLITE_WSD vfsList = 0;
++#define vfsList GLOBAL(sqlite3_vfs *, vfsList)
+
+- if( zFilename==0 || zFilename[0]==0 ){
+- out = stdout;
+- }else{
+- out = fopen(zFilename, "w");
+- if( out==0 ){
+- fprintf(stderr, "** Unable to output memory debug output log: %s **\n",
+- zFilename);
+- return;
+- }
++/*
++** 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){
++ sqlite3_vfs *pVfs = 0;
++#if SQLITE_THREADSAFE
++ sqlite3_mutex *mutex;
++#endif
++#ifndef SQLITE_OMIT_AUTOINIT
++ int rc = sqlite3_initialize();
++ if( rc ) return 0;
++#endif
++#if SQLITE_THREADSAFE
++ mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
++#endif
++ sqlite3_mutex_enter(mutex);
++ for(pVfs = vfsList; pVfs; pVfs=pVfs->pNext){
++ if( zVfs==0 ) break;
++ if( strcmp(zVfs, pVfs->zName)==0 ) break;
+ }
+- memsys5Enter();
+- nMinLog = memsys5Log(mem5.szAtom);
+- for(i=0; i<=LOGMAX && i+nMinLog<32; i++){
+- for(n=0, j=mem5.aiFreelist[i]; j>=0; j = MEM5LINK(j)->next, n++){}
+- fprintf(out, "freelist items of size %d: %d\n", mem5.szAtom << i, n);
++ sqlite3_mutex_leave(mutex);
++ return pVfs;
++}
++
++/*
++** Unlink a VFS from the linked list
++*/
++static void vfsUnlink(sqlite3_vfs *pVfs){
++ assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)) );
++ if( pVfs==0 ){
++ /* No-op */
++ }else if( vfsList==pVfs ){
++ vfsList = pVfs->pNext;
++ }else if( vfsList ){
++ sqlite3_vfs *p = vfsList;
++ while( p->pNext && p->pNext!=pVfs ){
++ p = p->pNext;
++ }
++ if( p->pNext==pVfs ){
++ p->pNext = pVfs->pNext;
++ }
+ }
+- fprintf(out, "mem5.nAlloc = %llu\n", mem5.nAlloc);
+- fprintf(out, "mem5.totalAlloc = %llu\n", mem5.totalAlloc);
+- fprintf(out, "mem5.totalExcess = %llu\n", mem5.totalExcess);
+- fprintf(out, "mem5.currentOut = %u\n", mem5.currentOut);
+- fprintf(out, "mem5.currentCount = %u\n", mem5.currentCount);
+- fprintf(out, "mem5.maxOut = %u\n", mem5.maxOut);
+- fprintf(out, "mem5.maxCount = %u\n", mem5.maxCount);
+- fprintf(out, "mem5.maxRequest = %u\n", mem5.maxRequest);
+- memsys5Leave();
+- if( out==stdout ){
+- fflush(stdout);
++}
++
++/*
++** Register a VFS with the system. It is harmless to register the same
++** VFS multiple times. The new VFS becomes the default if makeDflt is
++** true.
++*/
++SQLITE_API int 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
++ MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
++ sqlite3_mutex_enter(mutex);
++ vfsUnlink(pVfs);
++ if( makeDflt || vfsList==0 ){
++ pVfs->pNext = vfsList;
++ vfsList = pVfs;
+ }else{
+- fclose(out);
++ pVfs->pNext = vfsList->pNext;
++ vfsList->pNext = pVfs;
+ }
++ assert(vfsList);
++ sqlite3_mutex_leave(mutex);
++ return SQLITE_OK;
+ }
+-#endif
+
+ /*
+-** This routine is the only routine in this file with external
+-** linkage. It returns a pointer to a static sqlite3_mem_methods
+-** struct populated with the memsys5 methods.
++** Unregister a VFS so that it is no longer accessible.
+ */
+-SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys5(void){
+- static const sqlite3_mem_methods memsys5Methods = {
+- memsys5Malloc,
+- memsys5Free,
+- memsys5Realloc,
+- memsys5Size,
+- memsys5Roundup,
+- memsys5Init,
+- memsys5Shutdown,
+- 0
+- };
+- return &memsys5Methods;
++SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs *pVfs){
++#if SQLITE_THREADSAFE
++ sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
++#endif
++ sqlite3_mutex_enter(mutex);
++ vfsUnlink(pVfs);
++ sqlite3_mutex_leave(mutex);
++ return SQLITE_OK;
+ }
+
+-#endif /* SQLITE_ENABLE_MEMSYS5 */
+-
+-/************** End of mem5.c ************************************************/
+-/************** Begin file mutex.c *******************************************/
++/************** End of os.c **************************************************/
++/************** Begin file fault.c *******************************************/
+ /*
+-** 2007 August 14
++** 2008 Jan 22
+ **
+ ** The author disclaims copyright to this source code. In place of
+ ** a legal notice, here is a blessing:
+@@ -17715,152 +18451,147 @@
+ ** May you share freely, never taking more than you give.
+ **
+ *************************************************************************
+-** This file contains the C functions that implement mutexes.
+ **
+-** This file contains code that is common across all mutex implementations.
++** This file contains code to support the concept of "benign"
++** malloc failures (when the xMalloc() or xRealloc() method of the
++** sqlite3_mem_methods structure fails to allocate a block of memory
++** and returns 0).
++**
++** Most malloc failures are non-benign. After they occur, SQLite
++** abandons the current operation and returns an error code (usually
++** SQLITE_NOMEM) to the user. However, sometimes a fault is not necessarily
++** fatal. For example, if a malloc fails while resizing a hash table, this
++** is completely recoverable simply by not carrying out the resize. The
++** hash table will continue to function normally. So a malloc failure
++** during a hash table resize is a benign fault.
+ */
+
+-#if defined(SQLITE_DEBUG) && !defined(SQLITE_MUTEX_OMIT)
+-/*
+-** For debugging purposes, record when the mutex subsystem is initialized
+-** and uninitialized so that we can assert() if there is an attempt to
+-** allocate a mutex while the system is uninitialized.
+-*/
+-static SQLITE_WSD int mutexIsInit = 0;
+-#endif /* SQLITE_DEBUG */
+
++#ifndef SQLITE_OMIT_BUILTIN_TEST
+
+-#ifndef SQLITE_MUTEX_OMIT
+ /*
+-** Initialize the mutex system.
++** Global variables.
+ */
+-SQLITE_PRIVATE int sqlite3MutexInit(void){
+- int rc = SQLITE_OK;
+- if( !sqlite3GlobalConfig.mutex.xMutexAlloc ){
+- /* If the xMutexAlloc method has not been set, then the user did not
+- ** install a mutex implementation via sqlite3_config() prior to
+- ** sqlite3_initialize() being called. This block copies pointers to
+- ** the default implementation into the sqlite3GlobalConfig structure.
+- */
+- sqlite3_mutex_methods const *pFrom;
+- sqlite3_mutex_methods *pTo = &sqlite3GlobalConfig.mutex;
+-
+- if( sqlite3GlobalConfig.bCoreMutex ){
+- pFrom = sqlite3DefaultMutex();
+- }else{
+- pFrom = sqlite3NoopMutex();
+- }
+- memcpy(pTo, pFrom, offsetof(sqlite3_mutex_methods, xMutexAlloc));
+- memcpy(&pTo->xMutexFree, &pFrom->xMutexFree,
+- sizeof(*pTo) - offsetof(sqlite3_mutex_methods, xMutexFree));
+- pTo->xMutexAlloc = pFrom->xMutexAlloc;
+- }
+- rc = sqlite3GlobalConfig.mutex.xMutexInit();
++typedef struct BenignMallocHooks BenignMallocHooks;
++static SQLITE_WSD struct BenignMallocHooks {
++ void (*xBenignBegin)(void);
++ void (*xBenignEnd)(void);
++} sqlite3Hooks = { 0, 0 };
+
+-#ifdef SQLITE_DEBUG
+- GLOBAL(int, mutexIsInit) = 1;
++/* The "wsdHooks" macro will resolve to the appropriate BenignMallocHooks
++** structure. 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, wsdHooks can refer directly
++** to the "sqlite3Hooks" state vector declared above.
++*/
++#ifdef SQLITE_OMIT_WSD
++# define wsdHooksInit \
++ BenignMallocHooks *x = &GLOBAL(BenignMallocHooks,sqlite3Hooks)
++# define wsdHooks x[0]
++#else
++# define wsdHooksInit
++# define wsdHooks sqlite3Hooks
+ #endif
+
+- return rc;
+-}
+
+ /*
+-** Shutdown the mutex system. This call frees resources allocated by
+-** sqlite3MutexInit().
++** Register hooks to call when sqlite3BeginBenignMalloc() and
++** sqlite3EndBenignMalloc() are called, respectively.
+ */
+-SQLITE_PRIVATE int sqlite3MutexEnd(void){
+- int rc = SQLITE_OK;
+- if( sqlite3GlobalConfig.mutex.xMutexEnd ){
+- rc = sqlite3GlobalConfig.mutex.xMutexEnd();
+- }
+-
+-#ifdef SQLITE_DEBUG
+- GLOBAL(int, mutexIsInit) = 0;
+-#endif
+-
+- return rc;
++SQLITE_PRIVATE void sqlite3BenignMallocHooks(
++ void (*xBenignBegin)(void),
++ void (*xBenignEnd)(void)
++){
++ wsdHooksInit;
++ wsdHooks.xBenignBegin = xBenignBegin;
++ wsdHooks.xBenignEnd = xBenignEnd;
+ }
+
+ /*
+-** Retrieve a pointer to a static mutex or allocate a new dynamic one.
++** This (sqlite3EndBenignMalloc()) is called by SQLite code to indicate that
++** subsequent malloc failures are benign. A call to sqlite3EndBenignMalloc()
++** indicates that subsequent malloc failures are non-benign.
+ */
+-SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int id){
+-#ifndef SQLITE_OMIT_AUTOINIT
+- if( sqlite3_initialize() ) return 0;
+-#endif
+- return sqlite3GlobalConfig.mutex.xMutexAlloc(id);
+-}
+-
+-SQLITE_PRIVATE sqlite3_mutex *sqlite3MutexAlloc(int id){
+- if( !sqlite3GlobalConfig.bCoreMutex ){
+- return 0;
++SQLITE_PRIVATE void sqlite3BeginBenignMalloc(void){
++ wsdHooksInit;
++ if( wsdHooks.xBenignBegin ){
++ wsdHooks.xBenignBegin();
+ }
+- assert( GLOBAL(int, mutexIsInit) );
+- return sqlite3GlobalConfig.mutex.xMutexAlloc(id);
+ }
+-
+-/*
+-** Free a dynamic mutex.
+-*/
+-SQLITE_API void sqlite3_mutex_free(sqlite3_mutex *p){
+- if( p ){
+- sqlite3GlobalConfig.mutex.xMutexFree(p);
++SQLITE_PRIVATE void sqlite3EndBenignMalloc(void){
++ wsdHooksInit;
++ if( wsdHooks.xBenignEnd ){
++ wsdHooks.xBenignEnd();
+ }
+ }
+
++#endif /* #ifndef SQLITE_OMIT_BUILTIN_TEST */
++
++/************** End of fault.c ***********************************************/
++/************** Begin file mem0.c ********************************************/
+ /*
+-** Obtain the mutex p. If some other thread already has the mutex, block
+-** until it can be obtained.
++** 2008 October 28
++**
++** 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 a no-op memory allocation drivers for use when
++** SQLITE_ZERO_MALLOC is defined. The allocation drivers implemented
++** here always fail. SQLite will not operate with these drivers. These
++** are merely placeholders. Real drivers must be substituted using
++** sqlite3_config() before SQLite will operate.
+ */
+-SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex *p){
+- if( p ){
+- sqlite3GlobalConfig.mutex.xMutexEnter(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.
++** This version of the memory allocator is the default. It is
++** used when no other memory allocator is specified using compile-time
++** macros.
+ */
+-SQLITE_API int sqlite3_mutex_try(sqlite3_mutex *p){
+- int rc = SQLITE_OK;
+- if( p ){
+- return sqlite3GlobalConfig.mutex.xMutexTry(p);
+- }
+- return rc;
+-}
++#ifdef SQLITE_ZERO_MALLOC
+
+ /*
+-** The sqlite3_mutex_leave() routine exits a mutex that was previously
+-** entered by the same thread. The behavior is undefined if the mutex
+-** is not currently entered. If a NULL pointer is passed as an argument
+-** this function is a no-op.
++** No-op versions of all memory allocation routines
+ */
+-SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex *p){
+- if( p ){
+- sqlite3GlobalConfig.mutex.xMutexLeave(p);
+- }
+-}
++static void *sqlite3MemMalloc(int nByte){ return 0; }
++static void sqlite3MemFree(void *pPrior){ return; }
++static void *sqlite3MemRealloc(void *pPrior, int nByte){ return 0; }
++static int sqlite3MemSize(void *pPrior){ return 0; }
++static int sqlite3MemRoundup(int n){ return n; }
++static int sqlite3MemInit(void *NotUsed){ return SQLITE_OK; }
++static void sqlite3MemShutdown(void *NotUsed){ return; }
+
+-#ifndef NDEBUG
+ /*
+-** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
+-** intended for use inside assert() statements.
++** This routine is the only routine in this file with external linkage.
++**
++** Populate the low-level memory allocation function pointers in
++** sqlite3GlobalConfig.m with pointers to the routines in this file.
+ */
+-SQLITE_API int sqlite3_mutex_held(sqlite3_mutex *p){
+- return p==0 || sqlite3GlobalConfig.mutex.xMutexHeld(p);
+-}
+-SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex *p){
+- return p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld(p);
++SQLITE_PRIVATE void sqlite3MemSetDefault(void){
++ static const sqlite3_mem_methods defaultMethods = {
++ sqlite3MemMalloc,
++ sqlite3MemFree,
++ sqlite3MemRealloc,
++ sqlite3MemSize,
++ sqlite3MemRoundup,
++ sqlite3MemInit,
++ sqlite3MemShutdown,
++ 0
++ };
++ sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods);
+ }
+-#endif
+
+-#endif /* !defined(SQLITE_MUTEX_OMIT) */
++#endif /* SQLITE_ZERO_MALLOC */
+
+-/************** End of mutex.c ***********************************************/
+-/************** Begin file mutex_noop.c **************************************/
++/************** End of mem0.c ************************************************/
++/************** Begin file mem1.c ********************************************/
+ /*
+-** 2008 October 07
++** 2007 August 14
+ **
+ ** The author disclaims copyright to this source code. In place of
+ ** a legal notice, here is a blessing:
+@@ -17870,205 +18601,278 @@
+ ** May you share freely, never taking more than you give.
+ **
+ *************************************************************************
+-** This file contains the C functions that implement mutexes.
+ **
+-** This implementation in this file does not provide any mutual
+-** exclusion and is thus suitable for use only in applications
+-** that use SQLite in a single thread. The routines defined
+-** here are place-holders. Applications can substitute working
+-** mutex routines at start-time using the
++** This file contains low-level memory allocation drivers for when
++** SQLite will use the standard C-library malloc/realloc/free interface
++** to obtain the memory it needs.
+ **
+-** sqlite3_config(SQLITE_CONFIG_MUTEX,...)
++** This file contains implementations of the low-level memory allocation
++** routines specified in the sqlite3_mem_methods object. The content of
++** this file is only used if SQLITE_SYSTEM_MALLOC is defined. The
++** SQLITE_SYSTEM_MALLOC macro is defined automatically if neither the
++** SQLITE_MEMDEBUG nor the SQLITE_WIN32_MALLOC macros are defined. The
++** default configuration is to use memory allocation routines in this
++** file.
+ **
+-** interface.
++** C-preprocessor macro summary:
+ **
+-** If compiled with SQLITE_DEBUG, then additional logic is inserted
+-** that does error checking on mutexes to make sure they are being
+-** called correctly.
++** HAVE_MALLOC_USABLE_SIZE The configure script sets this symbol if
++** the malloc_usable_size() interface exists
++** on the target platform. Or, this symbol
++** can be set manually, if desired.
++** If an equivalent interface exists by
++** a different name, using a separate -D
++** option to rename it.
++**
++** SQLITE_WITHOUT_ZONEMALLOC Some older macs lack support for the zone
++** memory allocator. Set this symbol to enable
++** building on older macs.
++**
++** SQLITE_WITHOUT_MSIZE Set this symbol to disable the use of
++** _msize() on windows systems. This might
++** be necessary when compiling for Delphi,
++** for example.
+ */
+
+-#ifndef SQLITE_MUTEX_OMIT
++/*
++** This version of the memory allocator is the default. It is
++** used when no other memory allocator is specified using compile-time
++** macros.
++*/
++#ifdef SQLITE_SYSTEM_MALLOC
+
+-#ifndef SQLITE_DEBUG
+ /*
+-** Stub routines for all mutex methods.
+-**
+-** This routines provide no mutual exclusion or error checking.
++** The MSVCRT has malloc_usable_size() but it is called _msize().
++** The use of _msize() is automatic, but can be disabled by compiling
++** with -DSQLITE_WITHOUT_MSIZE
+ */
+-static int noopMutexInit(void){ return SQLITE_OK; }
+-static int noopMutexEnd(void){ return SQLITE_OK; }
+-static sqlite3_mutex *noopMutexAlloc(int id){
+- UNUSED_PARAMETER(id);
+- return (sqlite3_mutex*)8;
+-}
+-static void noopMutexFree(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; }
+-static void noopMutexEnter(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; }
+-static int noopMutexTry(sqlite3_mutex *p){
+- UNUSED_PARAMETER(p);
+- return SQLITE_OK;
+-}
+-static void noopMutexLeave(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; }
++#if defined(_MSC_VER) && !defined(SQLITE_WITHOUT_MSIZE)
++# define SQLITE_MALLOCSIZE _msize
++#endif
+
+-SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3NoopMutex(void){
+- static const sqlite3_mutex_methods sMutex = {
+- noopMutexInit,
+- noopMutexEnd,
+- noopMutexAlloc,
+- noopMutexFree,
+- noopMutexEnter,
+- noopMutexTry,
+- noopMutexLeave,
++#if defined(__APPLE__) && !defined(SQLITE_WITHOUT_ZONEMALLOC)
+
+- 0,
+- 0,
+- };
++/*
++** Use the zone allocator available on apple products unless the
++** SQLITE_WITHOUT_ZONEMALLOC symbol is defined.
++*/
++#include <sys/sysctl.h>
++#include <malloc/malloc.h>
++#include <libkern/OSAtomic.h>
++static malloc_zone_t* _sqliteZone_;
++#define SQLITE_MALLOC(x) malloc_zone_malloc(_sqliteZone_, (x))
++#define SQLITE_FREE(x) malloc_zone_free(_sqliteZone_, (x));
++#define SQLITE_REALLOC(x,y) malloc_zone_realloc(_sqliteZone_, (x), (y))
++#define SQLITE_MALLOCSIZE(x) \
++ (_sqliteZone_ ? _sqliteZone_->size(_sqliteZone_,x) : malloc_size(x))
+
+- return &sMutex;
+-}
+-#endif /* !SQLITE_DEBUG */
++#else /* if not __APPLE__ */
+
+-#ifdef SQLITE_DEBUG
+ /*
+-** In this implementation, error checking is provided for testing
+-** and debugging purposes. The mutexes still do not provide any
+-** mutual exclusion.
++** Use standard C library malloc and free on non-Apple systems.
++** Also used by Apple systems if SQLITE_WITHOUT_ZONEMALLOC is defined.
+ */
++#define SQLITE_MALLOC(x) malloc(x)
++#define SQLITE_FREE(x) free(x)
++#define SQLITE_REALLOC(x,y) realloc((x),(y))
++
++#if (defined(_MSC_VER) && !defined(SQLITE_WITHOUT_MSIZE)) \
++ || (defined(HAVE_MALLOC_H) && defined(HAVE_MALLOC_USABLE_SIZE))
++# include <malloc.h> /* Needed for malloc_usable_size on linux */
++#endif
++#ifdef HAVE_MALLOC_USABLE_SIZE
++# ifndef SQLITE_MALLOCSIZE
++# define SQLITE_MALLOCSIZE(x) malloc_usable_size(x)
++# endif
++#else
++# undef SQLITE_MALLOCSIZE
++#endif
++
++#endif /* __APPLE__ or not __APPLE__ */
+
+ /*
+-** The mutex object
++** Like malloc(), but remember the size of the allocation
++** so that we can find it later using sqlite3MemSize().
++**
++** For this low-level routine, we are guaranteed that nByte>0 because
++** cases of nByte<=0 will be intercepted and dealt with by higher level
++** routines.
+ */
+-typedef struct sqlite3_debug_mutex {
+- int id; /* The mutex type */
+- int cnt; /* Number of entries without a matching leave */
+-} sqlite3_debug_mutex;
++static void *sqlite3MemMalloc(int nByte){
++#ifdef SQLITE_MALLOCSIZE
++ void *p = SQLITE_MALLOC( nByte );
++ if( p==0 ){
++ testcase( sqlite3GlobalConfig.xLog!=0 );
++ sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes of memory", nByte);
++ }
++ return p;
++#else
++ sqlite3_int64 *p;
++ assert( nByte>0 );
++ nByte = ROUND8(nByte);
++ p = SQLITE_MALLOC( nByte+8 );
++ if( p ){
++ p[0] = nByte;
++ p++;
++ }else{
++ testcase( sqlite3GlobalConfig.xLog!=0 );
++ sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes of memory", nByte);
++ }
++ return (void *)p;
++#endif
++}
+
+ /*
+-** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
+-** intended for use inside assert() statements.
++** Like free() but works for allocations obtained from sqlite3MemMalloc()
++** or sqlite3MemRealloc().
++**
++** For this low-level routine, we already know that pPrior!=0 since
++** cases where pPrior==0 will have been intecepted and dealt with
++** by higher-level routines.
+ */
+-static int debugMutexHeld(sqlite3_mutex *pX){
+- sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
+- return p==0 || p->cnt>0;
+-}
+-static int debugMutexNotheld(sqlite3_mutex *pX){
+- sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
+- return p==0 || p->cnt==0;
++static void sqlite3MemFree(void *pPrior){
++#ifdef SQLITE_MALLOCSIZE
++ SQLITE_FREE(pPrior);
++#else
++ sqlite3_int64 *p = (sqlite3_int64*)pPrior;
++ assert( pPrior!=0 );
++ p--;
++ SQLITE_FREE(p);
++#endif
+ }
+
+ /*
+-** Initialize and deinitialize the mutex subsystem.
++** Report the allocated size of a prior return from xMalloc()
++** or xRealloc().
+ */
+-static int debugMutexInit(void){ return SQLITE_OK; }
+-static int debugMutexEnd(void){ return SQLITE_OK; }
++static int sqlite3MemSize(void *pPrior){
++#ifdef SQLITE_MALLOCSIZE
++ return pPrior ? (int)SQLITE_MALLOCSIZE(pPrior) : 0;
++#else
++ sqlite3_int64 *p;
++ if( pPrior==0 ) return 0;
++ p = (sqlite3_int64*)pPrior;
++ p--;
++ return (int)p[0];
++#endif
++}
+
+ /*
+-** 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.
++** Like realloc(). Resize an allocation previously obtained from
++** sqlite3MemMalloc().
++**
++** 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
++** cases where nByte<=0 will have been intercepted by higher-level
++** routines and redirected to xFree.
+ */
+-static sqlite3_mutex *debugMutexAlloc(int id){
+- static sqlite3_debug_mutex aStatic[6];
+- sqlite3_debug_mutex *pNew = 0;
+- switch( id ){
+- case SQLITE_MUTEX_FAST:
+- case SQLITE_MUTEX_RECURSIVE: {
+- pNew = sqlite3Malloc(sizeof(*pNew));
+- if( pNew ){
+- pNew->id = id;
+- pNew->cnt = 0;
+- }
+- break;
+- }
+- default: {
+- assert( id-2 >= 0 );
+- assert( id-2 < (int)(sizeof(aStatic)/sizeof(aStatic[0])) );
+- pNew = &aStatic[id-2];
+- pNew->id = id;
+- break;
+- }
++static void *sqlite3MemRealloc(void *pPrior, int nByte){
++#ifdef SQLITE_MALLOCSIZE
++ void *p = SQLITE_REALLOC(pPrior, nByte);
++ if( p==0 ){
++ testcase( sqlite3GlobalConfig.xLog!=0 );
++ sqlite3_log(SQLITE_NOMEM,
++ "failed memory resize %u to %u bytes",
++ SQLITE_MALLOCSIZE(pPrior), nByte);
+ }
+- return (sqlite3_mutex*)pNew;
++ return p;
++#else
++ sqlite3_int64 *p = (sqlite3_int64*)pPrior;
++ assert( pPrior!=0 && nByte>0 );
++ assert( nByte==ROUND8(nByte) ); /* EV: R-46199-30249 */
++ p--;
++ p = SQLITE_REALLOC(p, nByte+8 );
++ if( p ){
++ p[0] = nByte;
++ p++;
++ }else{
++ testcase( sqlite3GlobalConfig.xLog!=0 );
++ sqlite3_log(SQLITE_NOMEM,
++ "failed memory resize %u to %u bytes",
++ sqlite3MemSize(pPrior), nByte);
++ }
++ return (void*)p;
++#endif
+ }
+
+ /*
+-** This routine deallocates a previously allocated mutex.
++** Round up a request size to the next valid allocation size.
+ */
+-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);
++static int sqlite3MemRoundup(int n){
++ return ROUND8(n);
+ }
+
+ /*
+-** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
+-** to enter a mutex. If another thread is already within the mutex,
+-** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return
+-** 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,
+-** 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.
++** Initialize this module.
+ */
+-static void debugMutexEnter(sqlite3_mutex *pX){
+- sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
+- assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) );
+- p->cnt++;
+-}
+-static int debugMutexTry(sqlite3_mutex *pX){
+- sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
+- assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) );
+- p->cnt++;
++static int sqlite3MemInit(void *NotUsed){
++#if defined(__APPLE__) && !defined(SQLITE_WITHOUT_ZONEMALLOC)
++ int cpuCount;
++ size_t len;
++ if( _sqliteZone_ ){
++ return SQLITE_OK;
++ }
++ len = sizeof(cpuCount);
++ /* One usually wants to use hw.acctivecpu for MT decisions, but not here */
++ sysctlbyname("hw.ncpu", &cpuCount, &len, NULL, 0);
++ if( cpuCount>1 ){
++ /* defer MT decisions to system malloc */
++ _sqliteZone_ = malloc_default_zone();
++ }else{
++ /* only 1 core, use our own zone to contention over global locks,
++ ** e.g. we have our own dedicated locks */
++ bool success;
++ malloc_zone_t* newzone = malloc_create_zone(4096, 0);
++ malloc_set_zone_name(newzone, "Sqlite_Heap");
++ do{
++ success = OSAtomicCompareAndSwapPtrBarrier(NULL, newzone,
++ (void * volatile *)&_sqliteZone_);
++ }while(!_sqliteZone_);
++ if( !success ){
++ /* somebody registered a zone first */
++ malloc_destroy_zone(newzone);
++ }
++ }
++#endif
++ UNUSED_PARAMETER(NotUsed);
+ return SQLITE_OK;
+ }
+
+ /*
+-** The sqlite3_mutex_leave() routine exits a mutex that was
+-** previously entered by the same thread. The behavior
+-** is undefined if the mutex is not currently entered or
+-** is not currently allocated. SQLite will never do either.
++** Deinitialize this module.
+ */
+-static void debugMutexLeave(sqlite3_mutex *pX){
+- sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
+- assert( debugMutexHeld(pX) );
+- p->cnt--;
+- assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) );
+-}
+-
+-SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3NoopMutex(void){
+- static const sqlite3_mutex_methods sMutex = {
+- debugMutexInit,
+- debugMutexEnd,
+- debugMutexAlloc,
+- debugMutexFree,
+- debugMutexEnter,
+- debugMutexTry,
+- debugMutexLeave,
+-
+- debugMutexHeld,
+- debugMutexNotheld
+- };
+-
+- return &sMutex;
++static void sqlite3MemShutdown(void *NotUsed){
++ UNUSED_PARAMETER(NotUsed);
++ return;
+ }
+-#endif /* SQLITE_DEBUG */
+
+ /*
+-** If compiled with SQLITE_MUTEX_NOOP, then the no-op mutex implementation
+-** is used regardless of the run-time threadsafety setting.
++** This routine is the only routine in this file with external linkage.
++**
++** Populate the low-level memory allocation function pointers in
++** sqlite3GlobalConfig.m with pointers to the routines in this file.
+ */
+-#ifdef SQLITE_MUTEX_NOOP
+-SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
+- return sqlite3NoopMutex();
++SQLITE_PRIVATE void sqlite3MemSetDefault(void){
++ static const sqlite3_mem_methods defaultMethods = {
++ sqlite3MemMalloc,
++ sqlite3MemFree,
++ sqlite3MemRealloc,
++ sqlite3MemSize,
++ sqlite3MemRoundup,
++ sqlite3MemInit,
++ sqlite3MemShutdown,
++ 0
++ };
++ sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods);
+ }
+-#endif /* defined(SQLITE_MUTEX_NOOP) */
+-#endif /* !defined(SQLITE_MUTEX_OMIT) */
+
+-/************** End of mutex_noop.c ******************************************/
+-/************** Begin file mutex_unix.c **************************************/
++#endif /* SQLITE_SYSTEM_MALLOC */
++
++/************** End of mem1.c ************************************************/
++/************** Begin file mem2.c ********************************************/
+ /*
+-** 2007 August 28
++** 2007 August 15
+ **
+ ** The author disclaims copyright to this source code. In place of
+ ** a legal notice, here is a blessing:
+@@ -18078,694 +18882,527 @@
+ ** May you share freely, never taking more than you give.
+ **
+ *************************************************************************
+-** This file contains the C functions that implement mutexes for pthreads
++**
++** This file contains low-level memory allocation drivers for when
++** SQLite will use the standard C-library malloc/realloc/free interface
++** to obtain the memory it needs while adding lots of additional debugging
++** information to each allocation in order to help detect and fix memory
++** leaks and memory usage errors.
++**
++** This file contains implementations of the low-level memory allocation
++** routines specified in the sqlite3_mem_methods object.
+ */
+
+ /*
+-** The code in this file is only used if we are compiling threadsafe
+-** under unix with pthreads.
+-**
+-** Note that this implementation requires a version of pthreads that
+-** supports recursive mutexes.
++** This version of the memory allocator is used only if the
++** SQLITE_MEMDEBUG macro is defined
+ */
+-#ifdef SQLITE_MUTEX_PTHREADS
+-
+-#include <pthread.h>
++#ifdef SQLITE_MEMDEBUG
+
+ /*
+-** The sqlite3_mutex.id, sqlite3_mutex.nRef, and sqlite3_mutex.owner fields
+-** are necessary under two condidtions: (1) Debug builds and (2) using
+-** home-grown mutexes. Encapsulate these conditions into a single #define.
++** The backtrace functionality is only available with GLIBC
+ */
+-#if defined(SQLITE_DEBUG) || defined(SQLITE_HOMEGROWN_RECURSIVE_MUTEX)
+-# define SQLITE_MUTEX_NREF 1
+-#else
+-# define SQLITE_MUTEX_NREF 0
+-#endif
+-
+-/*
+-** Each recursive mutex is an instance of the following structure.
+-*/
+-struct sqlite3_mutex {
+- pthread_mutex_t mutex; /* Mutex controlling the lock */
+-#if SQLITE_MUTEX_NREF
+- int id; /* Mutex type */
+- volatile int nRef; /* Number of entrances */
+- volatile pthread_t owner; /* Thread that is within this mutex */
+- int trace; /* True to trace changes */
+-#endif
+-};
+-#if SQLITE_MUTEX_NREF
+-#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, 0, 0, (pthread_t)0, 0 }
++#ifdef __GLIBC__
++ extern int backtrace(void**,int);
++ extern void backtrace_symbols_fd(void*const*,int,int);
+ #else
+-#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER }
++# define backtrace(A,B) 1
++# define backtrace_symbols_fd(A,B,C)
+ #endif
++/* #include <stdio.h> */
+
+ /*
+-** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
+-** intended for use only inside assert() statements. On some platforms,
+-** there might be race conditions that can cause these routines to
+-** deliver incorrect results. In particular, if pthread_equal() is
+-** not an atomic operation, then these routines might delivery
+-** incorrect results. On most platforms, pthread_equal() is a
+-** comparison of two integers and is therefore atomic. But we are
+-** told that HPUX is not such a platform. If so, then these routines
+-** will not always work correctly on HPUX.
++** Each memory allocation looks like this:
+ **
+-** On those platforms where pthread_equal() is not atomic, SQLite
+-** should be compiled without -DSQLITE_DEBUG and with -DNDEBUG to
+-** make sure no assert() statements are evaluated and hence these
+-** routines are never called.
+-*/
+-#if !defined(NDEBUG) || defined(SQLITE_DEBUG)
+-static int pthreadMutexHeld(sqlite3_mutex *p){
+- return (p->nRef!=0 && pthread_equal(p->owner, pthread_self()));
+-}
+-static int pthreadMutexNotheld(sqlite3_mutex *p){
+- return p->nRef==0 || pthread_equal(p->owner, pthread_self())==0;
+-}
+-#endif
+-
+-/*
+-** Initialize and deinitialize the mutex subsystem.
++** ------------------------------------------------------------------------
++** | Title | backtrace pointers | MemBlockHdr | allocation | EndGuard |
++** ------------------------------------------------------------------------
++**
++** The application code sees only a pointer to the allocation. We have
++** to back up from the allocation pointer to find the MemBlockHdr. The
++** MemBlockHdr tells us the size of the allocation and the number of
++** backtrace pointers. There is also a guard word at the end of the
++** MemBlockHdr.
+ */
+-static int pthreadMutexInit(void){ return SQLITE_OK; }
+-static int pthreadMutexEnd(void){ return SQLITE_OK; }
++struct MemBlockHdr {
++ i64 iSize; /* Size of this allocation */
++ struct MemBlockHdr *pNext, *pPrev; /* Linked list of all unfreed memory */
++ char nBacktrace; /* Number of backtraces on this alloc */
++ char nBacktraceSlots; /* Available backtrace slots */
++ u8 nTitle; /* Bytes of title; includes '\0' */
++ u8 eType; /* Allocation type code */
++ int iForeGuard; /* Guard word for sanity */
++};
+
+ /*
+-** 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:
+-**
+-** <ul>
+-** <li> SQLITE_MUTEX_FAST
+-** <li> SQLITE_MUTEX_RECURSIVE
+-** <li> SQLITE_MUTEX_STATIC_MASTER
+-** <li> SQLITE_MUTEX_STATIC_MEM
+-** <li> SQLITE_MUTEX_STATIC_MEM2
+-** <li> SQLITE_MUTEX_STATIC_PRNG
+-** <li> SQLITE_MUTEX_STATIC_LRU
+-** <li> SQLITE_MUTEX_STATIC_PMEM
+-** </ul>
+-**
+-** The first two constants cause sqlite3_mutex_alloc() to create
+-** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
+-** 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. But 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() each return
+-** a pointer to a static preexisting mutex. Six 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
+-** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or
+-** SQLITE_MUTEX_RECURSIVE.
+-**
+-** 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
+-** mutex types, the same mutex is returned on every call that has
+-** the same type number.
++** Guard words
+ */
+-static sqlite3_mutex *pthreadMutexAlloc(int iType){
+- static sqlite3_mutex staticMutexes[] = {
+- SQLITE3_MUTEX_INITIALIZER,
+- SQLITE3_MUTEX_INITIALIZER,
+- SQLITE3_MUTEX_INITIALIZER,
+- SQLITE3_MUTEX_INITIALIZER,
+- SQLITE3_MUTEX_INITIALIZER,
+- SQLITE3_MUTEX_INITIALIZER
+- };
+- sqlite3_mutex *p;
+- switch( iType ){
+- case SQLITE_MUTEX_RECURSIVE: {
+- p = sqlite3MallocZero( sizeof(*p) );
+- if( p ){
+-#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
+- /* If recursive mutexes are not available, we will have to
+- ** build our own. See below. */
+- pthread_mutex_init(&p->mutex, 0);
+-#else
+- /* Use a recursive mutex if it is available */
+- pthread_mutexattr_t recursiveAttr;
+- pthread_mutexattr_init(&recursiveAttr);
+- pthread_mutexattr_settype(&recursiveAttr, PTHREAD_MUTEX_RECURSIVE);
+- 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;
+-#endif
+- break;
+- }
+- }
+- return p;
+-}
+-
++#define FOREGUARD 0x80F5E153
++#define REARGUARD 0xE4676B53
+
+ /*
+-** This routine deallocates a previously
+-** allocated mutex. SQLite is careful to deallocate every
+-** mutex that it allocates.
++** Number of malloc size increments to track.
+ */
+-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);
+-}
++#define NCSIZE 1000
+
+ /*
+-** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
+-** to enter a mutex. If another thread is already within the mutex,
+-** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return
+-** 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,
+-** 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.
++** All of the static variables used by this module are collected
++** into a single structure named "mem". This is to keep the
++** static variables organized and to reduce namespace pollution
++** when this module is combined with other in the amalgamation.
+ */
+-static void pthreadMutexEnter(sqlite3_mutex *p){
+- assert( p->id==SQLITE_MUTEX_RECURSIVE || pthreadMutexNotheld(p) );
++static struct {
++
++ /*
++ ** Mutex to control access to the memory allocation subsystem.
++ */
++ sqlite3_mutex *mutex;
+
+-#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
+- /* If recursive mutexes are not available, then we have to grow
+- ** our own. This implementation assumes that pthread_equal()
+- ** is atomic - that it cannot be deceived into thinking self
+- ** and p->owner are equal if p->owner changes between two values
+- ** that are not equal to self while the comparison is taking place.
+- ** This implementation also assumes a coherent cache - that
+- ** separate processes cannot read different values from the same
+- ** address at the same time. If either of these two conditions
+- ** are not met, then the mutexes will fail and problems will result.
++ /*
++ ** Head and tail of a linked list of all outstanding allocations
+ */
+- {
+- pthread_t self = pthread_self();
+- if( p->nRef>0 && pthread_equal(p->owner, self) ){
+- p->nRef++;
+- }else{
+- pthread_mutex_lock(&p->mutex);
+- assert( p->nRef==0 );
+- p->owner = self;
+- p->nRef = 1;
+- }
+- }
+-#else
+- /* Use the built-in recursive mutexes if they are available.
++ struct MemBlockHdr *pFirst;
++ struct MemBlockHdr *pLast;
++
++ /*
++ ** The number of levels of backtrace to save in new allocations.
+ */
+- pthread_mutex_lock(&p->mutex);
+-#if SQLITE_MUTEX_NREF
+- assert( p->nRef>0 || p->owner==0 );
+- p->owner = pthread_self();
+- p->nRef++;
+-#endif
+-#endif
++ int nBacktrace;
++ void (*xBacktrace)(int, int, void **);
+
+-#ifdef SQLITE_DEBUG
+- if( p->trace ){
+- printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
+- }
+-#endif
+-}
+-static int pthreadMutexTry(sqlite3_mutex *p){
+- int rc;
+- assert( p->id==SQLITE_MUTEX_RECURSIVE || pthreadMutexNotheld(p) );
++ /*
++ ** Title text to insert in front of each block
++ */
++ int nTitle; /* Bytes of zTitle to save. Includes '\0' and padding */
++ char zTitle[100]; /* The title text */
+
+-#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
+- /* If recursive mutexes are not available, then we have to grow
+- ** our own. This implementation assumes that pthread_equal()
+- ** is atomic - that it cannot be deceived into thinking self
+- ** and p->owner are equal if p->owner changes between two values
+- ** that are not equal to self while the comparison is taking place.
+- ** This implementation also assumes a coherent cache - that
+- ** separate processes cannot read different values from the same
+- ** address at the same time. If either of these two conditions
+- ** are not met, then the mutexes will fail and problems will result.
++ /*
++ ** sqlite3MallocDisallow() increments the following counter.
++ ** sqlite3MallocAllow() decrements it.
+ */
+- {
+- pthread_t self = pthread_self();
+- if( p->nRef>0 && pthread_equal(p->owner, self) ){
+- p->nRef++;
+- rc = SQLITE_OK;
+- }else if( pthread_mutex_trylock(&p->mutex)==0 ){
+- assert( p->nRef==0 );
+- p->owner = self;
+- p->nRef = 1;
+- rc = SQLITE_OK;
+- }else{
+- rc = SQLITE_BUSY;
+- }
+- }
+-#else
+- /* Use the built-in recursive mutexes if they are available.
++ int disallow; /* Do not allow memory allocation */
++
++ /*
++ ** Gather statistics on the sizes of memory allocations.
++ ** nAlloc[i] is the number of allocation attempts of i*8
++ ** bytes. i==NCSIZE is the number of allocation attempts for
++ ** sizes more than NCSIZE*8 bytes.
+ */
+- if( pthread_mutex_trylock(&p->mutex)==0 ){
+-#if SQLITE_MUTEX_NREF
+- p->owner = pthread_self();
+- p->nRef++;
+-#endif
+- rc = SQLITE_OK;
+- }else{
+- rc = SQLITE_BUSY;
+- }
+-#endif
++ int nAlloc[NCSIZE]; /* Total number of allocations */
++ int nCurrent[NCSIZE]; /* Current number of allocations */
++ int mxCurrent[NCSIZE]; /* Highwater mark for nCurrent */
++
++} mem;
+
+-#ifdef SQLITE_DEBUG
+- if( rc==SQLITE_OK && p->trace ){
+- printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
+- }
+-#endif
+- return rc;
+-}
+
+ /*
+-** The sqlite3_mutex_leave() routine exits a mutex that was
+-** previously entered by the same thread. The behavior
+-** is undefined if the mutex is not currently entered or
+-** is not currently allocated. SQLite will never do either.
++** Adjust memory usage statistics
+ */
+-static void pthreadMutexLeave(sqlite3_mutex *p){
+- assert( pthreadMutexHeld(p) );
+-#if SQLITE_MUTEX_NREF
+- p->nRef--;
+- if( p->nRef==0 ) p->owner = 0;
+-#endif
+- assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
+-
+-#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
+- if( p->nRef==0 ){
+- pthread_mutex_unlock(&p->mutex);
++static void adjustStats(int iSize, int increment){
++ int i = ROUND8(iSize)/8;
++ if( i>NCSIZE-1 ){
++ i = NCSIZE - 1;
+ }
+-#else
+- pthread_mutex_unlock(&p->mutex);
+-#endif
+-
+-#ifdef SQLITE_DEBUG
+- if( p->trace ){
+- printf("leave mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
++ if( increment>0 ){
++ mem.nAlloc[i]++;
++ mem.nCurrent[i]++;
++ if( mem.nCurrent[i]>mem.mxCurrent[i] ){
++ mem.mxCurrent[i] = mem.nCurrent[i];
++ }
++ }else{
++ mem.nCurrent[i]--;
++ assert( mem.nCurrent[i]>=0 );
+ }
+-#endif
+-}
+-
+-SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
+- static const sqlite3_mutex_methods sMutex = {
+- pthreadMutexInit,
+- pthreadMutexEnd,
+- pthreadMutexAlloc,
+- pthreadMutexFree,
+- pthreadMutexEnter,
+- pthreadMutexTry,
+- pthreadMutexLeave,
+-#ifdef SQLITE_DEBUG
+- pthreadMutexHeld,
+- pthreadMutexNotheld
+-#else
+- 0,
+- 0
+-#endif
+- };
+-
+- return &sMutex;
+ }
+
+-#endif /* SQLITE_MUTEX_PTHREADS */
+-
+-/************** End of mutex_unix.c ******************************************/
+-/************** Begin file mutex_w32.c ***************************************/
+ /*
+-** 2007 August 14
+-**
+-** The author disclaims copyright to this source code. In place of
+-** a legal notice, here is a blessing:
+-**
+-** May you do good and not evil.
+-** May you find forgiveness for yourself and forgive others.
+-** May you share freely, never taking more than you give.
++** Given an allocation, find the MemBlockHdr for that allocation.
+ **
+-*************************************************************************
+-** This file contains the C functions that implement mutexes for win32
++** This routine checks the guards at either end of the allocation and
++** if they are incorrect it asserts.
+ */
++static struct MemBlockHdr *sqlite3MemsysGetHeader(void *pAllocation){
++ struct MemBlockHdr *p;
++ int *pInt;
++ u8 *pU8;
++ int nReserve;
+
+-/*
+-** The code in this file is only used if we are compiling multithreaded
+-** on a win32 system.
+-*/
+-#ifdef SQLITE_MUTEX_W32
++ p = (struct MemBlockHdr*)pAllocation;
++ p--;
++ assert( p->iForeGuard==(int)FOREGUARD );
++ nReserve = ROUND8(p->iSize);
++ pInt = (int*)pAllocation;
++ pU8 = (u8*)pAllocation;
++ assert( pInt[nReserve/sizeof(int)]==(int)REARGUARD );
++ /* This checks any of the "extra" bytes allocated due
++ ** to rounding up to an 8 byte boundary to ensure
++ ** they haven't been overwritten.
++ */
++ while( nReserve-- > p->iSize ) assert( pU8[nReserve]==0x65 );
++ return p;
++}
+
+ /*
+-** Each recursive mutex is an instance of the following structure.
++** Return the number of bytes currently allocated at address p.
+ */
+-struct sqlite3_mutex {
+- CRITICAL_SECTION mutex; /* Mutex controlling the lock */
+- int id; /* Mutex type */
+-#ifdef SQLITE_DEBUG
+- volatile int nRef; /* Number of enterances */
+- volatile DWORD owner; /* Thread holding this mutex */
+- int trace; /* True to trace changes */
+-#endif
+-};
+-#define SQLITE_W32_MUTEX_INITIALIZER { 0 }
+-#ifdef SQLITE_DEBUG
+-#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0, 0L, (DWORD)0, 0 }
+-#else
+-#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0 }
+-#endif
++static int sqlite3MemSize(void *p){
++ struct MemBlockHdr *pHdr;
++ if( !p ){
++ return 0;
++ }
++ pHdr = sqlite3MemsysGetHeader(p);
++ return pHdr->iSize;
++}
+
+ /*
+-** 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 win 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.
+-**
+-** mutexIsNT() is only used for the TryEnterCriticalSection() API call,
+-** which is only available if your application was compiled with
+-** _WIN32_WINNT defined to a value >= 0x0400. Currently, the only
+-** call to TryEnterCriticalSection() is #ifdef'ed out, so #ifdef
+-** this out as well.
++** Initialize the memory allocation subsystem.
+ */
+-#if 0
+-#if SQLITE_OS_WINCE || SQLITE_OS_WINRT
+-# define mutexIsNT() (1)
+-#else
+- static int mutexIsNT(void){
+- static int osType = 0;
+- if( osType==0 ){
+- OSVERSIONINFO sInfo;
+- sInfo.dwOSVersionInfoSize = sizeof(sInfo);
+- GetVersionEx(&sInfo);
+- osType = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1;
+- }
+- return osType==2;
++static int sqlite3MemInit(void *NotUsed){
++ UNUSED_PARAMETER(NotUsed);
++ assert( (sizeof(struct MemBlockHdr)&7) == 0 );
++ if( !sqlite3GlobalConfig.bMemstat ){
++ /* If memory status is enabled, then the malloc.c wrapper will already
++ ** hold the STATIC_MEM mutex when the routines here are invoked. */
++ mem.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
+ }
+-#endif /* SQLITE_OS_WINCE */
+-#endif
++ return SQLITE_OK;
++}
+
+-#ifdef SQLITE_DEBUG
+ /*
+-** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
+-** intended for use only inside assert() statements.
++** Deinitialize the memory allocation subsystem.
+ */
+-static int winMutexHeld(sqlite3_mutex *p){
+- return p->nRef!=0 && p->owner==GetCurrentThreadId();
+-}
+-static int winMutexNotheld2(sqlite3_mutex *p, DWORD tid){
+- return p->nRef==0 || p->owner!=tid;
+-}
+-static int winMutexNotheld(sqlite3_mutex *p){
+- DWORD tid = GetCurrentThreadId();
+- return winMutexNotheld2(p, tid);
++static void sqlite3MemShutdown(void *NotUsed){
++ UNUSED_PARAMETER(NotUsed);
++ mem.mutex = 0;
+ }
+-#endif
+-
+
+ /*
+-** Initialize and deinitialize the mutex subsystem.
+-*/
+-static sqlite3_mutex winMutex_staticMutexes[6] = {
+- SQLITE3_MUTEX_INITIALIZER,
+- SQLITE3_MUTEX_INITIALIZER,
+- SQLITE3_MUTEX_INITIALIZER,
+- SQLITE3_MUTEX_INITIALIZER,
+- SQLITE3_MUTEX_INITIALIZER,
+- SQLITE3_MUTEX_INITIALIZER
+-};
+-static int winMutex_isInit = 0;
+-/* As winMutexInit() and winMutexEnd() are called as part
+-** of the sqlite3_initialize and sqlite3_shutdown()
+-** processing, the "interlocked" magic is probably not
+-** strictly necessary.
++** Round up a request size to the next valid allocation size.
+ */
+-static long winMutex_lock = 0;
++static int sqlite3MemRoundup(int n){
++ return ROUND8(n);
++}
+
+-SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds); /* os_win.c */
++/*
++** Fill a buffer with pseudo-random bytes. This is used to preset
++** the content of a new memory allocation to unpredictable values and
++** to clear the content of a freed allocation to unpredictable values.
++*/
++static void randomFill(char *pBuf, int nByte){
++ unsigned int x, y, r;
++ x = SQLITE_PTR_TO_INT(pBuf);
++ y = nByte | 1;
++ while( nByte >= 4 ){
++ x = (x>>1) ^ (-(x&1) & 0xd0000001);
++ y = y*1103515245 + 12345;
++ r = x ^ y;
++ *(int*)pBuf = r;
++ pBuf += 4;
++ nByte -= 4;
++ }
++ while( nByte-- > 0 ){
++ x = (x>>1) ^ (-(x&1) & 0xd0000001);
++ y = y*1103515245 + 12345;
++ r = x ^ y;
++ *(pBuf++) = r & 0xff;
++ }
++}
+
+-static int winMutexInit(void){
+- /* The first to increment to 1 does actual initialization */
+- if( InterlockedCompareExchange(&winMutex_lock, 1, 0)==0 ){
+- int i;
+- for(i=0; i<ArraySize(winMutex_staticMutexes); i++){
+-#if SQLITE_OS_WINRT
+- InitializeCriticalSectionEx(&winMutex_staticMutexes[i].mutex, 0, 0);
+-#else
+- InitializeCriticalSection(&winMutex_staticMutexes[i].mutex);
+-#endif
++/*
++** Allocate nByte bytes of memory.
++*/
++static void *sqlite3MemMalloc(int nByte){
++ struct MemBlockHdr *pHdr;
++ void **pBt;
++ char *z;
++ int *pInt;
++ void *p = 0;
++ int totalSize;
++ int nReserve;
++ sqlite3_mutex_enter(mem.mutex);
++ assert( mem.disallow==0 );
++ nReserve = ROUND8(nByte);
++ totalSize = nReserve + sizeof(*pHdr) + sizeof(int) +
++ mem.nBacktrace*sizeof(void*) + mem.nTitle;
++ p = malloc(totalSize);
++ if( p ){
++ z = p;
++ pBt = (void**)&z[mem.nTitle];
++ pHdr = (struct MemBlockHdr*)&pBt[mem.nBacktrace];
++ pHdr->pNext = 0;
++ pHdr->pPrev = mem.pLast;
++ if( mem.pLast ){
++ mem.pLast->pNext = pHdr;
++ }else{
++ mem.pFirst = pHdr;
+ }
+- winMutex_isInit = 1;
+- }else{
+- /* Someone else is in the process of initing the static mutexes */
+- while( !winMutex_isInit ){
+- sqlite3_win32_sleep(1);
++ mem.pLast = pHdr;
++ pHdr->iForeGuard = FOREGUARD;
++ pHdr->eType = MEMTYPE_HEAP;
++ pHdr->nBacktraceSlots = mem.nBacktrace;
++ pHdr->nTitle = mem.nTitle;
++ if( mem.nBacktrace ){
++ void *aAddr[40];
++ pHdr->nBacktrace = backtrace(aAddr, mem.nBacktrace+1)-1;
++ memcpy(pBt, &aAddr[1], pHdr->nBacktrace*sizeof(void*));
++ assert(pBt[0]);
++ if( mem.xBacktrace ){
++ mem.xBacktrace(nByte, pHdr->nBacktrace-1, &aAddr[1]);
++ }
++ }else{
++ pHdr->nBacktrace = 0;
++ }
++ if( mem.nTitle ){
++ memcpy(z, mem.zTitle, mem.nTitle);
+ }
++ pHdr->iSize = nByte;
++ adjustStats(nByte, +1);
++ pInt = (int*)&pHdr[1];
++ pInt[nReserve/sizeof(int)] = REARGUARD;
++ randomFill((char*)pInt, nByte);
++ memset(((char*)pInt)+nByte, 0x65, nReserve-nByte);
++ p = (void*)pInt;
+ }
+- return SQLITE_OK;
++ sqlite3_mutex_leave(mem.mutex);
++ return p;
+ }
+
+-static int winMutexEnd(void){
+- /* The first to decrement to 0 does actual shutdown
+- ** (which should be the last to shutdown.) */
+- if( InterlockedCompareExchange(&winMutex_lock, 0, 1)==1 ){
+- if( winMutex_isInit==1 ){
+- int i;
+- for(i=0; i<ArraySize(winMutex_staticMutexes); i++){
+- DeleteCriticalSection(&winMutex_staticMutexes[i].mutex);
+- }
+- winMutex_isInit = 0;
++/*
++** Free memory.
++*/
++static void sqlite3MemFree(void *pPrior){
++ struct MemBlockHdr *pHdr;
++ void **pBt;
++ char *z;
++ assert( sqlite3GlobalConfig.bMemstat || sqlite3GlobalConfig.bCoreMutex==0
++ || mem.mutex!=0 );
++ pHdr = sqlite3MemsysGetHeader(pPrior);
++ pBt = (void**)pHdr;
++ pBt -= pHdr->nBacktraceSlots;
++ sqlite3_mutex_enter(mem.mutex);
++ if( pHdr->pPrev ){
++ assert( pHdr->pPrev->pNext==pHdr );
++ pHdr->pPrev->pNext = pHdr->pNext;
++ }else{
++ assert( mem.pFirst==pHdr );
++ mem.pFirst = pHdr->pNext;
++ }
++ if( pHdr->pNext ){
++ assert( pHdr->pNext->pPrev==pHdr );
++ pHdr->pNext->pPrev = pHdr->pPrev;
++ }else{
++ assert( mem.pLast==pHdr );
++ mem.pLast = pHdr->pPrev;
++ }
++ z = (char*)pBt;
++ z -= pHdr->nTitle;
++ adjustStats(pHdr->iSize, -1);
++ randomFill(z, sizeof(void*)*pHdr->nBacktraceSlots + sizeof(*pHdr) +
++ pHdr->iSize + sizeof(int) + pHdr->nTitle);
++ free(z);
++ sqlite3_mutex_leave(mem.mutex);
++}
++
++/*
++** Change the size of an existing memory allocation.
++**
++** For this debugging implementation, we *always* make a copy of the
++** allocation into a new place in memory. In this way, if the
++** higher level code is using pointer to the old allocation, it is
++** much more likely to break and we are much more liking to find
++** the error.
++*/
++static void *sqlite3MemRealloc(void *pPrior, int nByte){
++ struct MemBlockHdr *pOldHdr;
++ void *pNew;
++ assert( mem.disallow==0 );
++ assert( (nByte & 7)==0 ); /* EV: R-46199-30249 */
++ pOldHdr = sqlite3MemsysGetHeader(pPrior);
++ pNew = sqlite3MemMalloc(nByte);
++ if( pNew ){
++ memcpy(pNew, pPrior, nByte<pOldHdr->iSize ? nByte : pOldHdr->iSize);
++ if( nByte>pOldHdr->iSize ){
++ randomFill(&((char*)pNew)[pOldHdr->iSize], nByte - pOldHdr->iSize);
+ }
++ sqlite3MemFree(pPrior);
+ }
+- return SQLITE_OK;
++ return pNew;
+ }
+
+ /*
+-** 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:
++** Populate the low-level memory allocation function pointers in
++** sqlite3GlobalConfig.m with pointers to the routines in this file.
++*/
++SQLITE_PRIVATE void sqlite3MemSetDefault(void){
++ static const sqlite3_mem_methods defaultMethods = {
++ sqlite3MemMalloc,
++ sqlite3MemFree,
++ sqlite3MemRealloc,
++ sqlite3MemSize,
++ sqlite3MemRoundup,
++ sqlite3MemInit,
++ sqlite3MemShutdown,
++ 0
++ };
++ sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods);
++}
++
++/*
++** Set the "type" of an allocation.
++*/
++SQLITE_PRIVATE void sqlite3MemdebugSetType(void *p, u8 eType){
++ if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){
++ struct MemBlockHdr *pHdr;
++ pHdr = sqlite3MemsysGetHeader(p);
++ assert( pHdr->iForeGuard==FOREGUARD );
++ pHdr->eType = eType;
++ }
++}
++
++/*
++** Return TRUE if the mask of type in eType matches the type of the
++** allocation p. Also return true if p==NULL.
+ **
+-** <ul>
+-** <li> SQLITE_MUTEX_FAST
+-** <li> SQLITE_MUTEX_RECURSIVE
+-** <li> SQLITE_MUTEX_STATIC_MASTER
+-** <li> SQLITE_MUTEX_STATIC_MEM
+-** <li> SQLITE_MUTEX_STATIC_MEM2
+-** <li> SQLITE_MUTEX_STATIC_PRNG
+-** <li> SQLITE_MUTEX_STATIC_LRU
+-** <li> SQLITE_MUTEX_STATIC_PMEM
+-** </ul>
++** This routine is designed for use within an assert() statement, to
++** verify the type of an allocation. For example:
+ **
+-** The first two constants cause sqlite3_mutex_alloc() to create
+-** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
+-** 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. But 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.
++** assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) );
++*/
++SQLITE_PRIVATE int sqlite3MemdebugHasType(void *p, u8 eType){
++ int rc = 1;
++ if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){
++ struct MemBlockHdr *pHdr;
++ pHdr = sqlite3MemsysGetHeader(p);
++ assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */
++ if( (pHdr->eType&eType)==0 ){
++ rc = 0;
++ }
++ }
++ return rc;
++}
++
++/*
++** Return TRUE if the mask of type in eType matches no bits of the type of the
++** allocation p. Also return true if p==NULL.
+ **
+-** The other allowed parameters to sqlite3_mutex_alloc() each return
+-** a pointer to a static preexisting mutex. Six 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
+-** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or
+-** SQLITE_MUTEX_RECURSIVE.
++** This routine is designed for use within an assert() statement, to
++** verify the type of an allocation. For example:
+ **
+-** 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
+-** mutex types, the same mutex is returned on every call that has
+-** the same type number.
++** assert( sqlite3MemdebugNoType(p, MEMTYPE_DB) );
+ */
+-static sqlite3_mutex *winMutexAlloc(int iType){
+- sqlite3_mutex *p;
+-
+- switch( iType ){
+- case SQLITE_MUTEX_FAST:
+- case SQLITE_MUTEX_RECURSIVE: {
+- p = sqlite3MallocZero( sizeof(*p) );
+- if( p ){
+-#ifdef SQLITE_DEBUG
+- p->id = iType;
+-#endif
+-#if SQLITE_OS_WINRT
+- InitializeCriticalSectionEx(&p->mutex, 0, 0);
+-#else
+- InitializeCriticalSection(&p->mutex);
+-#endif
+- }
+- break;
+- }
+- default: {
+- assert( winMutex_isInit==1 );
+- assert( iType-2 >= 0 );
+- assert( iType-2 < ArraySize(winMutex_staticMutexes) );
+- p = &winMutex_staticMutexes[iType-2];
+-#ifdef SQLITE_DEBUG
+- p->id = iType;
+-#endif
+- break;
++SQLITE_PRIVATE int sqlite3MemdebugNoType(void *p, u8 eType){
++ int rc = 1;
++ if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){
++ struct MemBlockHdr *pHdr;
++ pHdr = sqlite3MemsysGetHeader(p);
++ assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */
++ if( (pHdr->eType&eType)!=0 ){
++ rc = 0;
+ }
+ }
+- return p;
++ return rc;
+ }
+
+-
+ /*
+-** This routine deallocates a previously
+-** allocated mutex. SQLite is careful to deallocate every
+-** mutex that it allocates.
++** Set the number of backtrace levels kept for each allocation.
++** A value of zero turns off backtracing. The number is always rounded
++** up to a multiple of 2.
+ */
+-static void winMutexFree(sqlite3_mutex *p){
+- assert( p );
+- assert( p->nRef==0 && p->owner==0 );
+- assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
+- DeleteCriticalSection(&p->mutex);
+- sqlite3_free(p);
++SQLITE_PRIVATE void sqlite3MemdebugBacktrace(int depth){
++ if( depth<0 ){ depth = 0; }
++ if( depth>20 ){ depth = 20; }
++ depth = (depth+1)&0xfe;
++ mem.nBacktrace = depth;
++}
++
++SQLITE_PRIVATE void sqlite3MemdebugBacktraceCallback(void (*xBacktrace)(int, int, void **)){
++ mem.xBacktrace = xBacktrace;
+ }
+
+ /*
+-** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
+-** to enter a mutex. If another thread is already within the mutex,
+-** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return
+-** 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,
+-** 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.
++** Set the title string for subsequent allocations.
+ */
+-static void winMutexEnter(sqlite3_mutex *p){
+-#ifdef SQLITE_DEBUG
+- DWORD tid = GetCurrentThreadId();
+- assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) );
+-#endif
+- EnterCriticalSection(&p->mutex);
+-#ifdef SQLITE_DEBUG
+- assert( p->nRef>0 || p->owner==0 );
+- p->owner = tid;
+- p->nRef++;
+- if( p->trace ){
+- printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
++SQLITE_PRIVATE void sqlite3MemdebugSettitle(const char *zTitle){
++ unsigned int n = sqlite3Strlen30(zTitle) + 1;
++ sqlite3_mutex_enter(mem.mutex);
++ if( n>=sizeof(mem.zTitle) ) n = sizeof(mem.zTitle)-1;
++ memcpy(mem.zTitle, zTitle, n);
++ mem.zTitle[n] = 0;
++ mem.nTitle = ROUND8(n);
++ sqlite3_mutex_leave(mem.mutex);
++}
++
++SQLITE_PRIVATE void sqlite3MemdebugSync(){
++ struct MemBlockHdr *pHdr;
++ for(pHdr=mem.pFirst; pHdr; pHdr=pHdr->pNext){
++ void **pBt = (void**)pHdr;
++ pBt -= pHdr->nBacktraceSlots;
++ mem.xBacktrace(pHdr->iSize, pHdr->nBacktrace-1, &pBt[1]);
+ }
+-#endif
+ }
+-static int winMutexTry(sqlite3_mutex *p){
+-#ifndef NDEBUG
+- DWORD tid = GetCurrentThreadId();
+-#endif
+- int rc = SQLITE_BUSY;
+- assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) );
+- /*
+- ** The sqlite3_mutex_try() routine is very rarely used, and when it
+- ** is used it is merely an optimization. So it is OK for it to always
+- ** fail.
+- **
+- ** The TryEnterCriticalSection() interface is only available on WinNT.
+- ** And some windows compilers complain if you try to use it without
+- ** first doing some #defines that prevent SQLite from building on Win98.
+- ** For that reason, we will omit this optimization for now. See
+- ** ticket #2685.
+- */
+-#if 0
+- if( mutexIsNT() && TryEnterCriticalSection(&p->mutex) ){
+- p->owner = tid;
+- p->nRef++;
+- rc = SQLITE_OK;
++
++/*
++** Open the file indicated and write a log of all unfreed memory
++** allocations into that log.
++*/
++SQLITE_PRIVATE void sqlite3MemdebugDump(const char *zFilename){
++ FILE *out;
++ struct MemBlockHdr *pHdr;
++ void **pBt;
++ int i;
++ out = fopen(zFilename, "w");
++ if( out==0 ){
++ fprintf(stderr, "** Unable to output memory debug output log: %s **\n",
++ zFilename);
++ return;
+ }
+-#else
+- UNUSED_PARAMETER(p);
+-#endif
+-#ifdef SQLITE_DEBUG
+- if( rc==SQLITE_OK && p->trace ){
+- printf("try mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
++ for(pHdr=mem.pFirst; pHdr; pHdr=pHdr->pNext){
++ char *z = (char*)pHdr;
++ z -= pHdr->nBacktraceSlots*sizeof(void*) + pHdr->nTitle;
++ fprintf(out, "**** %lld bytes at %p from %s ****\n",
++ pHdr->iSize, &pHdr[1], pHdr->nTitle ? z : "???");
++ if( pHdr->nBacktrace ){
++ fflush(out);
++ pBt = (void**)pHdr;
++ pBt -= pHdr->nBacktraceSlots;
++ backtrace_symbols_fd(pBt, pHdr->nBacktrace, fileno(out));
++ fprintf(out, "\n");
++ }
+ }
+-#endif
+- return rc;
++ fprintf(out, "COUNTS:\n");
++ for(i=0; i<NCSIZE-1; i++){
++ if( mem.nAlloc[i] ){
++ fprintf(out, " %5d: %10d %10d %10d\n",
++ i*8, mem.nAlloc[i], mem.nCurrent[i], mem.mxCurrent[i]);
++ }
++ }
++ if( mem.nAlloc[NCSIZE-1] ){
++ fprintf(out, " %5d: %10d %10d %10d\n",
++ NCSIZE*8-8, mem.nAlloc[NCSIZE-1],
++ mem.nCurrent[NCSIZE-1], mem.mxCurrent[NCSIZE-1]);
++ }
++ fclose(out);
+ }
+
+ /*
+-** The sqlite3_mutex_leave() routine exits a mutex that was
+-** previously entered by the same thread. The behavior
+-** is undefined if the mutex is not currently entered or
+-** is not currently allocated. SQLite will never do either.
++** Return the number of times sqlite3MemMalloc() has been called.
+ */
+-static void winMutexLeave(sqlite3_mutex *p){
+-#ifndef NDEBUG
+- DWORD tid = GetCurrentThreadId();
+- assert( p->nRef>0 );
+- assert( p->owner==tid );
+- p->nRef--;
+- if( p->nRef==0 ) p->owner = 0;
+- assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
+-#endif
+- LeaveCriticalSection(&p->mutex);
+-#ifdef SQLITE_DEBUG
+- if( p->trace ){
+- printf("leave mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
++SQLITE_PRIVATE int sqlite3MemdebugMallocCount(){
++ int i;
++ int nTotal = 0;
++ for(i=0; i<NCSIZE; i++){
++ nTotal += mem.nAlloc[i];
+ }
+-#endif
++ return nTotal;
+ }
+
+-SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
+- static const sqlite3_mutex_methods sMutex = {
+- winMutexInit,
+- winMutexEnd,
+- winMutexAlloc,
+- winMutexFree,
+- winMutexEnter,
+- winMutexTry,
+- winMutexLeave,
+-#ifdef SQLITE_DEBUG
+- winMutexHeld,
+- winMutexNotheld
+-#else
+- 0,
+- 0
+-#endif
+- };
+
+- return &sMutex;
+-}
+-#endif /* SQLITE_MUTEX_W32 */
++#endif /* SQLITE_MEMDEBUG */
+
+-/************** End of mutex_w32.c *******************************************/
+-/************** Begin file malloc.c ******************************************/
++/************** End of mem2.c ************************************************/
++/************** Begin file mem3.c ********************************************/
+ /*
+-** 2001 September 15
++** 2007 October 14
+ **
+ ** The author disclaims copyright to this source code. In place of
+ ** a legal notice, here is a blessing:
+@@ -18775,1904 +19412,1632 @@
+ ** May you share freely, never taking more than you give.
+ **
+ *************************************************************************
++** This file contains the C functions that implement a memory
++** allocation subsystem for use by SQLite.
+ **
+-** Memory allocation functions used throughout sqlite.
++** This version of the memory allocation subsystem omits all
++** use of malloc(). The SQLite user supplies a block of memory
++** before calling sqlite3_initialize() from which allocations
++** are made and returned by the xMalloc() and xRealloc()
++** implementations. Once sqlite3_initialize() has been called,
++** the amount of memory available to SQLite is fixed and cannot
++** be changed.
++**
++** This version of the memory allocation subsystem is included
++** in the build only if SQLITE_ENABLE_MEMSYS3 is defined.
+ */
+-/* #include <stdarg.h> */
+
+ /*
+-** Attempt to release up to n bytes of non-essential memory currently
+-** held by SQLite. An example of non-essential memory is memory used to
+-** cache database pages that are not currently in use.
++** This version of the memory allocator is only built into the library
++** SQLITE_ENABLE_MEMSYS3 is defined. Defining this symbol does not
++** mean that the library will use a memory-pool by default, just that
++** it is available. The mempool allocator is activated by calling
++** sqlite3_config().
+ */
+-SQLITE_API int sqlite3_release_memory(int n){
+-#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+- return sqlite3PcacheReleaseMemory(n);
+-#else
+- /* IMPLEMENTATION-OF: R-34391-24921 The sqlite3_release_memory() routine
+- ** is a no-op returning zero if SQLite is not compiled with
+- ** SQLITE_ENABLE_MEMORY_MANAGEMENT. */
+- UNUSED_PARAMETER(n);
+- return 0;
+-#endif
+-}
++#ifdef SQLITE_ENABLE_MEMSYS3
+
+ /*
+-** An instance of the following object records the location of
+-** each unused scratch buffer.
++** Maximum size (in Mem3Blocks) of a "small" chunk.
+ */
+-typedef struct ScratchFreeslot {
+- struct ScratchFreeslot *pNext; /* Next unused scratch buffer */
+-} ScratchFreeslot;
++#define MX_SMALL 10
++
+
+ /*
+-** State information local to the memory allocation subsystem.
++** Number of freelist hash slots
+ */
+-static SQLITE_WSD struct Mem0Global {
+- sqlite3_mutex *mutex; /* Mutex to serialize access */
++#define N_HASH 61
++
++/*
++** A memory allocation (also called a "chunk") consists of two or
++** more blocks where each block is 8 bytes. The first 8 bytes are
++** a header that is not returned to the user.
++**
++** A chunk is two or more blocks that is either checked out or
++** free. The first block has format u.hdr. u.hdr.size4x is 4 times the
++** size of the allocation in blocks if the allocation is free.
++** The u.hdr.size4x&1 bit is true if the chunk is checked out and
++** false if the chunk is on the freelist. The u.hdr.size4x&2 bit
++** is true if the previous chunk is checked out and false if the
++** previous chunk is free. The u.hdr.prevSize field is the size of
++** the previous chunk in blocks if the previous chunk is on the
++** freelist. If the previous chunk is checked out, then
++** u.hdr.prevSize can be part of the data for that chunk and should
++** not be read or written.
++**
++** We often identify a chunk by its index in mem3.aPool[]. When
++** this is done, the chunk index refers to the second block of
++** the chunk. In this way, the first chunk has an index of 1.
++** A chunk index of 0 means "no such chunk" and is the equivalent
++** of a NULL pointer.
++**
++** The second block of free chunks is of the form u.list. The
++** two fields form a double-linked list of chunks of related sizes.
++** Pointers to the head of the list are stored in mem3.aiSmall[]
++** for smaller chunks and mem3.aiHash[] for larger chunks.
++**
++** The second block of a chunk is user data if the chunk is checked
++** out. If a chunk is checked out, the user data may extend into
++** the u.hdr.prevSize value of the following chunk.
++*/
++typedef struct Mem3Block Mem3Block;
++struct Mem3Block {
++ union {
++ struct {
++ u32 prevSize; /* Size of previous chunk in Mem3Block elements */
++ u32 size4x; /* 4x the size of current chunk in Mem3Block elements */
++ } hdr;
++ struct {
++ u32 next; /* Index in mem3.aPool[] of next free chunk */
++ u32 prev; /* Index in mem3.aPool[] of previous free chunk */
++ } list;
++ } u;
++};
+
++/*
++** All of the static variables used by this module are collected
++** into a single structure named "mem3". This is to keep the
++** static variables organized and to reduce namespace pollution
++** when this module is combined with other in the amalgamation.
++*/
++static SQLITE_WSD struct Mem3Global {
+ /*
+- ** The alarm callback and its arguments. The mem0.mutex lock will
+- ** be held while the callback is running. Recursive calls into
+- ** the memory subsystem are allowed, but no new callbacks will be
+- ** issued.
++ ** Memory available for allocation. nPool is the size of the array
++ ** (in Mem3Blocks) pointed to by aPool less 2.
+ */
+- sqlite3_int64 alarmThreshold;
+- void (*alarmCallback)(void*, sqlite3_int64,int);
+- void *alarmArg;
++ u32 nPool;
++ Mem3Block *aPool;
+
+ /*
+- ** Pointers to the end of sqlite3GlobalConfig.pScratch memory
+- ** (so that a range test can be used to determine if an allocation
+- ** being freed came from pScratch) and a pointer to the list of
+- ** unused scratch allocations.
++ ** True if we are evaluating an out-of-memory callback.
+ */
+- void *pScratchEnd;
+- ScratchFreeslot *pScratchFree;
+- u32 nScratchFree;
++ int alarmBusy;
++
++ /*
++ ** Mutex to control access to the memory allocation subsystem.
++ */
++ sqlite3_mutex *mutex;
++
++ /*
++ ** The minimum amount of free space that we have seen.
++ */
++ u32 mnMaster;
+
+ /*
+- ** True if heap is nearly "full" where "full" is defined by the
+- ** sqlite3_soft_heap_limit() setting.
++ ** iMaster is the index of the master chunk. Most new allocations
++ ** occur off of this chunk. szMaster is the size (in Mem3Blocks)
++ ** of the current master. iMaster is 0 if there is not master chunk.
++ ** The master chunk is not in either the aiHash[] or aiSmall[].
+ */
+- int nearlyFull;
+-} mem0 = { 0, 0, 0, 0, 0, 0, 0, 0 };
++ u32 iMaster;
++ u32 szMaster;
+
+-#define mem0 GLOBAL(struct Mem0Global, mem0)
++ /*
++ ** Array of lists of free blocks according to the block size
++ ** for smaller chunks, or a hash on the block size for larger
++ ** chunks.
++ */
++ u32 aiSmall[MX_SMALL-1]; /* For sizes 2 through MX_SMALL, inclusive */
++ u32 aiHash[N_HASH]; /* For sizes MX_SMALL+1 and larger */
++} mem3 = { 97535575 };
+
+-/*
+-** This routine runs when the memory allocator sees that the
+-** total memory allocation is about to exceed the soft heap
+-** limit.
+-*/
+-static void softHeapLimitEnforcer(
+- void *NotUsed,
+- sqlite3_int64 NotUsed2,
+- int allocSize
+-){
+- UNUSED_PARAMETER2(NotUsed, NotUsed2);
+- sqlite3_release_memory(allocSize);
+-}
++#define mem3 GLOBAL(struct Mem3Global, mem3)
+
+ /*
+-** Change the alarm callback
++** Unlink the chunk at mem3.aPool[i] from list it is currently
++** on. *pRoot is the list that i is a member of.
+ */
+-static int sqlite3MemoryAlarm(
+- void(*xCallback)(void *pArg, sqlite3_int64 used,int N),
+- void *pArg,
+- sqlite3_int64 iThreshold
+-){
+- int nUsed;
+- sqlite3_mutex_enter(mem0.mutex);
+- mem0.alarmCallback = xCallback;
+- mem0.alarmArg = pArg;
+- mem0.alarmThreshold = iThreshold;
+- nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
+- mem0.nearlyFull = (iThreshold>0 && iThreshold<=nUsed);
+- sqlite3_mutex_leave(mem0.mutex);
+- return SQLITE_OK;
++static void memsys3UnlinkFromList(u32 i, u32 *pRoot){
++ u32 next = mem3.aPool[i].u.list.next;
++ u32 prev = mem3.aPool[i].u.list.prev;
++ assert( sqlite3_mutex_held(mem3.mutex) );
++ if( prev==0 ){
++ *pRoot = next;
++ }else{
++ mem3.aPool[prev].u.list.next = next;
++ }
++ if( next ){
++ mem3.aPool[next].u.list.prev = prev;
++ }
++ mem3.aPool[i].u.list.next = 0;
++ mem3.aPool[i].u.list.prev = 0;
+ }
+
+-#ifndef SQLITE_OMIT_DEPRECATED
+ /*
+-** Deprecated external interface. Internal/core SQLite code
+-** should call sqlite3MemoryAlarm.
++** Unlink the chunk at index i from
++** whatever list is currently a member of.
+ */
+-SQLITE_API int sqlite3_memory_alarm(
+- void(*xCallback)(void *pArg, sqlite3_int64 used,int N),
+- void *pArg,
+- sqlite3_int64 iThreshold
+-){
+- return sqlite3MemoryAlarm(xCallback, pArg, iThreshold);
++static void memsys3Unlink(u32 i){
++ u32 size, hash;
++ assert( sqlite3_mutex_held(mem3.mutex) );
++ assert( (mem3.aPool[i-1].u.hdr.size4x & 1)==0 );
++ assert( i>=1 );
++ size = mem3.aPool[i-1].u.hdr.size4x/4;
++ assert( size==mem3.aPool[i+size-1].u.hdr.prevSize );
++ assert( size>=2 );
++ if( size <= MX_SMALL ){
++ memsys3UnlinkFromList(i, &mem3.aiSmall[size-2]);
++ }else{
++ hash = size % N_HASH;
++ memsys3UnlinkFromList(i, &mem3.aiHash[hash]);
++ }
+ }
+-#endif
+
+ /*
+-** Set the soft heap-size limit for the library. Passing a zero or
+-** negative value indicates no limit.
++** Link the chunk at mem3.aPool[i] so that is on the list rooted
++** at *pRoot.
+ */
+-SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 n){
+- sqlite3_int64 priorLimit;
+- sqlite3_int64 excess;
+-#ifndef SQLITE_OMIT_AUTOINIT
+- int rc = sqlite3_initialize();
+- if( rc ) return -1;
+-#endif
+- sqlite3_mutex_enter(mem0.mutex);
+- priorLimit = mem0.alarmThreshold;
+- sqlite3_mutex_leave(mem0.mutex);
+- if( n<0 ) return priorLimit;
+- if( n>0 ){
+- sqlite3MemoryAlarm(softHeapLimitEnforcer, 0, n);
+- }else{
+- sqlite3MemoryAlarm(0, 0, 0);
++static void memsys3LinkIntoList(u32 i, u32 *pRoot){
++ assert( sqlite3_mutex_held(mem3.mutex) );
++ mem3.aPool[i].u.list.next = *pRoot;
++ mem3.aPool[i].u.list.prev = 0;
++ if( *pRoot ){
++ mem3.aPool[*pRoot].u.list.prev = i;
+ }
+- excess = sqlite3_memory_used() - n;
+- if( excess>0 ) sqlite3_release_memory((int)(excess & 0x7fffffff));
+- return priorLimit;
+-}
+-SQLITE_API void sqlite3_soft_heap_limit(int n){
+- if( n<0 ) n = 0;
+- sqlite3_soft_heap_limit64(n);
++ *pRoot = i;
+ }
+
+ /*
+-** Initialize the memory allocation subsystem.
++** Link the chunk at index i into either the appropriate
++** small chunk list, or into the large chunk hash table.
+ */
+-SQLITE_PRIVATE int sqlite3MallocInit(void){
+- if( sqlite3GlobalConfig.m.xMalloc==0 ){
+- sqlite3MemSetDefault();
+- }
+- memset(&mem0, 0, sizeof(mem0));
+- if( sqlite3GlobalConfig.bCoreMutex ){
+- mem0.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
+- }
+- if( sqlite3GlobalConfig.pScratch && sqlite3GlobalConfig.szScratch>=100
+- && sqlite3GlobalConfig.nScratch>0 ){
+- int i, n, sz;
+- ScratchFreeslot *pSlot;
+- sz = ROUNDDOWN8(sqlite3GlobalConfig.szScratch);
+- sqlite3GlobalConfig.szScratch = sz;
+- pSlot = (ScratchFreeslot*)sqlite3GlobalConfig.pScratch;
+- n = sqlite3GlobalConfig.nScratch;
+- mem0.pScratchFree = pSlot;
+- mem0.nScratchFree = n;
+- for(i=0; i<n-1; i++){
+- pSlot->pNext = (ScratchFreeslot*)(sz+(char*)pSlot);
+- pSlot = pSlot->pNext;
+- }
+- pSlot->pNext = 0;
+- mem0.pScratchEnd = (void*)&pSlot[1];
++static void memsys3Link(u32 i){
++ u32 size, hash;
++ assert( sqlite3_mutex_held(mem3.mutex) );
++ assert( i>=1 );
++ assert( (mem3.aPool[i-1].u.hdr.size4x & 1)==0 );
++ size = mem3.aPool[i-1].u.hdr.size4x/4;
++ assert( size==mem3.aPool[i+size-1].u.hdr.prevSize );
++ assert( size>=2 );
++ if( size <= MX_SMALL ){
++ memsys3LinkIntoList(i, &mem3.aiSmall[size-2]);
+ }else{
+- mem0.pScratchEnd = 0;
+- sqlite3GlobalConfig.pScratch = 0;
+- sqlite3GlobalConfig.szScratch = 0;
+- sqlite3GlobalConfig.nScratch = 0;
+- }
+- if( sqlite3GlobalConfig.pPage==0 || sqlite3GlobalConfig.szPage<512
+- || sqlite3GlobalConfig.nPage<1 ){
+- sqlite3GlobalConfig.pPage = 0;
+- sqlite3GlobalConfig.szPage = 0;
+- sqlite3GlobalConfig.nPage = 0;
++ hash = size % N_HASH;
++ memsys3LinkIntoList(i, &mem3.aiHash[hash]);
+ }
+- return sqlite3GlobalConfig.m.xInit(sqlite3GlobalConfig.m.pAppData);
+ }
+
+ /*
+-** Return true if the heap is currently under memory pressure - in other
+-** words if the amount of heap used is close to the limit set by
+-** sqlite3_soft_heap_limit().
++** If the STATIC_MEM mutex is not already held, obtain it now. The mutex
++** will already be held (obtained by code in malloc.c) if
++** sqlite3GlobalConfig.bMemStat is true.
+ */
+-SQLITE_PRIVATE int sqlite3HeapNearlyFull(void){
+- return mem0.nearlyFull;
++static void memsys3Enter(void){
++ if( sqlite3GlobalConfig.bMemstat==0 && mem3.mutex==0 ){
++ mem3.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
++ }
++ sqlite3_mutex_enter(mem3.mutex);
++}
++static void memsys3Leave(void){
++ sqlite3_mutex_leave(mem3.mutex);
+ }
+
+ /*
+-** Deinitialize the memory allocation subsystem.
++** Called when we are unable to satisfy an allocation of nBytes.
+ */
+-SQLITE_PRIVATE void sqlite3MallocEnd(void){
+- if( sqlite3GlobalConfig.m.xShutdown ){
+- sqlite3GlobalConfig.m.xShutdown(sqlite3GlobalConfig.m.pAppData);
++static void memsys3OutOfMemory(int nByte){
++ if( !mem3.alarmBusy ){
++ mem3.alarmBusy = 1;
++ assert( sqlite3_mutex_held(mem3.mutex) );
++ sqlite3_mutex_leave(mem3.mutex);
++ sqlite3_release_memory(nByte);
++ sqlite3_mutex_enter(mem3.mutex);
++ mem3.alarmBusy = 0;
+ }
+- memset(&mem0, 0, sizeof(mem0));
+ }
+
+-/*
+-** Return the amount of memory currently checked out.
+-*/
+-SQLITE_API sqlite3_int64 sqlite3_memory_used(void){
+- int n, mx;
+- sqlite3_int64 res;
+- sqlite3_status(SQLITE_STATUS_MEMORY_USED, &n, &mx, 0);
+- res = (sqlite3_int64)n; /* Work around bug in Borland C. Ticket #3216 */
+- return res;
+-}
+
+ /*
+-** Return the maximum amount of memory that has ever been
+-** checked out since either the beginning of this process
+-** or since the most recent reset.
++** Chunk i is a free chunk that has been unlinked. Adjust its
++** size parameters for check-out and return a pointer to the
++** user portion of the chunk.
+ */
+-SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag){
+- int n, mx;
+- sqlite3_int64 res;
+- sqlite3_status(SQLITE_STATUS_MEMORY_USED, &n, &mx, resetFlag);
+- res = (sqlite3_int64)mx; /* Work around bug in Borland C. Ticket #3216 */
+- return res;
++static void *memsys3Checkout(u32 i, u32 nBlock){
++ u32 x;
++ assert( sqlite3_mutex_held(mem3.mutex) );
++ assert( i>=1 );
++ assert( mem3.aPool[i-1].u.hdr.size4x/4==nBlock );
++ assert( mem3.aPool[i+nBlock-1].u.hdr.prevSize==nBlock );
++ x = mem3.aPool[i-1].u.hdr.size4x;
++ mem3.aPool[i-1].u.hdr.size4x = nBlock*4 | 1 | (x&2);
++ mem3.aPool[i+nBlock-1].u.hdr.prevSize = nBlock;
++ mem3.aPool[i+nBlock-1].u.hdr.size4x |= 2;
++ return &mem3.aPool[i];
+ }
+
+ /*
+-** Trigger the alarm
++** Carve a piece off of the end of the mem3.iMaster free chunk.
++** Return a pointer to the new allocation. Or, if the master chunk
++** is not large enough, return 0.
+ */
+-static void sqlite3MallocAlarm(int nByte){
+- void (*xCallback)(void*,sqlite3_int64,int);
+- sqlite3_int64 nowUsed;
+- void *pArg;
+- if( mem0.alarmCallback==0 ) return;
+- xCallback = mem0.alarmCallback;
+- nowUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
+- pArg = mem0.alarmArg;
+- mem0.alarmCallback = 0;
+- sqlite3_mutex_leave(mem0.mutex);
+- xCallback(pArg, nowUsed, nByte);
+- sqlite3_mutex_enter(mem0.mutex);
+- mem0.alarmCallback = xCallback;
+- mem0.alarmArg = pArg;
++static void *memsys3FromMaster(u32 nBlock){
++ assert( sqlite3_mutex_held(mem3.mutex) );
++ assert( mem3.szMaster>=nBlock );
++ if( nBlock>=mem3.szMaster-1 ){
++ /* Use the entire master */
++ void *p = memsys3Checkout(mem3.iMaster, mem3.szMaster);
++ mem3.iMaster = 0;
++ mem3.szMaster = 0;
++ mem3.mnMaster = 0;
++ return p;
++ }else{
++ /* Split the master block. Return the tail. */
++ u32 newi, x;
++ newi = mem3.iMaster + mem3.szMaster - nBlock;
++ assert( newi > mem3.iMaster+1 );
++ mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = nBlock;
++ mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x |= 2;
++ mem3.aPool[newi-1].u.hdr.size4x = nBlock*4 + 1;
++ mem3.szMaster -= nBlock;
++ mem3.aPool[newi-1].u.hdr.prevSize = mem3.szMaster;
++ x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2;
++ mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x;
++ if( mem3.szMaster < mem3.mnMaster ){
++ mem3.mnMaster = mem3.szMaster;
++ }
++ return (void*)&mem3.aPool[newi];
++ }
+ }
+
+ /*
+-** Do a memory allocation with statistics and alarms. Assume the
+-** lock is already held.
++** *pRoot is the head of a list of free chunks of the same size
++** or same size hash. In other words, *pRoot is an entry in either
++** mem3.aiSmall[] or mem3.aiHash[].
++**
++** This routine examines all entries on the given list and tries
++** to coalesce each entries with adjacent free chunks.
++**
++** If it sees a chunk that is larger than mem3.iMaster, it replaces
++** the current mem3.iMaster with the new larger chunk. In order for
++** this mem3.iMaster replacement to work, the master chunk must be
++** linked into the hash tables. That is not the normal state of
++** affairs, of course. The calling routine must link the master
++** chunk before invoking this routine, then must unlink the (possibly
++** changed) master chunk once this routine has finished.
+ */
+-static int mallocWithAlarm(int n, void **pp){
+- int nFull;
+- void *p;
+- assert( sqlite3_mutex_held(mem0.mutex) );
+- nFull = sqlite3GlobalConfig.m.xRoundup(n);
+- sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, n);
+- if( mem0.alarmCallback!=0 ){
+- int nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
+- if( nUsed >= mem0.alarmThreshold - nFull ){
+- mem0.nearlyFull = 1;
+- sqlite3MallocAlarm(nFull);
++static void memsys3Merge(u32 *pRoot){
++ u32 iNext, prev, size, i, x;
++
++ assert( sqlite3_mutex_held(mem3.mutex) );
++ for(i=*pRoot; i>0; i=iNext){
++ iNext = mem3.aPool[i].u.list.next;
++ size = mem3.aPool[i-1].u.hdr.size4x;
++ assert( (size&1)==0 );
++ if( (size&2)==0 ){
++ memsys3UnlinkFromList(i, pRoot);
++ assert( i > mem3.aPool[i-1].u.hdr.prevSize );
++ prev = i - mem3.aPool[i-1].u.hdr.prevSize;
++ if( prev==iNext ){
++ iNext = mem3.aPool[prev].u.list.next;
++ }
++ memsys3Unlink(prev);
++ size = i + size/4 - prev;
++ x = mem3.aPool[prev-1].u.hdr.size4x & 2;
++ mem3.aPool[prev-1].u.hdr.size4x = size*4 | x;
++ mem3.aPool[prev+size-1].u.hdr.prevSize = size;
++ memsys3Link(prev);
++ i = prev;
+ }else{
+- mem0.nearlyFull = 0;
++ size /= 4;
++ }
++ if( size>mem3.szMaster ){
++ mem3.iMaster = i;
++ mem3.szMaster = size;
+ }
+ }
+- p = sqlite3GlobalConfig.m.xMalloc(nFull);
+-#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+- if( p==0 && mem0.alarmCallback ){
+- sqlite3MallocAlarm(nFull);
+- p = sqlite3GlobalConfig.m.xMalloc(nFull);
+- }
+-#endif
+- if( p ){
+- nFull = sqlite3MallocSize(p);
+- sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nFull);
+- sqlite3StatusAdd(SQLITE_STATUS_MALLOC_COUNT, 1);
+- }
+- *pp = p;
+- return nFull;
+ }
+
+ /*
+-** Allocate memory. This routine is like sqlite3_malloc() except that it
+-** assumes the memory subsystem has already been initialized.
++** Return a block of memory of at least nBytes in size.
++** Return NULL if unable.
++**
++** This function assumes that the necessary mutexes, if any, are
++** already held by the caller. Hence "Unsafe".
+ */
+-SQLITE_PRIVATE void *sqlite3Malloc(int n){
+- void *p;
+- if( n<=0 /* IMP: R-65312-04917 */
+- || 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
+- ** 255 bytes of overhead. SQLite itself will never use anything near
+- ** this amount. The only way to reach the limit is with sqlite3_malloc() */
+- p = 0;
+- }else if( sqlite3GlobalConfig.bMemstat ){
+- sqlite3_mutex_enter(mem0.mutex);
+- mallocWithAlarm(n, &p);
+- sqlite3_mutex_leave(mem0.mutex);
++static void *memsys3MallocUnsafe(int nByte){
++ u32 i;
++ u32 nBlock;
++ u32 toFree;
++
++ assert( sqlite3_mutex_held(mem3.mutex) );
++ assert( sizeof(Mem3Block)==8 );
++ if( nByte<=12 ){
++ nBlock = 2;
+ }else{
+- p = sqlite3GlobalConfig.m.xMalloc(n);
++ nBlock = (nByte + 11)/8;
+ }
+- assert( EIGHT_BYTE_ALIGNMENT(p) ); /* IMP: R-04675-44850 */
+- return p;
+-}
++ assert( nBlock>=2 );
+
+-/*
+-** This version of the memory allocation is for use by the application.
+-** First make sure the memory subsystem is initialized, then do the
+-** allocation.
+-*/
+-SQLITE_API void *sqlite3_malloc(int n){
+-#ifndef SQLITE_OMIT_AUTOINIT
+- if( sqlite3_initialize() ) return 0;
+-#endif
+- return sqlite3Malloc(n);
+-}
+-
+-/*
+-** Each thread may only have a single outstanding allocation from
+-** xScratchMalloc(). We verify this constraint in the single-threaded
+-** case by setting scratchAllocOut to 1 when an allocation
+-** is outstanding clearing it when the allocation is freed.
+-*/
+-#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
+-static int scratchAllocOut = 0;
+-#endif
++ /* STEP 1:
++ ** Look for an entry of the correct size in either the small
++ ** chunk table or in the large chunk hash table. This is
++ ** successful most of the time (about 9 times out of 10).
++ */
++ if( nBlock <= MX_SMALL ){
++ i = mem3.aiSmall[nBlock-2];
++ if( i>0 ){
++ memsys3UnlinkFromList(i, &mem3.aiSmall[nBlock-2]);
++ return memsys3Checkout(i, nBlock);
++ }
++ }else{
++ int hash = nBlock % N_HASH;
++ for(i=mem3.aiHash[hash]; i>0; i=mem3.aPool[i].u.list.next){
++ if( mem3.aPool[i-1].u.hdr.size4x/4==nBlock ){
++ memsys3UnlinkFromList(i, &mem3.aiHash[hash]);
++ return memsys3Checkout(i, nBlock);
++ }
++ }
++ }
+
++ /* STEP 2:
++ ** Try to satisfy the allocation by carving a piece off of the end
++ ** of the master chunk. This step usually works if step 1 fails.
++ */
++ if( mem3.szMaster>=nBlock ){
++ return memsys3FromMaster(nBlock);
++ }
+
+-/*
+-** Allocate memory that is to be used and released right away.
+-** This routine is similar to alloca() in that it is not intended
+-** for situations where the memory might be held long-term. This
+-** routine is intended to get memory to old large transient data
+-** structures that would not normally fit on the stack of an
+-** embedded processor.
+-*/
+-SQLITE_PRIVATE void *sqlite3ScratchMalloc(int n){
+- void *p;
+- assert( n>0 );
+
+- sqlite3_mutex_enter(mem0.mutex);
+- 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);
+- 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 = sqlite3GlobalConfig.m.xMalloc(n);
++ /* STEP 3:
++ ** Loop through the entire memory pool. Coalesce adjacent free
++ ** chunks. Recompute the master chunk as the largest free chunk.
++ ** Then try again to satisfy the allocation by carving a piece off
++ ** of the end of the master chunk. This step happens very
++ ** rarely (we hope!)
++ */
++ for(toFree=nBlock*16; toFree<(mem3.nPool*16); toFree *= 2){
++ memsys3OutOfMemory(toFree);
++ if( mem3.iMaster ){
++ memsys3Link(mem3.iMaster);
++ mem3.iMaster = 0;
++ mem3.szMaster = 0;
++ }
++ for(i=0; i<N_HASH; i++){
++ memsys3Merge(&mem3.aiHash[i]);
++ }
++ for(i=0; i<MX_SMALL-1; i++){
++ memsys3Merge(&mem3.aiSmall[i]);
++ }
++ if( mem3.szMaster ){
++ memsys3Unlink(mem3.iMaster);
++ if( mem3.szMaster>=nBlock ){
++ return memsys3FromMaster(nBlock);
++ }
+ }
+- sqlite3MemdebugSetType(p, MEMTYPE_SCRATCH);
+ }
+- assert( sqlite3_mutex_notheld(mem0.mutex) );
+-
+-
+-#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 );
+- if( p ) scratchAllocOut++;
+-#endif
+
+- return p;
++ /* If none of the above worked, then we fail. */
++ return 0;
+ }
+-SQLITE_PRIVATE void sqlite3ScratchFree(void *p){
+- if( p ){
+
+-#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
+- /* Verify that no more than two scratch allocation per thread
+- ** is 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 && scratchAllocOut<=2 );
+- scratchAllocOut--;
+-#endif
++/*
++** Free an outstanding memory allocation.
++**
++** This function assumes that the necessary mutexes, if any, are
++** already held by the caller. Hence "Unsafe".
++*/
++static void memsys3FreeUnsafe(void *pOld){
++ Mem3Block *p = (Mem3Block*)pOld;
++ int i;
++ u32 size, x;
++ assert( sqlite3_mutex_held(mem3.mutex) );
++ assert( p>mem3.aPool && p<&mem3.aPool[mem3.nPool] );
++ i = p - mem3.aPool;
++ assert( (mem3.aPool[i-1].u.hdr.size4x&1)==1 );
++ size = mem3.aPool[i-1].u.hdr.size4x/4;
++ assert( i+size<=mem3.nPool+1 );
++ mem3.aPool[i-1].u.hdr.size4x &= ~1;
++ mem3.aPool[i+size-1].u.hdr.prevSize = size;
++ mem3.aPool[i+size-1].u.hdr.size4x &= ~2;
++ memsys3Link(i);
+
+- if( p>=sqlite3GlobalConfig.pScratch && p<mem0.pScratchEnd ){
+- /* Release memory from the SQLITE_CONFIG_SCRATCH allocation */
+- ScratchFreeslot *pSlot;
+- pSlot = (ScratchFreeslot*)p;
+- sqlite3_mutex_enter(mem0.mutex);
+- pSlot->pNext = mem0.pScratchFree;
+- mem0.pScratchFree = pSlot;
+- mem0.nScratchFree++;
+- assert( mem0.nScratchFree <= (u32)sqlite3GlobalConfig.nScratch );
+- sqlite3StatusAdd(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) );
+- 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);
+- sqlite3GlobalConfig.m.xFree(p);
+- sqlite3_mutex_leave(mem0.mutex);
+- }else{
+- sqlite3GlobalConfig.m.xFree(p);
+- }
++ /* Try to expand the master using the newly freed chunk */
++ if( mem3.iMaster ){
++ while( (mem3.aPool[mem3.iMaster-1].u.hdr.size4x&2)==0 ){
++ size = mem3.aPool[mem3.iMaster-1].u.hdr.prevSize;
++ mem3.iMaster -= size;
++ mem3.szMaster += size;
++ memsys3Unlink(mem3.iMaster);
++ x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2;
++ mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x;
++ mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = mem3.szMaster;
++ }
++ x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2;
++ while( (mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x&1)==0 ){
++ memsys3Unlink(mem3.iMaster+mem3.szMaster);
++ mem3.szMaster += mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x/4;
++ mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x;
++ mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = mem3.szMaster;
+ }
+ }
+ }
+
+ /*
+-** TRUE if p is a lookaside memory allocation from db
++** Return the size of an outstanding allocation, in bytes. The
++** size returned omits the 8-byte header overhead. This only
++** works for chunks that are currently checked out.
+ */
+-#ifndef SQLITE_OMIT_LOOKASIDE
+-static int isLookaside(sqlite3 *db, void *p){
+- return p && p>=db->lookaside.pStart && p<db->lookaside.pEnd;
++static int memsys3Size(void *p){
++ Mem3Block *pBlock;
++ if( p==0 ) return 0;
++ pBlock = (Mem3Block*)p;
++ assert( (pBlock[-1].u.hdr.size4x&1)!=0 );
++ return (pBlock[-1].u.hdr.size4x&~3)*2 - 4;
+ }
+-#else
+-#define isLookaside(A,B) 0
+-#endif
+
+ /*
+-** Return the size of a memory allocation previously obtained from
+-** sqlite3Malloc() or sqlite3_malloc().
++** Round up a request size to the next valid allocation size.
+ */
+-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 || sqlite3_mutex_held(db->mutex) );
+- if( db && isLookaside(db, p) ){
+- return db->lookaside.sz;
++static int memsys3Roundup(int n){
++ if( n<=12 ){
++ return 12;
+ }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);
++ return ((n+11)&~7) - 4;
+ }
+ }
+
+ /*
+-** Free memory previously obtained from sqlite3Malloc().
++** Allocate nBytes of memory.
+ */
+-SQLITE_API void sqlite3_free(void *p){
+- if( p==0 ) return; /* IMP: R-49053-54554 */
+- assert( sqlite3MemdebugNoType(p, MEMTYPE_DB) );
+- assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
+- if( sqlite3GlobalConfig.bMemstat ){
+- sqlite3_mutex_enter(mem0.mutex);
+- sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, -sqlite3MallocSize(p));
+- sqlite3StatusAdd(SQLITE_STATUS_MALLOC_COUNT, -1);
+- sqlite3GlobalConfig.m.xFree(p);
+- sqlite3_mutex_leave(mem0.mutex);
+- }else{
+- sqlite3GlobalConfig.m.xFree(p);
+- }
++static void *memsys3Malloc(int nBytes){
++ sqlite3_int64 *p;
++ assert( nBytes>0 ); /* malloc.c filters out 0 byte requests */
++ memsys3Enter();
++ p = memsys3MallocUnsafe(nBytes);
++ memsys3Leave();
++ return (void*)p;
+ }
+
+ /*
+-** Free memory that might be associated with a particular database
+-** connection.
++** Free memory.
+ */
+-SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){
+- assert( db==0 || sqlite3_mutex_held(db->mutex) );
+- if( db ){
+- if( db->pnBytesFreed ){
+- *db->pnBytesFreed += sqlite3DbMallocSize(db, p);
+- return;
+- }
+- if( isLookaside(db, p) ){
+- LookasideSlot *pBuf = (LookasideSlot*)p;
+-#if SQLITE_DEBUG
+- /* Trash all content in the buffer being freed */
+- memset(p, 0xaa, db->lookaside.sz);
+-#endif
+- pBuf->pNext = db->lookaside.pFree;
+- db->lookaside.pFree = pBuf;
+- db->lookaside.nOut--;
+- return;
+- }
+- }
+- assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) );
+- assert( sqlite3MemdebugHasType(p, MEMTYPE_LOOKASIDE|MEMTYPE_HEAP) );
+- assert( db!=0 || sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) );
+- sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
+- sqlite3_free(p);
++static void memsys3Free(void *pPrior){
++ assert( pPrior );
++ memsys3Enter();
++ memsys3FreeUnsafe(pPrior);
++ memsys3Leave();
+ }
+
+ /*
+ ** Change the size of an existing memory allocation
+ */
+-SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, int nBytes){
+- int nOld, nNew, nDiff;
+- void *pNew;
+- if( pOld==0 ){
+- return sqlite3Malloc(nBytes); /* IMP: R-28354-25769 */
++static void *memsys3Realloc(void *pPrior, int nBytes){
++ int nOld;
++ void *p;
++ if( pPrior==0 ){
++ return sqlite3_malloc(nBytes);
+ }
+ if( nBytes<=0 ){
+- sqlite3_free(pOld); /* IMP: R-31593-10574 */
++ sqlite3_free(pPrior);
+ return 0;
+ }
+- if( nBytes>=0x7fffff00 ){
+- /* The 0x7ffff00 limit term is explained in comments on sqlite3Malloc() */
+- return 0;
++ nOld = memsys3Size(pPrior);
++ if( nBytes<=nOld && nBytes>=nOld-128 ){
++ return pPrior;
+ }
+- nOld = sqlite3MallocSize(pOld);
+- /* 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);
+- if( nOld==nNew ){
+- pNew = pOld;
+- }else if( sqlite3GlobalConfig.bMemstat ){
+- sqlite3_mutex_enter(mem0.mutex);
+- sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, 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);
+- pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
+- }
+- if( pNew ){
+- nNew = sqlite3MallocSize(pNew);
+- sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nNew-nOld);
++ memsys3Enter();
++ p = memsys3MallocUnsafe(nBytes);
++ if( p ){
++ if( nOld<nBytes ){
++ memcpy(p, pPrior, nOld);
++ }else{
++ memcpy(p, pPrior, nBytes);
+ }
+- sqlite3_mutex_leave(mem0.mutex);
+- }else{
+- pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
++ memsys3FreeUnsafe(pPrior);
+ }
+- assert( EIGHT_BYTE_ALIGNMENT(pNew) ); /* IMP: R-04675-44850 */
+- return pNew;
++ memsys3Leave();
++ return p;
+ }
+
+ /*
+-** The public interface to sqlite3Realloc. Make sure that the memory
+-** subsystem is initialized prior to invoking sqliteRealloc.
++** Initialize this module.
+ */
+-SQLITE_API void *sqlite3_realloc(void *pOld, int n){
+-#ifndef SQLITE_OMIT_AUTOINIT
+- if( sqlite3_initialize() ) return 0;
+-#endif
+- return sqlite3Realloc(pOld, n);
+-}
++static int memsys3Init(void *NotUsed){
++ UNUSED_PARAMETER(NotUsed);
++ if( !sqlite3GlobalConfig.pHeap ){
++ return SQLITE_ERROR;
++ }
+
++ /* Store a pointer to the memory block in global structure mem3. */
++ assert( sizeof(Mem3Block)==8 );
++ mem3.aPool = (Mem3Block *)sqlite3GlobalConfig.pHeap;
++ mem3.nPool = (sqlite3GlobalConfig.nHeap / sizeof(Mem3Block)) - 2;
+
+-/*
+-** Allocate and zero memory.
+-*/
+-SQLITE_PRIVATE void *sqlite3MallocZero(int n){
+- void *p = sqlite3Malloc(n);
+- if( p ){
+- memset(p, 0, n);
+- }
+- return p;
++ /* Initialize the master block. */
++ mem3.szMaster = mem3.nPool;
++ mem3.mnMaster = mem3.szMaster;
++ mem3.iMaster = 1;
++ mem3.aPool[0].u.hdr.size4x = (mem3.szMaster<<2) + 2;
++ mem3.aPool[mem3.nPool].u.hdr.prevSize = mem3.nPool;
++ mem3.aPool[mem3.nPool].u.hdr.size4x = 1;
++
++ return SQLITE_OK;
+ }
+
+ /*
+-** Allocate and zero memory. If the allocation fails, make
+-** the mallocFailed flag in the connection pointer.
++** Deinitialize this module.
+ */
+-SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3 *db, int n){
+- void *p = sqlite3DbMallocRaw(db, n);
+- if( p ){
+- memset(p, 0, n);
+- }
+- return p;
++static void memsys3Shutdown(void *NotUsed){
++ UNUSED_PARAMETER(NotUsed);
++ mem3.mutex = 0;
++ return;
+ }
+
++
++
+ /*
+-** Allocate and zero memory. If the allocation fails, make
+-** the mallocFailed flag in the connection pointer.
+-**
+-** If db!=0 and db->mallocFailed is true (indicating a prior malloc
+-** failure on the same database connection) then always return 0.
+-** Hence for a particular database connection, once malloc starts
+-** failing, it fails consistently until mallocFailed is reset.
+-** This is an important assumption. There are many places in the
+-** code that do things like this:
+-**
+-** int *a = (int*)sqlite3DbMallocRaw(db, 100);
+-** int *b = (int*)sqlite3DbMallocRaw(db, 200);
+-** if( b ) a[10] = 9;
+-**
+-** In other words, if a subsequent malloc (ex: "b") worked, it is assumed
+-** that all prior mallocs (ex: "a") worked too.
++** Open the file indicated and write a log of all unfreed memory
++** allocations into that log.
+ */
+-SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3 *db, int n){
+- void *p;
+- assert( db==0 || sqlite3_mutex_held(db->mutex) );
+- assert( db==0 || db->pnBytesFreed==0 );
+-#ifndef SQLITE_OMIT_LOOKASIDE
+- if( db ){
+- LookasideSlot *pBuf;
+- if( db->mallocFailed ){
+- return 0;
+- }
+- if( db->lookaside.bEnabled ){
+- if( n>db->lookaside.sz ){
+- db->lookaside.anStat[1]++;
+- }else if( (pBuf = db->lookaside.pFree)==0 ){
+- db->lookaside.anStat[2]++;
+- }else{
+- db->lookaside.pFree = pBuf->pNext;
+- db->lookaside.nOut++;
+- db->lookaside.anStat[0]++;
+- if( db->lookaside.nOut>db->lookaside.mxOut ){
+- db->lookaside.mxOut = db->lookaside.nOut;
+- }
+- return (void*)pBuf;
+- }
++SQLITE_PRIVATE void sqlite3Memsys3Dump(const char *zFilename){
++#ifdef SQLITE_DEBUG
++ FILE *out;
++ u32 i, j;
++ u32 size;
++ if( zFilename==0 || zFilename[0]==0 ){
++ out = stdout;
++ }else{
++ out = fopen(zFilename, "w");
++ if( out==0 ){
++ fprintf(stderr, "** Unable to output memory debug output log: %s **\n",
++ zFilename);
++ return;
+ }
+ }
+-#else
+- if( db && db->mallocFailed ){
+- return 0;
+- }
+-#endif
+- p = sqlite3Malloc(n);
+- if( !p && db ){
+- db->mallocFailed = 1;
+- }
+- sqlite3MemdebugSetType(p, MEMTYPE_DB |
+- ((db && db->lookaside.bEnabled) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP));
+- return p;
+-}
+-
+-/*
+-** 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){
+- void *pNew = 0;
+- assert( db!=0 );
+- assert( sqlite3_mutex_held(db->mutex) );
+- if( db->mallocFailed==0 ){
+- if( p==0 ){
+- return sqlite3DbMallocRaw(db, n);
++ memsys3Enter();
++ fprintf(out, "CHUNKS:\n");
++ for(i=1; i<=mem3.nPool; i+=size/4){
++ size = mem3.aPool[i-1].u.hdr.size4x;
++ if( size/4<=1 ){
++ fprintf(out, "%p size error\n", &mem3.aPool[i]);
++ assert( 0 );
++ break;
+ }
+- if( isLookaside(db, p) ){
+- if( n<=db->lookaside.sz ){
+- return p;
+- }
+- pNew = sqlite3DbMallocRaw(db, n);
+- if( pNew ){
+- memcpy(pNew, p, db->lookaside.sz);
+- sqlite3DbFree(db, p);
+- }
++ if( (size&1)==0 && mem3.aPool[i+size/4-1].u.hdr.prevSize!=size/4 ){
++ fprintf(out, "%p tail size does not match\n", &mem3.aPool[i]);
++ assert( 0 );
++ break;
++ }
++ if( ((mem3.aPool[i+size/4-1].u.hdr.size4x&2)>>1)!=(size&1) ){
++ fprintf(out, "%p tail checkout bit is incorrect\n", &mem3.aPool[i]);
++ assert( 0 );
++ break;
++ }
++ if( size&1 ){
++ fprintf(out, "%p %6d bytes checked out\n", &mem3.aPool[i], (size/4)*8-8);
+ }else{
+- assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) );
+- assert( sqlite3MemdebugHasType(p, MEMTYPE_LOOKASIDE|MEMTYPE_HEAP) );
+- sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
+- pNew = sqlite3_realloc(p, n);
+- if( !pNew ){
+- sqlite3MemdebugSetType(p, MEMTYPE_DB|MEMTYPE_HEAP);
+- db->mallocFailed = 1;
+- }
+- sqlite3MemdebugSetType(pNew, MEMTYPE_DB |
+- (db->lookaside.bEnabled ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP));
++ fprintf(out, "%p %6d bytes free%s\n", &mem3.aPool[i], (size/4)*8-8,
++ i==mem3.iMaster ? " **master**" : "");
+ }
+ }
+- return pNew;
++ for(i=0; i<MX_SMALL-1; i++){
++ if( mem3.aiSmall[i]==0 ) continue;
++ fprintf(out, "small(%2d):", i);
++ for(j = mem3.aiSmall[i]; j>0; j=mem3.aPool[j].u.list.next){
++ fprintf(out, " %p(%d)", &mem3.aPool[j],
++ (mem3.aPool[j-1].u.hdr.size4x/4)*8-8);
++ }
++ fprintf(out, "\n");
++ }
++ for(i=0; i<N_HASH; i++){
++ if( mem3.aiHash[i]==0 ) continue;
++ fprintf(out, "hash(%2d):", i);
++ for(j = mem3.aiHash[i]; j>0; j=mem3.aPool[j].u.list.next){
++ fprintf(out, " %p(%d)", &mem3.aPool[j],
++ (mem3.aPool[j-1].u.hdr.size4x/4)*8-8);
++ }
++ fprintf(out, "\n");
++ }
++ fprintf(out, "master=%d\n", mem3.iMaster);
++ fprintf(out, "nowUsed=%d\n", mem3.nPool*8 - mem3.szMaster*8);
++ fprintf(out, "mxUsed=%d\n", mem3.nPool*8 - mem3.mnMaster*8);
++ sqlite3_mutex_leave(mem3.mutex);
++ if( out==stdout ){
++ fflush(stdout);
++ }else{
++ fclose(out);
++ }
++#else
++ UNUSED_PARAMETER(zFilename);
++#endif
+ }
+
+ /*
+-** Attempt to reallocate p. If the reallocation fails, then free p
+-** and set the mallocFailed flag in the database connection.
++** This routine is the only routine in this file with external
++** linkage.
++**
++** 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 void *sqlite3DbReallocOrFree(sqlite3 *db, void *p, int n){
+- void *pNew;
+- pNew = sqlite3DbRealloc(db, p, n);
+- if( !pNew ){
+- sqlite3DbFree(db, p);
+- }
+- return pNew;
++SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void){
++ static const sqlite3_mem_methods mempoolMethods = {
++ memsys3Malloc,
++ memsys3Free,
++ memsys3Realloc,
++ memsys3Size,
++ memsys3Roundup,
++ memsys3Init,
++ memsys3Shutdown,
++ 0
++ };
++ return &mempoolMethods;
+ }
+
++#endif /* SQLITE_ENABLE_MEMSYS3 */
++
++/************** End of mem3.c ************************************************/
++/************** Begin file mem5.c ********************************************/
+ /*
+-** Make a copy of a string in memory obtained from sqliteMalloc(). These
+-** functions call sqlite3MallocRaw() directly instead of sqliteMalloc(). This
+-** is because when memory debugging is turned on, these two functions are
+-** called via macros that record the current file and line number in the
+-** ThreadData structure.
++** 2007 October 14
++**
++** The author disclaims copyright to this source code. In place of
++** a legal notice, here is a blessing:
++**
++** May you do good and not evil.
++** May you find forgiveness for yourself and forgive others.
++** May you share freely, never taking more than you give.
++**
++*************************************************************************
++** This file contains the C functions that implement a memory
++** allocation subsystem for use by SQLite.
++**
++** This version of the memory allocation subsystem omits all
++** use of malloc(). The application gives SQLite a block of memory
++** before calling sqlite3_initialize() from which allocations
++** are made and returned by the xMalloc() and xRealloc()
++** implementations. Once sqlite3_initialize() has been called,
++** the amount of memory available to SQLite is fixed and cannot
++** be changed.
++**
++** This version of the memory allocation subsystem is included
++** in the build only if SQLITE_ENABLE_MEMSYS5 is defined.
++**
++** This memory allocator uses the following algorithm:
++**
++** 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.
++**
++** 3. New memory is allocated from the first available free block.
++**
++** This algorithm is described in: J. M. Robson. "Bounds for Some Functions
++** Concerning Dynamic Storage Allocation". Journal of the Association for
++** Computing Machinery, Volume 21, Number 8, July 1974, pages 491-499.
++**
++** Let n be the size of the largest allocation divided by the minimum
++** allocation size (after rounding all sizes up to a power of 2.) Let M
++** be the maximum amount of memory ever outstanding at one time. Let
++** N be the total amount of memory available for allocation. Robson
++** proved that this memory allocator will never breakdown due to
++** fragmentation as long as the following constraint holds:
++**
++** N >= M*(1 + log2(n)/2) - n + 1
++**
++** The sqlite3_status() logic tracks the maximum values of n and M so
++** that an application can, at any time, verify this constraint.
+ */
+-SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3 *db, const char *z){
+- char *zNew;
+- size_t n;
+- if( z==0 ){
+- return 0;
+- }
+- n = sqlite3Strlen30(z) + 1;
+- assert( (n&0x7fffffff)==n );
+- zNew = sqlite3DbMallocRaw(db, (int)n);
+- if( zNew ){
+- memcpy(zNew, z, n);
+- }
+- return zNew;
+-}
+-SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3 *db, const char *z, int n){
+- char *zNew;
+- if( z==0 ){
+- return 0;
+- }
+- assert( (n&0x7fffffff)==n );
+- zNew = sqlite3DbMallocRaw(db, n+1);
+- if( zNew ){
+- memcpy(zNew, z, n);
+- zNew[n] = 0;
+- }
+- return zNew;
+-}
+
+ /*
+-** Create a string from the zFromat argument and the va_list that follows.
+-** Store the string in memory obtained from sqliteMalloc() and make *pz
+-** point to that string.
++** This version of the memory allocator is used only when
++** SQLITE_ENABLE_MEMSYS5 is defined.
+ */
+-SQLITE_PRIVATE void sqlite3SetString(char **pz, sqlite3 *db, const char *zFormat, ...){
+- va_list ap;
+- char *z;
+-
+- va_start(ap, zFormat);
+- z = sqlite3VMPrintf(db, zFormat, ap);
+- va_end(ap);
+- sqlite3DbFree(db, *pz);
+- *pz = z;
+-}
+-
++#ifdef SQLITE_ENABLE_MEMSYS5
+
+ /*
+-** This function must be called before exiting any API function (i.e.
+-** returning control to the user) that has called sqlite3_malloc or
+-** sqlite3_realloc.
+-**
+-** The returned value is normally a copy of the second argument to this
+-** function. However, if a malloc() failure has occurred since the previous
+-** invocation SQLITE_NOMEM is returned instead.
++** A minimum allocation is an instance of the following structure.
++** Larger allocations are an array of these structures where the
++** size of the array is a power of 2.
+ **
+-** If the first argument, db, is not NULL and a malloc() error has occurred,
+-** then the connection error-code (the value returned by sqlite3_errcode())
+-** is set to SQLITE_NOMEM.
++** The size of this object must be a power of two. That fact is
++** verified in memsys5Init().
+ */
+-SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){
+- /* If the db handle is not NULL, then we must hold the connection handle
+- ** mutex here. Otherwise the read (and possible write) of db->mallocFailed
+- ** 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;
+- }
+- return rc & (db ? db->errMask : 0xff);
+-}
++typedef struct Mem5Link Mem5Link;
++struct Mem5Link {
++ int next; /* Index of next free chunk */
++ int prev; /* Index of previous free chunk */
++};
+
+-/************** End of malloc.c **********************************************/
+-/************** Begin file printf.c ******************************************/
+ /*
+-** The "printf" code that follows dates from the 1980's. It is in
+-** the public domain. The original comments are included here for
+-** completeness. They are very out-of-date but might be useful as
+-** an historical reference. Most of the "enhancements" have been backed
+-** out so that the functionality is now the same as standard printf().
+-**
+-**************************************************************************
+-**
+-** This file contains code for a set of "printf"-like routines. These
+-** routines format strings much like the printf() from the standard C
+-** library, though the implementation here has enhancements to support
+-** SQLlite.
++** Maximum size of any allocation is ((1<<LOGMAX)*mem5.szAtom). Since
++** mem5.szAtom is always at least 8 and 32-bit integers are used,
++** it is not actually possible to reach this limit.
+ */
++#define LOGMAX 30
+
+ /*
+-** Conversion types fall into various categories as defined by the
+-** following enumeration.
++** Masks used for mem5.aCtrl[] elements.
+ */
+-#define etRADIX 1 /* Integer types. %d, %x, %o, and so forth */
+-#define etFLOAT 2 /* Floating point. %f */
+-#define etEXP 3 /* Exponentional notation. %e and %E */
+-#define etGENERIC 4 /* Floating or exponential, depending on exponent. %g */
+-#define etSIZE 5 /* Return number of characters processed so far. %n */
+-#define etSTRING 6 /* Strings. %s */
+-#define etDYNSTRING 7 /* Dynamically allocated strings. %z */
+-#define etPERCENT 8 /* Percent symbol. %% */
+-#define etCHARX 9 /* Characters. %c */
+-/* The rest are extensions, not normally found in printf() */
+-#define etSQLESCAPE 10 /* Strings with '\'' doubled. %q */
+-#define etSQLESCAPE2 11 /* Strings with '\'' doubled and enclosed in '',
+- NULL pointers replaced by SQL NULL. %Q */
+-#define etTOKEN 12 /* a pointer to a Token structure */
+-#define etSRCLIST 13 /* a pointer to a SrcList */
+-#define etPOINTER 14 /* The %p conversion */
+-#define etSQLESCAPE3 15 /* %w -> Strings with '\"' doubled */
+-#define etORDINAL 16 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */
++#define CTRL_LOGSIZE 0x1f /* Log2 Size of this block */
++#define CTRL_FREE 0x20 /* True if not checked out */
+
+-#define etINVALID 0 /* Any unrecognized conversion type */
++/*
++** All of the static variables used by this module are collected
++** into a single structure named "mem5". This is to keep the
++** static variables organized and to reduce namespace pollution
++** when this module is combined with other in the amalgamation.
++*/
++static SQLITE_WSD struct Mem5Global {
++ /*
++ ** Memory available for allocation
++ */
++ int szAtom; /* Smallest possible allocation in bytes */
++ int nBlock; /* Number of szAtom sized blocks in zPool */
++ u8 *zPool; /* Memory available to be allocated */
++
++ /*
++ ** Mutex to control access to the memory allocation subsystem.
++ */
++ sqlite3_mutex *mutex;
++
++ /*
++ ** Performance statistics
++ */
++ u64 nAlloc; /* Total number of calls to malloc */
++ u64 totalAlloc; /* Total of all malloc calls - includes internal frag */
++ u64 totalExcess; /* Total internal fragmentation */
++ u32 currentOut; /* Current checkout, including internal fragmentation */
++ u32 currentCount; /* Current number of distinct checkouts */
++ u32 maxOut; /* Maximum instantaneous currentOut */
++ u32 maxCount; /* Maximum instantaneous currentCount */
++ u32 maxRequest; /* Largest allocation (exclusive of internal frag) */
++
++ /*
++ ** Lists of free blocks. aiFreelist[0] is a list of free blocks of
++ ** size mem5.szAtom. aiFreelist[1] holds blocks of size szAtom*2.
++ ** and so forth.
++ */
++ int aiFreelist[LOGMAX+1];
++
++ /*
++ ** Space for tracking which blocks are checked out and the size
++ ** of each block. One byte per block.
++ */
++ u8 *aCtrl;
+
++} mem5;
+
+ /*
+-** An "etByte" is an 8-bit unsigned value.
++** Access the static variable through a macro for SQLITE_OMIT_WSD
+ */
+-typedef unsigned char etByte;
++#define mem5 GLOBAL(struct Mem5Global, mem5)
+
+ /*
+-** Each builtin conversion character (ex: the 'd' in "%d") is described
+-** by an instance of the following structure
++** Assuming mem5.zPool is divided up into an array of Mem5Link
++** structures, return a pointer to the idx-th such lik.
+ */
+-typedef struct et_info { /* Information about each format field */
+- char fmttype; /* The format field code letter */
+- etByte base; /* The base for radix conversion */
+- etByte flags; /* One or more of FLAG_ constants below */
+- etByte type; /* Conversion paradigm */
+- etByte charset; /* Offset into aDigits[] of the digits string */
+- etByte prefix; /* Offset into aPrefix[] of the prefix string */
+-} et_info;
++#define MEM5LINK(idx) ((Mem5Link *)(&mem5.zPool[(idx)*mem5.szAtom]))
+
+ /*
+-** Allowed values for et_info.flags
++** Unlink the chunk at mem5.aPool[i] from list it is currently
++** on. It should be found on mem5.aiFreelist[iLogsize].
+ */
+-#define FLAG_SIGNED 1 /* True if the value to convert is signed */
+-#define FLAG_INTERN 2 /* True if for internal use only */
+-#define FLAG_STRING 4 /* Allow infinity precision */
++static void memsys5Unlink(int i, int iLogsize){
++ int next, prev;
++ assert( i>=0 && i<mem5.nBlock );
++ assert( iLogsize>=0 && iLogsize<=LOGMAX );
++ assert( (mem5.aCtrl[i] & CTRL_LOGSIZE)==iLogsize );
+
++ next = MEM5LINK(i)->next;
++ prev = MEM5LINK(i)->prev;
++ if( prev<0 ){
++ mem5.aiFreelist[iLogsize] = next;
++ }else{
++ MEM5LINK(prev)->next = next;
++ }
++ if( next>=0 ){
++ MEM5LINK(next)->prev = prev;
++ }
++}
+
+ /*
+-** The following table is searched linearly, so it is good to put the
+-** most frequently used conversion types first.
++** Link the chunk at mem5.aPool[i] so that is on the iLogsize
++** free list.
+ */
+-static const char aDigits[] = "0123456789ABCDEF0123456789abcdef";
+-static const char aPrefix[] = "-x0\000X0";
+-static const et_info fmtinfo[] = {
+- { 'd', 10, 1, etRADIX, 0, 0 },
+- { 's', 0, 4, etSTRING, 0, 0 },
+- { 'g', 0, 1, etGENERIC, 30, 0 },
+- { 'z', 0, 4, etDYNSTRING, 0, 0 },
+- { 'q', 0, 4, etSQLESCAPE, 0, 0 },
+- { 'Q', 0, 4, etSQLESCAPE2, 0, 0 },
+- { 'w', 0, 4, etSQLESCAPE3, 0, 0 },
+- { 'c', 0, 0, etCHARX, 0, 0 },
+- { 'o', 8, 0, etRADIX, 0, 2 },
+- { 'u', 10, 0, etRADIX, 0, 0 },
+- { 'x', 16, 0, etRADIX, 16, 1 },
+- { 'X', 16, 0, etRADIX, 0, 4 },
+-#ifndef SQLITE_OMIT_FLOATING_POINT
+- { 'f', 0, 1, etFLOAT, 0, 0 },
+- { 'e', 0, 1, etEXP, 30, 0 },
+- { 'E', 0, 1, etEXP, 14, 0 },
+- { 'G', 0, 1, etGENERIC, 14, 0 },
+-#endif
+- { 'i', 10, 1, etRADIX, 0, 0 },
+- { 'n', 0, 0, etSIZE, 0, 0 },
+- { '%', 0, 0, etPERCENT, 0, 0 },
+- { 'p', 16, 0, etPOINTER, 0, 1 },
++static void memsys5Link(int i, int iLogsize){
++ int x;
++ assert( sqlite3_mutex_held(mem5.mutex) );
++ assert( i>=0 && i<mem5.nBlock );
++ assert( iLogsize>=0 && iLogsize<=LOGMAX );
++ assert( (mem5.aCtrl[i] & CTRL_LOGSIZE)==iLogsize );
+
+-/* All the rest have the FLAG_INTERN bit set and are thus for internal
+-** use only */
+- { 'T', 0, 2, etTOKEN, 0, 0 },
+- { 'S', 0, 2, etSRCLIST, 0, 0 },
+- { 'r', 10, 3, etORDINAL, 0, 0 },
+-};
++ x = MEM5LINK(i)->next = mem5.aiFreelist[iLogsize];
++ MEM5LINK(i)->prev = -1;
++ if( x>=0 ){
++ assert( x<mem5.nBlock );
++ MEM5LINK(x)->prev = i;
++ }
++ mem5.aiFreelist[iLogsize] = i;
++}
+
+ /*
+-** If SQLITE_OMIT_FLOATING_POINT is defined, then none of the floating point
+-** conversions will work.
++** If the STATIC_MEM mutex is not already held, obtain it now. The mutex
++** will already be held (obtained by code in malloc.c) if
++** sqlite3GlobalConfig.bMemStat is true.
+ */
+-#ifndef SQLITE_OMIT_FLOATING_POINT
++static void memsys5Enter(void){
++ sqlite3_mutex_enter(mem5.mutex);
++}
++static void memsys5Leave(void){
++ sqlite3_mutex_leave(mem5.mutex);
++}
++
+ /*
+-** "*val" is a double such that 0.1 <= *val < 10.0
+-** Return the ascii code for the leading digit of *val, then
+-** multiply "*val" by 10.0 to renormalize.
+-**
+-** Example:
+-** input: *val = 3.14159
+-** output: *val = 1.4159 function return = '3'
+-**
+-** The counter *cnt is incremented each time. After counter exceeds
+-** 16 (the number of significant digits in a 64-bit float) '0' is
+-** always returned.
++** Return the size of an outstanding allocation, in bytes. The
++** size returned omits the 8-byte header overhead. This only
++** works for chunks that are currently checked out.
+ */
+-static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
+- int digit;
+- LONGDOUBLE_TYPE d;
+- if( (*cnt)<=0 ) return '0';
+- (*cnt)--;
+- digit = (int)*val;
+- d = digit;
+- digit += '0';
+- *val = (*val - d)*10.0;
+- return (char)digit;
++static int memsys5Size(void *p){
++ int iSize = 0;
++ if( p ){
++ int i = ((u8 *)p-mem5.zPool)/mem5.szAtom;
++ assert( i>=0 && i<mem5.nBlock );
++ iSize = mem5.szAtom * (1 << (mem5.aCtrl[i]&CTRL_LOGSIZE));
++ }
++ return iSize;
+ }
+-#endif /* SQLITE_OMIT_FLOATING_POINT */
+
+ /*
+-** Append N space characters to the given string buffer.
++** Find the first entry on the freelist iLogsize. Unlink that
++** entry and return its index.
+ */
+-SQLITE_PRIVATE void sqlite3AppendSpace(StrAccum *pAccum, int N){
+- static const char zSpaces[] = " ";
+- while( N>=(int)sizeof(zSpaces)-1 ){
+- sqlite3StrAccumAppend(pAccum, zSpaces, sizeof(zSpaces)-1);
+- N -= sizeof(zSpaces)-1;
+- }
+- if( N>0 ){
+- sqlite3StrAccumAppend(pAccum, zSpaces, N);
++static int memsys5UnlinkFirst(int iLogsize){
++ int i;
++ int iFirst;
++
++ assert( iLogsize>=0 && iLogsize<=LOGMAX );
++ i = iFirst = mem5.aiFreelist[iLogsize];
++ assert( iFirst>=0 );
++ while( i>0 ){
++ if( i<iFirst ) iFirst = i;
++ i = MEM5LINK(i)->next;
+ }
++ memsys5Unlink(iFirst, iLogsize);
++ return iFirst;
+ }
+
+ /*
+-** On machines with a small stack size, you can redefine the
+-** SQLITE_PRINT_BUF_SIZE to be something smaller, if desired.
++** Return a block of memory of at least nBytes in size.
++** Return NULL if unable. Return NULL if nBytes==0.
++**
++** The caller guarantees that nByte positive.
++**
++** The caller has obtained a mutex prior to invoking this
++** routine so there is never any chance that two or more
++** threads can be in this routine at the same time.
+ */
+-#ifndef SQLITE_PRINT_BUF_SIZE
+-# define SQLITE_PRINT_BUF_SIZE 70
+-#endif
+-#define etBUFSIZE SQLITE_PRINT_BUF_SIZE /* Size of the output buffer */
++static void *memsys5MallocUnsafe(int nByte){
++ int i; /* Index of a mem5.aPool[] slot */
++ int iBin; /* Index into mem5.aiFreelist[] */
++ int iFullSz; /* Size of allocation rounded up to power of 2 */
++ int iLogsize; /* Log2 of iFullSz/POW2_MIN */
++
++ /* nByte must be a positive */
++ assert( nByte>0 );
++
++ /* Keep track of the maximum allocation request. Even unfulfilled
++ ** requests are counted */
++ if( (u32)nByte>mem5.maxRequest ){
++ mem5.maxRequest = nByte;
++ }
++
++ /* Abort if the requested allocation size is larger than the largest
++ ** power of two that we can represent using 32-bit signed integers.
++ */
++ if( nByte > 0x40000000 ){
++ return 0;
++ }
++
++ /* Round nByte up to the next valid power of two */
++ for(iFullSz=mem5.szAtom, iLogsize=0; iFullSz<nByte; iFullSz *= 2, iLogsize++){}
++
++ /* Make sure mem5.aiFreelist[iLogsize] contains at least one free
++ ** block. If not, then split a block of the next larger power of
++ ** two in order to create a new free block of size iLogsize.
++ */
++ for(iBin=iLogsize; mem5.aiFreelist[iBin]<0 && iBin<=LOGMAX; iBin++){}
++ if( iBin>LOGMAX ){
++ testcase( sqlite3GlobalConfig.xLog!=0 );
++ sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes", nByte);
++ return 0;
++ }
++ i = memsys5UnlinkFirst(iBin);
++ while( iBin>iLogsize ){
++ int newSize;
++
++ iBin--;
++ newSize = 1 << iBin;
++ mem5.aCtrl[i+newSize] = CTRL_FREE | iBin;
++ memsys5Link(i+newSize, iBin);
++ }
++ mem5.aCtrl[i] = iLogsize;
++
++ /* Update allocator performance statistics. */
++ mem5.nAlloc++;
++ mem5.totalAlloc += iFullSz;
++ mem5.totalExcess += iFullSz - nByte;
++ mem5.currentCount++;
++ mem5.currentOut += iFullSz;
++ if( mem5.maxCount<mem5.currentCount ) mem5.maxCount = mem5.currentCount;
++ if( mem5.maxOut<mem5.currentOut ) mem5.maxOut = mem5.currentOut;
++
++ /* Return a pointer to the allocated memory. */
++ return (void*)&mem5.zPool[i*mem5.szAtom];
++}
+
+ /*
+-** Render a string given by "fmt" into the StrAccum object.
++** Free an outstanding memory allocation.
+ */
+-SQLITE_PRIVATE void sqlite3VXPrintf(
+- StrAccum *pAccum, /* Accumulate results here */
+- int useExtended, /* Allow extended %-conversions */
+- const char *fmt, /* Format string */
+- va_list ap /* arguments */
+-){
+- int c; /* Next character in the format string */
+- char *bufpt; /* Pointer to the conversion buffer */
+- int precision; /* Precision of the current field */
+- int length; /* Length of the field */
+- int idx; /* A general purpose loop counter */
+- int width; /* Width of the current field */
+- etByte flag_leftjustify; /* True if "-" flag is present */
+- etByte flag_plussign; /* True if "+" flag is present */
+- etByte flag_blanksign; /* True if " " flag is present */
+- etByte flag_alternateform; /* True if "#" flag is present */
+- etByte flag_altform2; /* True if "!" flag is present */
+- etByte flag_zeropad; /* True if field width constant starts with zero */
+- etByte flag_long; /* True if "l" flag is present */
+- etByte flag_longlong; /* True if the "ll" flag is present */
+- etByte done; /* Loop termination flag */
+- etByte xtype = 0; /* Conversion paradigm */
+- char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */
+- sqlite_uint64 longvalue; /* Value for integer types */
+- LONGDOUBLE_TYPE realvalue; /* Value for real types */
+- 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 */
+-#ifndef SQLITE_OMIT_FLOATING_POINT
+- int exp, e2; /* exponent of real numbers */
+- int nsd; /* Number of significant digits returned */
+- double rounder; /* Used for rounding floating point values */
+- etByte flag_dp; /* True if decimal point should be shown */
+- etByte flag_rtz; /* True if trailing zeros should be removed */
+-#endif
+- char buf[etBUFSIZE]; /* Conversion buffer */
++static void memsys5FreeUnsafe(void *pOld){
++ u32 size, iLogsize;
++ int iBlock;
+
+- bufpt = 0;
+- for(; (c=(*fmt))!=0; ++fmt){
+- if( c!='%' ){
+- int amt;
+- bufpt = (char *)fmt;
+- amt = 1;
+- while( (c=(*++fmt))!='%' && c!=0 ) amt++;
+- sqlite3StrAccumAppend(pAccum, bufpt, amt);
+- if( c==0 ) break;
+- }
+- if( (c=(*++fmt))==0 ){
+- sqlite3StrAccumAppend(pAccum, "%", 1);
+- break;
+- }
+- /* Find out what flags are present */
+- flag_leftjustify = flag_plussign = flag_blanksign =
+- flag_alternateform = flag_altform2 = flag_zeropad = 0;
+- done = 0;
+- do{
+- switch( c ){
+- case '-': flag_leftjustify = 1; break;
+- case '+': flag_plussign = 1; break;
+- case ' ': flag_blanksign = 1; break;
+- case '#': flag_alternateform = 1; break;
+- case '!': flag_altform2 = 1; break;
+- case '0': flag_zeropad = 1; break;
+- default: done = 1; break;
+- }
+- }while( !done && (c=(*++fmt))!=0 );
+- /* Get the field width */
+- width = 0;
+- if( c=='*' ){
+- width = va_arg(ap,int);
+- if( width<0 ){
+- flag_leftjustify = 1;
+- width = -width;
+- }
+- c = *++fmt;
++ /* Set iBlock to the index of the block pointed to by pOld in
++ ** the array of mem5.szAtom byte blocks pointed to by mem5.zPool.
++ */
++ iBlock = ((u8 *)pOld-mem5.zPool)/mem5.szAtom;
++
++ /* Check that the pointer pOld points to a valid, non-free block. */
++ assert( iBlock>=0 && iBlock<mem5.nBlock );
++ assert( ((u8 *)pOld-mem5.zPool)%mem5.szAtom==0 );
++ assert( (mem5.aCtrl[iBlock] & CTRL_FREE)==0 );
++
++ iLogsize = mem5.aCtrl[iBlock] & CTRL_LOGSIZE;
++ size = 1<<iLogsize;
++ assert( iBlock+size-1<(u32)mem5.nBlock );
++
++ mem5.aCtrl[iBlock] |= CTRL_FREE;
++ mem5.aCtrl[iBlock+size-1] |= CTRL_FREE;
++ assert( mem5.currentCount>0 );
++ assert( mem5.currentOut>=(size*mem5.szAtom) );
++ mem5.currentCount--;
++ mem5.currentOut -= size*mem5.szAtom;
++ assert( mem5.currentOut>0 || mem5.currentCount==0 );
++ assert( mem5.currentCount>0 || mem5.currentOut==0 );
++
++ mem5.aCtrl[iBlock] = CTRL_FREE | iLogsize;
++ while( ALWAYS(iLogsize<LOGMAX) ){
++ int iBuddy;
++ if( (iBlock>>iLogsize) & 1 ){
++ iBuddy = iBlock - size;
+ }else{
+- while( c>='0' && c<='9' ){
+- width = width*10 + c - '0';
+- c = *++fmt;
+- }
++ iBuddy = iBlock + size;
+ }
+- /* Get the precision */
+- if( c=='.' ){
+- precision = 0;
+- c = *++fmt;
+- if( c=='*' ){
+- precision = va_arg(ap,int);
+- if( precision<0 ) precision = -precision;
+- c = *++fmt;
+- }else{
+- while( c>='0' && c<='9' ){
+- precision = precision*10 + c - '0';
+- c = *++fmt;
+- }
+- }
++ assert( iBuddy>=0 );
++ if( (iBuddy+(1<<iLogsize))>mem5.nBlock ) break;
++ if( mem5.aCtrl[iBuddy]!=(CTRL_FREE | iLogsize) ) break;
++ memsys5Unlink(iBuddy, iLogsize);
++ iLogsize++;
++ if( iBuddy<iBlock ){
++ mem5.aCtrl[iBuddy] = CTRL_FREE | iLogsize;
++ mem5.aCtrl[iBlock] = 0;
++ iBlock = iBuddy;
+ }else{
+- precision = -1;
++ mem5.aCtrl[iBlock] = CTRL_FREE | iLogsize;
++ mem5.aCtrl[iBuddy] = 0;
+ }
+- /* Get the conversion type modifier */
+- if( c=='l' ){
+- flag_long = 1;
+- c = *++fmt;
+- if( c=='l' ){
+- flag_longlong = 1;
+- c = *++fmt;
+- }else{
+- flag_longlong = 0;
+- }
+- }else{
+- flag_long = flag_longlong = 0;
++ size *= 2;
++ }
++ memsys5Link(iBlock, iLogsize);
++}
++
++/*
++** Allocate nBytes of memory
++*/
++static void *memsys5Malloc(int nBytes){
++ sqlite3_int64 *p = 0;
++ if( nBytes>0 ){
++ memsys5Enter();
++ p = memsys5MallocUnsafe(nBytes);
++ memsys5Leave();
++ }
++ return (void*)p;
++}
++
++/*
++** Free memory.
++**
++** The outer layer memory allocator prevents this routine from
++** being called with pPrior==0.
++*/
++static void memsys5Free(void *pPrior){
++ assert( pPrior!=0 );
++ memsys5Enter();
++ memsys5FreeUnsafe(pPrior);
++ memsys5Leave();
++}
++
++/*
++** Change the size of an existing memory allocation.
++**
++** The outer layer memory allocator prevents this routine from
++** being called with pPrior==0.
++**
++** nBytes is always a value obtained from a prior call to
++** memsys5Round(). Hence nBytes is always a non-negative power
++** of two. If nBytes==0 that means that an oversize allocation
++** (an allocation larger than 0x40000000) was requested and this
++** routine should return 0 without freeing pPrior.
++*/
++static void *memsys5Realloc(void *pPrior, int nBytes){
++ int nOld;
++ void *p;
++ assert( pPrior!=0 );
++ assert( (nBytes&(nBytes-1))==0 ); /* EV: R-46199-30249 */
++ assert( nBytes>=0 );
++ if( nBytes==0 ){
++ return 0;
++ }
++ nOld = memsys5Size(pPrior);
++ if( nBytes<=nOld ){
++ return pPrior;
++ }
++ memsys5Enter();
++ p = memsys5MallocUnsafe(nBytes);
++ if( p ){
++ memcpy(p, pPrior, nOld);
++ memsys5FreeUnsafe(pPrior);
++ }
++ memsys5Leave();
++ return p;
++}
++
++/*
++** Round up a request size to the next valid allocation size. If
++** the allocation is too large to be handled by this allocation system,
++** return 0.
++**
++** All allocations must be a power of two and must be expressed by a
++** 32-bit signed integer. Hence the largest allocation is 0x40000000
++** or 1073741824 bytes.
++*/
++static int memsys5Roundup(int n){
++ int iFullSz;
++ if( n > 0x40000000 ) return 0;
++ for(iFullSz=mem5.szAtom; iFullSz<n; iFullSz *= 2);
++ return iFullSz;
++}
++
++/*
++** Return the ceiling of the logarithm base 2 of iValue.
++**
++** Examples: memsys5Log(1) -> 0
++** memsys5Log(2) -> 1
++** memsys5Log(4) -> 2
++** memsys5Log(5) -> 3
++** memsys5Log(8) -> 3
++** memsys5Log(9) -> 4
++*/
++static int memsys5Log(int iValue){
++ int iLog;
++ for(iLog=0; (iLog<(int)((sizeof(int)*8)-1)) && (1<<iLog)<iValue; iLog++);
++ return iLog;
++}
++
++/*
++** Initialize the memory allocator.
++**
++** This routine is not threadsafe. The caller must be holding a mutex
++** to prevent multiple threads from entering at the same time.
++*/
++static int memsys5Init(void *NotUsed){
++ int ii; /* Loop counter */
++ int nByte; /* Number of bytes of memory available to this allocator */
++ u8 *zByte; /* Memory usable by this allocator */
++ int nMinLog; /* Log base 2 of minimum allocation size in bytes */
++ int iOffset; /* An offset into mem5.aCtrl[] */
++
++ UNUSED_PARAMETER(NotUsed);
++
++ /* For the purposes of this routine, disable the mutex */
++ mem5.mutex = 0;
++
++ /* The size of a Mem5Link object must be a power of two. Verify that
++ ** this is case.
++ */
++ assert( (sizeof(Mem5Link)&(sizeof(Mem5Link)-1))==0 );
++
++ nByte = sqlite3GlobalConfig.nHeap;
++ zByte = (u8*)sqlite3GlobalConfig.pHeap;
++ assert( zByte!=0 ); /* sqlite3_config() does not allow otherwise */
++
++ /* boundaries on sqlite3GlobalConfig.mnReq are enforced in sqlite3_config() */
++ nMinLog = memsys5Log(sqlite3GlobalConfig.mnReq);
++ mem5.szAtom = (1<<nMinLog);
++ while( (int)sizeof(Mem5Link)>mem5.szAtom ){
++ mem5.szAtom = mem5.szAtom << 1;
++ }
++
++ mem5.nBlock = (nByte / (mem5.szAtom+sizeof(u8)));
++ mem5.zPool = zByte;
++ mem5.aCtrl = (u8 *)&mem5.zPool[mem5.nBlock*mem5.szAtom];
++
++ for(ii=0; ii<=LOGMAX; ii++){
++ mem5.aiFreelist[ii] = -1;
++ }
++
++ iOffset = 0;
++ for(ii=LOGMAX; ii>=0; ii--){
++ int nAlloc = (1<<ii);
++ if( (iOffset+nAlloc)<=mem5.nBlock ){
++ mem5.aCtrl[iOffset] = ii | CTRL_FREE;
++ memsys5Link(iOffset, ii);
++ iOffset += nAlloc;
+ }
+- /* Fetch the info entry for the field */
+- infop = &fmtinfo[0];
+- xtype = etINVALID;
+- for(idx=0; idx<ArraySize(fmtinfo); idx++){
+- if( c==fmtinfo[idx].fmttype ){
+- infop = &fmtinfo[idx];
+- if( useExtended || (infop->flags & FLAG_INTERN)==0 ){
+- xtype = infop->type;
+- }else{
+- return;
+- }
+- break;
+- }
++ assert((iOffset+nAlloc)>mem5.nBlock);
++ }
++
++ /* If a mutex is required for normal operation, allocate one */
++ if( sqlite3GlobalConfig.bMemstat==0 ){
++ mem5.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
++ }
++
++ return SQLITE_OK;
++}
++
++/*
++** Deinitialize this module.
++*/
++static void memsys5Shutdown(void *NotUsed){
++ UNUSED_PARAMETER(NotUsed);
++ mem5.mutex = 0;
++ return;
++}
++
++#ifdef SQLITE_TEST
++/*
++** Open the file indicated and write a log of all unfreed memory
++** allocations into that log.
++*/
++SQLITE_PRIVATE void sqlite3Memsys5Dump(const char *zFilename){
++ FILE *out;
++ int i, j, n;
++ int nMinLog;
++
++ if( zFilename==0 || zFilename[0]==0 ){
++ out = stdout;
++ }else{
++ out = fopen(zFilename, "w");
++ if( out==0 ){
++ fprintf(stderr, "** Unable to output memory debug output log: %s **\n",
++ zFilename);
++ return;
+ }
+- zExtra = 0;
++ }
++ memsys5Enter();
++ nMinLog = memsys5Log(mem5.szAtom);
++ for(i=0; i<=LOGMAX && i+nMinLog<32; i++){
++ for(n=0, j=mem5.aiFreelist[i]; j>=0; j = MEM5LINK(j)->next, n++){}
++ fprintf(out, "freelist items of size %d: %d\n", mem5.szAtom << i, n);
++ }
++ fprintf(out, "mem5.nAlloc = %llu\n", mem5.nAlloc);
++ fprintf(out, "mem5.totalAlloc = %llu\n", mem5.totalAlloc);
++ fprintf(out, "mem5.totalExcess = %llu\n", mem5.totalExcess);
++ fprintf(out, "mem5.currentOut = %u\n", mem5.currentOut);
++ fprintf(out, "mem5.currentCount = %u\n", mem5.currentCount);
++ fprintf(out, "mem5.maxOut = %u\n", mem5.maxOut);
++ fprintf(out, "mem5.maxCount = %u\n", mem5.maxCount);
++ fprintf(out, "mem5.maxRequest = %u\n", mem5.maxRequest);
++ memsys5Leave();
++ if( out==stdout ){
++ fflush(stdout);
++ }else{
++ fclose(out);
++ }
++}
++#endif
+
+- /*
+- ** At this point, variables are initialized as follows:
+- **
+- ** flag_alternateform TRUE if a '#' is present.
+- ** flag_altform2 TRUE if a '!' is present.
+- ** flag_plussign TRUE if a '+' is present.
+- ** flag_leftjustify TRUE if a '-' is present or if the
+- ** field width was negative.
+- ** flag_zeropad TRUE if the width began with 0.
+- ** flag_long TRUE if the letter 'l' (ell) prefixed
+- ** the conversion character.
+- ** flag_longlong TRUE if the letter 'll' (ell ell) prefixed
+- ** the conversion character.
+- ** flag_blanksign TRUE if a ' ' is present.
+- ** width The specified field width. This is
+- ** always non-negative. Zero is the default.
+- ** precision The specified precision. The default
+- ** is -1.
+- ** xtype The class of the conversion.
+- ** infop Pointer to the appropriate info struct.
++/*
++** This routine is the only routine in this file with external
++** linkage. It returns a pointer to a static sqlite3_mem_methods
++** struct populated with the memsys5 methods.
++*/
++SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys5(void){
++ static const sqlite3_mem_methods memsys5Methods = {
++ memsys5Malloc,
++ memsys5Free,
++ memsys5Realloc,
++ memsys5Size,
++ memsys5Roundup,
++ memsys5Init,
++ memsys5Shutdown,
++ 0
++ };
++ return &memsys5Methods;
++}
++
++#endif /* SQLITE_ENABLE_MEMSYS5 */
++
++/************** End of mem5.c ************************************************/
++/************** Begin file mutex.c *******************************************/
++/*
++** 2007 August 14
++**
++** The author disclaims copyright to this source code. In place of
++** a legal notice, here is a blessing:
++**
++** May you do good and not evil.
++** May you find forgiveness for yourself and forgive others.
++** May you share freely, never taking more than you give.
++**
++*************************************************************************
++** This file contains the C functions that implement mutexes.
++**
++** This file contains code that is common across all mutex implementations.
++*/
++
++#if defined(SQLITE_DEBUG) && !defined(SQLITE_MUTEX_OMIT)
++/*
++** For debugging purposes, record when the mutex subsystem is initialized
++** and uninitialized so that we can assert() if there is an attempt to
++** allocate a mutex while the system is uninitialized.
++*/
++static SQLITE_WSD int mutexIsInit = 0;
++#endif /* SQLITE_DEBUG */
++
++
++#ifndef SQLITE_MUTEX_OMIT
++/*
++** Initialize the mutex system.
++*/
++SQLITE_PRIVATE int sqlite3MutexInit(void){
++ int rc = SQLITE_OK;
++ if( !sqlite3GlobalConfig.mutex.xMutexAlloc ){
++ /* If the xMutexAlloc method has not been set, then the user did not
++ ** install a mutex implementation via sqlite3_config() prior to
++ ** sqlite3_initialize() being called. This block copies pointers to
++ ** the default implementation into the sqlite3GlobalConfig structure.
+ */
+- switch( xtype ){
+- case etPOINTER:
+- flag_longlong = sizeof(char*)==sizeof(i64);
+- flag_long = sizeof(char*)==sizeof(long int);
+- /* Fall through into the next case */
+- case etORDINAL:
+- case etRADIX:
+- if( infop->flags & FLAG_SIGNED ){
+- i64 v;
+- if( flag_longlong ){
+- v = va_arg(ap,i64);
+- }else if( flag_long ){
+- v = va_arg(ap,long int);
+- }else{
+- v = va_arg(ap,int);
+- }
+- if( v<0 ){
+- if( v==SMALLEST_INT64 ){
+- longvalue = ((u64)1)<<63;
+- }else{
+- longvalue = -v;
+- }
+- prefix = '-';
+- }else{
+- longvalue = v;
+- if( flag_plussign ) prefix = '+';
+- else if( flag_blanksign ) prefix = ' ';
+- else prefix = 0;
+- }
+- }else{
+- if( flag_longlong ){
+- longvalue = va_arg(ap,u64);
+- }else if( flag_long ){
+- longvalue = va_arg(ap,unsigned long int);
+- }else{
+- longvalue = va_arg(ap,unsigned int);
+- }
+- prefix = 0;
+- }
+- if( longvalue==0 ) flag_alternateform = 0;
+- if( flag_zeropad && precision<width-(prefix!=0) ){
+- precision = width-(prefix!=0);
+- }
+- if( precision<etBUFSIZE-10 ){
+- nOut = etBUFSIZE;
+- zOut = buf;
+- }else{
+- nOut = precision + 10;
+- zOut = zExtra = sqlite3Malloc( nOut );
+- if( zOut==0 ){
+- pAccum->mallocFailed = 1;
+- return;
+- }
+- }
+- bufpt = &zOut[nOut-1];
+- if( xtype==etORDINAL ){
+- static const char zOrd[] = "thstndrd";
+- int x = (int)(longvalue % 10);
+- if( x>=4 || (longvalue/10)%10==1 ){
+- x = 0;
+- }
+- *(--bufpt) = zOrd[x*2+1];
+- *(--bufpt) = zOrd[x*2];
+- }
+- {
+- register const char *cset; /* Use registers for speed */
+- register int base;
+- cset = &aDigits[infop->charset];
+- base = infop->base;
+- do{ /* Convert to ascii */
+- *(--bufpt) = cset[longvalue%base];
+- longvalue = longvalue/base;
+- }while( longvalue>0 );
+- }
+- length = (int)(&zOut[nOut-1]-bufpt);
+- for(idx=precision-length; idx>0; idx--){
+- *(--bufpt) = '0'; /* Zero pad */
+- }
+- if( prefix ) *(--bufpt) = prefix; /* Add sign */
+- if( flag_alternateform && infop->prefix ){ /* Add "0" or "0x" */
+- const char *pre;
+- char x;
+- pre = &aPrefix[infop->prefix];
+- for(; (x=(*pre))!=0; pre++) *(--bufpt) = x;
+- }
+- length = (int)(&zOut[nOut-1]-bufpt);
+- break;
+- case etFLOAT:
+- case etEXP:
+- case etGENERIC:
+- realvalue = va_arg(ap,double);
+-#ifdef SQLITE_OMIT_FLOATING_POINT
+- length = 0;
+-#else
+- if( precision<0 ) precision = 6; /* Set default precision */
+- if( realvalue<0.0 ){
+- realvalue = -realvalue;
+- prefix = '-';
+- }else{
+- if( flag_plussign ) prefix = '+';
+- else if( flag_blanksign ) prefix = ' ';
+- else prefix = 0;
+- }
+- if( xtype==etGENERIC && precision>0 ) precision--;
+-#if 0
+- /* Rounding works like BSD when the constant 0.4999 is used. Wierd! */
+- for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1);
+-#else
+- /* It makes more sense to use 0.5 */
+- for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1){}
+-#endif
+- if( xtype==etFLOAT ) realvalue += rounder;
+- /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
+- exp = 0;
+- if( sqlite3IsNaN((double)realvalue) ){
+- bufpt = "NaN";
+- length = 3;
+- break;
+- }
+- if( realvalue>0.0 ){
+- LONGDOUBLE_TYPE scale = 1.0;
+- while( realvalue>=1e100*scale && exp<=350 ){ scale *= 1e100;exp+=100;}
+- while( realvalue>=1e64*scale && exp<=350 ){ scale *= 1e64; exp+=64; }
+- while( realvalue>=1e8*scale && exp<=350 ){ scale *= 1e8; exp+=8; }
+- while( realvalue>=10.0*scale && exp<=350 ){ scale *= 10.0; exp++; }
+- realvalue /= scale;
+- while( realvalue<1e-8 ){ realvalue *= 1e8; exp-=8; }
+- while( realvalue<1.0 ){ realvalue *= 10.0; exp--; }
+- if( exp>350 ){
+- if( prefix=='-' ){
+- bufpt = "-Inf";
+- }else if( prefix=='+' ){
+- bufpt = "+Inf";
+- }else{
+- bufpt = "Inf";
+- }
+- length = sqlite3Strlen30(bufpt);
+- break;
+- }
+- }
+- bufpt = buf;
+- /*
+- ** If the field type is etGENERIC, then convert to either etEXP
+- ** or etFLOAT, as appropriate.
+- */
+- if( xtype!=etFLOAT ){
+- realvalue += rounder;
+- if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; }
+- }
+- if( xtype==etGENERIC ){
+- flag_rtz = !flag_alternateform;
+- if( exp<-4 || exp>precision ){
+- xtype = etEXP;
+- }else{
+- precision = precision - exp;
+- xtype = etFLOAT;
+- }
+- }else{
+- flag_rtz = flag_altform2;
+- }
+- if( xtype==etEXP ){
+- e2 = 0;
+- }else{
+- e2 = exp;
+- }
+- if( e2+precision+width > etBUFSIZE - 15 ){
+- bufpt = zExtra = sqlite3Malloc( e2+precision+width+15 );
+- if( bufpt==0 ){
+- pAccum->mallocFailed = 1;
+- return;
+- }
+- }
+- zOut = bufpt;
+- nsd = 16 + flag_altform2*10;
+- flag_dp = (precision>0 ?1:0) | flag_alternateform | flag_altform2;
+- /* The sign in front of the number */
+- if( prefix ){
+- *(bufpt++) = prefix;
+- }
+- /* Digits prior to the decimal point */
+- if( e2<0 ){
+- *(bufpt++) = '0';
+- }else{
+- for(; e2>=0; e2--){
+- *(bufpt++) = et_getdigit(&realvalue,&nsd);
+- }
+- }
+- /* The decimal point */
+- if( flag_dp ){
+- *(bufpt++) = '.';
+- }
+- /* "0" digits after the decimal point but before the first
+- ** significant digit of the number */
+- for(e2++; e2<0; precision--, e2++){
+- assert( precision>0 );
+- *(bufpt++) = '0';
+- }
+- /* Significant digits after the decimal point */
+- while( (precision--)>0 ){
+- *(bufpt++) = et_getdigit(&realvalue,&nsd);
+- }
+- /* Remove trailing zeros and the "." if no digits follow the "." */
+- if( flag_rtz && flag_dp ){
+- while( bufpt[-1]=='0' ) *(--bufpt) = 0;
+- assert( bufpt>zOut );
+- if( bufpt[-1]=='.' ){
+- if( flag_altform2 ){
+- *(bufpt++) = '0';
+- }else{
+- *(--bufpt) = 0;
+- }
+- }
+- }
+- /* Add the "eNNN" suffix */
+- if( xtype==etEXP ){
+- *(bufpt++) = aDigits[infop->charset];
+- if( exp<0 ){
+- *(bufpt++) = '-'; exp = -exp;
+- }else{
+- *(bufpt++) = '+';
+- }
+- if( exp>=100 ){
+- *(bufpt++) = (char)((exp/100)+'0'); /* 100's digit */
+- exp %= 100;
+- }
+- *(bufpt++) = (char)(exp/10+'0'); /* 10's digit */
+- *(bufpt++) = (char)(exp%10+'0'); /* 1's digit */
+- }
+- *bufpt = 0;
+-
+- /* The converted number is in buf[] and zero terminated. Output it.
+- ** Note that the number is in the usual order, not reversed as with
+- ** integer conversions. */
+- length = (int)(bufpt-zOut);
+- bufpt = zOut;
+-
+- /* Special case: Add leading zeros if the flag_zeropad flag is
+- ** set and we are not left justified */
+- if( flag_zeropad && !flag_leftjustify && length < width){
+- int i;
+- int nPad = width - length;
+- for(i=width; i>=nPad; i--){
+- bufpt[i] = bufpt[i-nPad];
+- }
+- i = prefix!=0;
+- while( nPad-- ) bufpt[i++] = '0';
+- length = width;
+- }
+-#endif /* !defined(SQLITE_OMIT_FLOATING_POINT) */
+- break;
+- case etSIZE:
+- *(va_arg(ap,int*)) = pAccum->nChar;
+- length = width = 0;
+- break;
+- case etPERCENT:
+- buf[0] = '%';
+- bufpt = buf;
+- length = 1;
+- break;
+- case etCHARX:
+- 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;
+- }
+- bufpt = buf;
+- break;
+- case etSTRING:
+- case etDYNSTRING:
+- bufpt = va_arg(ap,char*);
+- if( bufpt==0 ){
+- bufpt = "";
+- }else if( xtype==etDYNSTRING ){
+- zExtra = bufpt;
+- }
+- if( precision>=0 ){
+- for(length=0; length<precision && bufpt[length]; length++){}
+- }else{
+- length = sqlite3Strlen30(bufpt);
+- }
+- break;
+- case etSQLESCAPE:
+- case etSQLESCAPE2:
+- case etSQLESCAPE3: {
+- int i, j, k, n, isnull;
+- int needQuote;
+- char ch;
+- char q = ((xtype==etSQLESCAPE3)?'"':'\''); /* Quote character */
+- char *escarg = va_arg(ap,char*);
+- isnull = escarg==0;
+- if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
+- k = precision;
+- for(i=n=0; k!=0 && (ch=escarg[i])!=0; i++, k--){
+- if( ch==q ) n++;
+- }
+- needQuote = !isnull && xtype==etSQLESCAPE2;
+- n += i + 1 + needQuote*2;
+- if( n>etBUFSIZE ){
+- bufpt = zExtra = sqlite3Malloc( n );
+- if( bufpt==0 ){
+- pAccum->mallocFailed = 1;
+- return;
+- }
+- }else{
+- bufpt = buf;
+- }
+- j = 0;
+- if( needQuote ) bufpt[j++] = q;
+- k = i;
+- for(i=0; i<k; i++){
+- bufpt[j++] = ch = escarg[i];
+- if( ch==q ) bufpt[j++] = ch;
+- }
+- if( needQuote ) bufpt[j++] = q;
+- bufpt[j] = 0;
+- length = j;
+- /* The precision in %q and %Q means how many input characters to
+- ** consume, not the length of the output...
+- ** if( precision>=0 && precision<length ) length = precision; */
+- break;
+- }
+- case etTOKEN: {
+- Token *pToken = va_arg(ap, Token*);
+- if( pToken ){
+- sqlite3StrAccumAppend(pAccum, (const char*)pToken->z, pToken->n);
+- }
+- length = width = 0;
+- break;
+- }
+- case etSRCLIST: {
+- SrcList *pSrc = va_arg(ap, SrcList*);
+- int k = va_arg(ap, int);
+- struct SrcList_item *pItem = &pSrc->a[k];
+- assert( k>=0 && k<pSrc->nSrc );
+- if( pItem->zDatabase ){
+- sqlite3StrAccumAppend(pAccum, pItem->zDatabase, -1);
+- sqlite3StrAccumAppend(pAccum, ".", 1);
+- }
+- sqlite3StrAccumAppend(pAccum, pItem->zName, -1);
+- length = width = 0;
+- break;
+- }
+- default: {
+- assert( xtype==etINVALID );
+- return;
+- }
+- }/* End switch over the format type */
+- /*
+- ** The text of the conversion is pointed to by "bufpt" and is
+- ** "length" characters long. The field width is "width". Do
+- ** the output.
+- */
+- if( !flag_leftjustify ){
+- register int nspace;
+- nspace = width-length;
+- if( nspace>0 ){
+- sqlite3AppendSpace(pAccum, nspace);
+- }
+- }
+- if( length>0 ){
+- sqlite3StrAccumAppend(pAccum, bufpt, length);
+- }
+- if( flag_leftjustify ){
+- register int nspace;
+- nspace = width-length;
+- if( nspace>0 ){
+- sqlite3AppendSpace(pAccum, nspace);
+- }
+- }
+- sqlite3_free(zExtra);
+- }/* End for loop over the format string */
+-} /* End of function */
++ sqlite3_mutex_methods const *pFrom;
++ sqlite3_mutex_methods *pTo = &sqlite3GlobalConfig.mutex;
+
+-/*
+-** Append N bytes of text from z to the StrAccum object.
+-*/
+-SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
+- assert( z!=0 || N==0 );
+- if( p->tooBig | p->mallocFailed ){
+- testcase(p->tooBig);
+- testcase(p->mallocFailed);
+- return;
+- }
+- assert( p->zText!=0 || p->nChar==0 );
+- if( N<0 ){
+- N = sqlite3Strlen30(z);
+- }
+- if( N==0 || NEVER(z==0) ){
+- return;
+- }
+- if( p->nChar+N >= p->nAlloc ){
+- char *zNew;
+- if( !p->useMalloc ){
+- p->tooBig = 1;
+- N = p->nAlloc - p->nChar - 1;
+- if( N<=0 ){
+- return;
+- }
++ if( sqlite3GlobalConfig.bCoreMutex ){
++ pFrom = sqlite3DefaultMutex();
+ }else{
+- char *zOld = (p->zText==p->zBase ? 0 : p->zText);
+- i64 szNew = p->nChar;
+- szNew += N + 1;
+- if( szNew > p->mxAlloc ){
+- sqlite3StrAccumReset(p);
+- p->tooBig = 1;
+- return;
+- }else{
+- p->nAlloc = (int)szNew;
+- }
+- if( p->useMalloc==1 ){
+- zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc);
+- }else{
+- zNew = sqlite3_realloc(zOld, p->nAlloc);
+- }
+- if( zNew ){
+- if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar);
+- p->zText = zNew;
+- }else{
+- p->mallocFailed = 1;
+- sqlite3StrAccumReset(p);
+- return;
+- }
++ pFrom = sqlite3NoopMutex();
+ }
++ memcpy(pTo, pFrom, offsetof(sqlite3_mutex_methods, xMutexAlloc));
++ memcpy(&pTo->xMutexFree, &pFrom->xMutexFree,
++ sizeof(*pTo) - offsetof(sqlite3_mutex_methods, xMutexFree));
++ pTo->xMutexAlloc = pFrom->xMutexAlloc;
+ }
+- assert( p->zText );
+- memcpy(&p->zText[p->nChar], z, N);
+- p->nChar += N;
++ rc = sqlite3GlobalConfig.mutex.xMutexInit();
++
++#ifdef SQLITE_DEBUG
++ GLOBAL(int, mutexIsInit) = 1;
++#endif
++
++ return rc;
+ }
+
+ /*
+-** Finish off a string by making sure it is zero-terminated.
+-** Return a pointer to the resulting string. Return a NULL
+-** pointer if any kind of error was encountered.
++** Shutdown the mutex system. This call frees resources allocated by
++** sqlite3MutexInit().
+ */
+-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->zText ){
+- memcpy(p->zText, p->zBase, p->nChar+1);
+- }else{
+- p->mallocFailed = 1;
+- }
+- }
++SQLITE_PRIVATE int sqlite3MutexEnd(void){
++ int rc = SQLITE_OK;
++ if( sqlite3GlobalConfig.mutex.xMutexEnd ){
++ rc = sqlite3GlobalConfig.mutex.xMutexEnd();
+ }
+- return p->zText;
++
++#ifdef SQLITE_DEBUG
++ GLOBAL(int, mutexIsInit) = 0;
++#endif
++
++ return rc;
+ }
+
+ /*
+-** Reset an StrAccum string. Reclaim all malloced memory.
++** Retrieve a pointer to a static mutex or allocate a new dynamic one.
+ */
+-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);
+- }
+- }
+- p->zText = 0;
++SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int id){
++#ifndef SQLITE_OMIT_AUTOINIT
++ if( sqlite3_initialize() ) return 0;
++#endif
++ return sqlite3GlobalConfig.mutex.xMutexAlloc(id);
+ }
+
+-/*
+-** Initialize a string accumulator
+-*/
+-SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum *p, char *zBase, int n, int mx){
+- p->zText = p->zBase = zBase;
+- p->db = 0;
+- p->nChar = 0;
+- p->nAlloc = n;
+- p->mxAlloc = mx;
+- p->useMalloc = 1;
+- p->tooBig = 0;
+- p->mallocFailed = 0;
++SQLITE_PRIVATE sqlite3_mutex *sqlite3MutexAlloc(int id){
++ if( !sqlite3GlobalConfig.bCoreMutex ){
++ return 0;
++ }
++ assert( GLOBAL(int, mutexIsInit) );
++ return sqlite3GlobalConfig.mutex.xMutexAlloc(id);
+ }
+
+ /*
+-** Print into memory obtained from sqliteMalloc(). Use the internal
+-** %-conversion extensions.
++** Free a dynamic mutex.
+ */
+-SQLITE_PRIVATE char *sqlite3VMPrintf(sqlite3 *db, const char *zFormat, va_list ap){
+- char *z;
+- char zBase[SQLITE_PRINT_BUF_SIZE];
+- StrAccum acc;
+- assert( db!=0 );
+- sqlite3StrAccumInit(&acc, zBase, sizeof(zBase),
+- db->aLimit[SQLITE_LIMIT_LENGTH]);
+- acc.db = db;
+- sqlite3VXPrintf(&acc, 1, zFormat, ap);
+- z = sqlite3StrAccumFinish(&acc);
+- if( acc.mallocFailed ){
+- db->mallocFailed = 1;
++SQLITE_API void sqlite3_mutex_free(sqlite3_mutex *p){
++ if( p ){
++ sqlite3GlobalConfig.mutex.xMutexFree(p);
+ }
+- return z;
+ }
+
+ /*
+-** Print into memory obtained from sqliteMalloc(). Use the internal
+-** %-conversion extensions.
++** Obtain the mutex p. If some other thread already has the mutex, block
++** until it can be obtained.
+ */
+-SQLITE_PRIVATE char *sqlite3MPrintf(sqlite3 *db, const char *zFormat, ...){
+- va_list ap;
+- char *z;
+- va_start(ap, zFormat);
+- z = sqlite3VMPrintf(db, zFormat, ap);
+- va_end(ap);
+- return z;
++SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex *p){
++ if( p ){
++ sqlite3GlobalConfig.mutex.xMutexEnter(p);
++ }
+ }
+
+ /*
+-** Like sqlite3MPrintf(), but call sqlite3DbFree() on zStr after formatting
+-** the string and before returnning. This routine is intended to be used
+-** to modify an existing string. For example:
+-**
+-** x = sqlite3MPrintf(db, x, "prefix %s suffix", x);
+-**
++** 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_PRIVATE char *sqlite3MAppendf(sqlite3 *db, char *zStr, const char *zFormat, ...){
+- va_list ap;
+- char *z;
+- va_start(ap, zFormat);
+- z = sqlite3VMPrintf(db, zFormat, ap);
+- va_end(ap);
+- sqlite3DbFree(db, zStr);
+- return z;
++SQLITE_API int sqlite3_mutex_try(sqlite3_mutex *p){
++ int rc = SQLITE_OK;
++ if( p ){
++ return sqlite3GlobalConfig.mutex.xMutexTry(p);
++ }
++ return rc;
+ }
+
+ /*
+-** Print into memory obtained from sqlite3_malloc(). Omit the internal
+-** %-conversion extensions.
++** The sqlite3_mutex_leave() routine exits a mutex that was previously
++** entered by the same thread. The behavior is undefined if the mutex
++** is not currently entered. If a NULL pointer is passed as an argument
++** this function is a no-op.
+ */
+-SQLITE_API char *sqlite3_vmprintf(const char *zFormat, va_list ap){
+- char *z;
+- char zBase[SQLITE_PRINT_BUF_SIZE];
+- StrAccum acc;
+-#ifndef SQLITE_OMIT_AUTOINIT
+- if( sqlite3_initialize() ) return 0;
+-#endif
+- sqlite3StrAccumInit(&acc, zBase, sizeof(zBase), SQLITE_MAX_LENGTH);
+- acc.useMalloc = 2;
+- sqlite3VXPrintf(&acc, 0, zFormat, ap);
+- z = sqlite3StrAccumFinish(&acc);
+- return z;
++SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex *p){
++ if( p ){
++ sqlite3GlobalConfig.mutex.xMutexLeave(p);
++ }
+ }
+
++#ifndef NDEBUG
+ /*
+-** Print into memory obtained from sqlite3_malloc()(). Omit the internal
+-** %-conversion extensions.
++** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
++** intended for use inside assert() statements.
+ */
+-SQLITE_API char *sqlite3_mprintf(const char *zFormat, ...){
+- va_list ap;
+- char *z;
+-#ifndef SQLITE_OMIT_AUTOINIT
+- if( sqlite3_initialize() ) return 0;
+-#endif
+- va_start(ap, zFormat);
+- z = sqlite3_vmprintf(zFormat, ap);
+- va_end(ap);
+- return z;
++SQLITE_API int sqlite3_mutex_held(sqlite3_mutex *p){
++ return p==0 || sqlite3GlobalConfig.mutex.xMutexHeld(p);
+ }
++SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex *p){
++ return p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld(p);
++}
++#endif
+
++#endif /* !defined(SQLITE_MUTEX_OMIT) */
++
++/************** End of mutex.c ***********************************************/
++/************** Begin file mutex_noop.c **************************************/
+ /*
+-** sqlite3_snprintf() works like snprintf() except that it ignores the
+-** current locale settings. This is important for SQLite because we
+-** are not able to use a "," as the decimal point in place of "." as
+-** specified by some locales.
++** 2008 October 07
+ **
+-** Oops: The first two arguments of sqlite3_snprintf() are backwards
+-** from the snprintf() standard. Unfortunately, it is too late to change
+-** this without breaking compatibility, so we just have to live with the
+-** mistake.
++** The author disclaims copyright to this source code. In place of
++** a legal notice, here is a blessing:
+ **
+-** sqlite3_vsnprintf() is the varargs version.
++** 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 mutexes.
++**
++** This implementation in this file does not provide any mutual
++** exclusion and is thus suitable for use only in applications
++** that use SQLite in a single thread. The routines defined
++** here are place-holders. Applications can substitute working
++** mutex routines at start-time using the
++**
++** sqlite3_config(SQLITE_CONFIG_MUTEX,...)
++**
++** interface.
++**
++** If compiled with SQLITE_DEBUG, then additional logic is inserted
++** that does error checking on mutexes to make sure they are being
++** called correctly.
+ */
+-SQLITE_API char *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;
+- sqlite3VXPrintf(&acc, 0, zFormat, ap);
+- return sqlite3StrAccumFinish(&acc);
+-}
+-SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
+- char *z;
+- va_list ap;
+- va_start(ap,zFormat);
+- z = sqlite3_vsnprintf(n, zBuf, zFormat, ap);
+- va_end(ap);
+- return z;
+-}
+
++#ifndef SQLITE_MUTEX_OMIT
++
++#ifndef SQLITE_DEBUG
+ /*
+-** This is the routine that actually formats the sqlite3_log() message.
+-** We house it in a separate routine from sqlite3_log() to avoid using
+-** stack space on small-stack systems when logging is disabled.
++** Stub routines for all mutex methods.
+ **
+-** sqlite3_log() must render into a static buffer. It cannot dynamically
+-** allocate memory because it might be called while the memory allocator
+-** mutex is held.
++** This routines provide no mutual exclusion or error checking.
+ */
+-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 */
++static int noopMutexInit(void){ return SQLITE_OK; }
++static int noopMutexEnd(void){ return SQLITE_OK; }
++static sqlite3_mutex *noopMutexAlloc(int id){
++ UNUSED_PARAMETER(id);
++ return (sqlite3_mutex*)8;
++}
++static void noopMutexFree(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; }
++static void noopMutexEnter(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; }
++static int noopMutexTry(sqlite3_mutex *p){
++ UNUSED_PARAMETER(p);
++ return SQLITE_OK;
++}
++static void noopMutexLeave(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; }
+
+- sqlite3StrAccumInit(&acc, zMsg, sizeof(zMsg), 0);
+- acc.useMalloc = 0;
+- sqlite3VXPrintf(&acc, 0, zFormat, ap);
+- sqlite3GlobalConfig.xLog(sqlite3GlobalConfig.pLogArg, iErrCode,
+- sqlite3StrAccumFinish(&acc));
++SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3NoopMutex(void){
++ static const sqlite3_mutex_methods sMutex = {
++ noopMutexInit,
++ noopMutexEnd,
++ noopMutexAlloc,
++ noopMutexFree,
++ noopMutexEnter,
++ noopMutexTry,
++ noopMutexLeave,
++
++ 0,
++ 0,
++ };
++
++ return &sMutex;
+ }
++#endif /* !SQLITE_DEBUG */
+
++#ifdef SQLITE_DEBUG
+ /*
+-** Format and write a message to the log if logging is enabled.
++** In this implementation, error checking is provided for testing
++** and debugging purposes. The mutexes still do not provide any
++** mutual exclusion.
+ */
+-SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...){
+- va_list ap; /* Vararg list */
+- if( sqlite3GlobalConfig.xLog ){
+- va_start(ap, zFormat);
+- renderLogMsg(iErrCode, zFormat, ap);
+- va_end(ap);
+- }
+-}
+
+-#if defined(SQLITE_DEBUG)
+ /*
+-** A version of printf() that understands %lld. Used for debugging.
+-** The printf() built into some versions of windows does not understand %lld
+-** and segfaults if you give it a long long int.
++** The mutex object
+ */
+-SQLITE_PRIVATE void sqlite3DebugPrintf(const char *zFormat, ...){
+- va_list ap;
+- StrAccum acc;
+- char zBuf[500];
+- sqlite3StrAccumInit(&acc, zBuf, sizeof(zBuf), 0);
+- acc.useMalloc = 0;
+- va_start(ap,zFormat);
+- sqlite3VXPrintf(&acc, 0, zFormat, ap);
+- va_end(ap);
+- sqlite3StrAccumFinish(&acc);
+- fprintf(stdout,"%s", zBuf);
+- fflush(stdout);
+-}
+-#endif
++typedef struct sqlite3_debug_mutex {
++ int id; /* The mutex type */
++ int cnt; /* Number of entries without a matching leave */
++} sqlite3_debug_mutex;
+
+-#ifndef SQLITE_OMIT_TRACE
+ /*
+-** variable-argument wrapper around sqlite3VXPrintf().
++** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
++** intended for use inside assert() statements.
+ */
+-SQLITE_PRIVATE void sqlite3XPrintf(StrAccum *p, const char *zFormat, ...){
+- va_list ap;
+- va_start(ap,zFormat);
+- sqlite3VXPrintf(p, 1, zFormat, ap);
+- va_end(ap);
++static int debugMutexHeld(sqlite3_mutex *pX){
++ sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
++ return p==0 || p->cnt>0;
++}
++static int debugMutexNotheld(sqlite3_mutex *pX){
++ sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
++ return p==0 || p->cnt==0;
+ }
+-#endif
+
+-/************** End of printf.c **********************************************/
+-/************** Begin file random.c ******************************************/
+ /*
+-** 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 file contains code to implement a pseudo-random number
+-** generator (PRNG) for SQLite.
+-**
+-** Random numbers are used by some of the database backends in order
+-** to generate random integer keys for tables or random filenames.
+-*/
+-
+-
+-/* All threads share a single random number generator.
+-** This structure is the current state of the generator.
++** Initialize and deinitialize the mutex subsystem.
+ */
+-static SQLITE_WSD struct sqlite3PrngType {
+- unsigned char isInit; /* True if initialized */
+- unsigned char i, j; /* State variables */
+- unsigned char s[256]; /* State variables */
+-} sqlite3Prng;
++static int debugMutexInit(void){ return SQLITE_OK; }
++static int debugMutexEnd(void){ return SQLITE_OK; }
+
+ /*
+-** Get a single 8-bit random value from the RC4 PRNG. The Mutex
+-** must be held while executing this routine.
+-**
+-** Why not just use a library random generator like lrand48() for this?
+-** Because the OP_NewRowid opcode in the VDBE depends on having a very
+-** good source of random numbers. The lrand48() library function may
+-** well be good enough. But maybe not. Or maybe lrand48() has some
+-** subtle problems on some systems that could cause problems. It is hard
+-** to know. To minimize the risk of problems due to bad lrand48()
+-** implementations, SQLite uses this random number generator based
+-** on RC4, which we know works very well.
+-**
+-** (Later): Actually, OP_NewRowid does not depend on a good source of
+-** randomness any more. But we will leave this code in all the same.
++** 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.
+ */
+-static u8 randomByte(void){
+- unsigned char t;
+-
+-
+- /* The "wsdPrng" macro will resolve to the pseudo-random number generator
+- ** 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, wsdPrng can refer directly
+- ** to the "sqlite3Prng" state vector declared above.
+- */
+-#ifdef SQLITE_OMIT_WSD
+- struct sqlite3PrngType *p = &GLOBAL(struct sqlite3PrngType, sqlite3Prng);
+-# define wsdPrng p[0]
+-#else
+-# define wsdPrng sqlite3Prng
+-#endif
+-
+-
+- /* Initialize the state of the random number generator once,
+- ** the first time this routine is called. The seed value does
+- ** not need to contain a lot of randomness since we are not
+- ** trying to do secure encryption or anything like that...
+- **
+- ** Nothing in this file or anywhere else in SQLite does any kind of
+- ** encryption. The RC4 algorithm is being used as a PRNG (pseudo-random
+- ** number generator) not as an encryption device.
+- */
+- if( !wsdPrng.isInit ){
+- int i;
+- char k[256];
+- wsdPrng.j = 0;
+- wsdPrng.i = 0;
+- sqlite3OsRandomness(sqlite3_vfs_find(0), 256, k);
+- for(i=0; i<256; i++){
+- wsdPrng.s[i] = (u8)i;
++static sqlite3_mutex *debugMutexAlloc(int id){
++ static sqlite3_debug_mutex aStatic[6];
++ sqlite3_debug_mutex *pNew = 0;
++ switch( id ){
++ case SQLITE_MUTEX_FAST:
++ case SQLITE_MUTEX_RECURSIVE: {
++ pNew = sqlite3Malloc(sizeof(*pNew));
++ if( pNew ){
++ pNew->id = id;
++ pNew->cnt = 0;
++ }
++ break;
+ }
+- for(i=0; i<256; i++){
+- wsdPrng.j += wsdPrng.s[i] + k[i];
+- t = wsdPrng.s[wsdPrng.j];
+- wsdPrng.s[wsdPrng.j] = wsdPrng.s[i];
+- wsdPrng.s[i] = t;
++ default: {
++ assert( id-2 >= 0 );
++ assert( id-2 < (int)(sizeof(aStatic)/sizeof(aStatic[0])) );
++ pNew = &aStatic[id-2];
++ pNew->id = id;
++ break;
+ }
+- wsdPrng.isInit = 1;
+ }
++ return (sqlite3_mutex*)pNew;
++}
+
+- /* Generate and return single random byte
+- */
+- wsdPrng.i++;
+- t = wsdPrng.s[wsdPrng.i];
+- wsdPrng.j += t;
+- wsdPrng.s[wsdPrng.i] = wsdPrng.s[wsdPrng.j];
+- wsdPrng.s[wsdPrng.j] = t;
+- t += wsdPrng.s[wsdPrng.i];
+- return wsdPrng.s[t];
++/*
++** This routine deallocates a previously allocated mutex.
++*/
++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);
+ }
+
+ /*
+-** Return N random bytes.
++** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
++** to enter a mutex. If another thread is already within the mutex,
++** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return
++** 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,
++** 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_API void sqlite3_randomness(int N, void *pBuf){
+- unsigned char *zBuf = pBuf;
+-#if SQLITE_THREADSAFE
+- sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PRNG);
+-#endif
+- sqlite3_mutex_enter(mutex);
+- while( N-- ){
+- *(zBuf++) = randomByte();
+- }
+- sqlite3_mutex_leave(mutex);
++static void debugMutexEnter(sqlite3_mutex *pX){
++ sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
++ assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) );
++ p->cnt++;
++}
++static int debugMutexTry(sqlite3_mutex *pX){
++ sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
++ assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) );
++ p->cnt++;
++ return SQLITE_OK;
+ }
+
+-#ifndef SQLITE_OMIT_BUILTIN_TEST
+ /*
+-** For testing purposes, we sometimes want to preserve the state of
+-** PRNG and restore the PRNG to its saved state at a later time, or
+-** to reset the PRNG to its initial state. These routines accomplish
+-** those tasks.
+-**
+-** The sqlite3_test_control() interface calls these routines to
+-** control the PRNG.
++** The sqlite3_mutex_leave() routine exits a mutex that was
++** previously entered by the same thread. The behavior
++** is undefined if the mutex is not currently entered or
++** is not currently allocated. SQLite will never do either.
+ */
+-static SQLITE_WSD struct sqlite3PrngType sqlite3SavedPrng;
+-SQLITE_PRIVATE void sqlite3PrngSaveState(void){
+- memcpy(
+- &GLOBAL(struct sqlite3PrngType, sqlite3SavedPrng),
+- &GLOBAL(struct sqlite3PrngType, sqlite3Prng),
+- sizeof(sqlite3Prng)
+- );
++static void debugMutexLeave(sqlite3_mutex *pX){
++ sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
++ assert( debugMutexHeld(pX) );
++ p->cnt--;
++ assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) );
+ }
+-SQLITE_PRIVATE void sqlite3PrngRestoreState(void){
+- memcpy(
+- &GLOBAL(struct sqlite3PrngType, sqlite3Prng),
+- &GLOBAL(struct sqlite3PrngType, sqlite3SavedPrng),
+- sizeof(sqlite3Prng)
+- );
++
++SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3NoopMutex(void){
++ static const sqlite3_mutex_methods sMutex = {
++ debugMutexInit,
++ debugMutexEnd,
++ debugMutexAlloc,
++ debugMutexFree,
++ debugMutexEnter,
++ debugMutexTry,
++ debugMutexLeave,
++
++ debugMutexHeld,
++ debugMutexNotheld
++ };
++
++ return &sMutex;
+ }
+-SQLITE_PRIVATE void sqlite3PrngResetState(void){
+- GLOBAL(struct sqlite3PrngType, sqlite3Prng).isInit = 0;
++#endif /* SQLITE_DEBUG */
++
++/*
++** If compiled with SQLITE_MUTEX_NOOP, then the no-op mutex implementation
++** is used regardless of the run-time threadsafety setting.
++*/
++#ifdef SQLITE_MUTEX_NOOP
++SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
++ return sqlite3NoopMutex();
+ }
+-#endif /* SQLITE_OMIT_BUILTIN_TEST */
++#endif /* defined(SQLITE_MUTEX_NOOP) */
++#endif /* !defined(SQLITE_MUTEX_OMIT) */
+
+-/************** End of random.c **********************************************/
+-/************** Begin file utf.c *********************************************/
++/************** End of mutex_noop.c ******************************************/
++/************** Begin file mutex_unix.c **************************************/
+ /*
+-** 2004 April 13
++** 2007 August 28
+ **
+ ** The author disclaims copyright to this source code. In place of
+ ** a legal notice, here is a blessing:
+@@ -20682,2498 +21047,2601 @@
+ ** May you share freely, never taking more than you give.
+ **
+ *************************************************************************
+-** This file contains routines used to translate between UTF-8,
+-** UTF-16, UTF-16BE, and UTF-16LE.
+-**
+-** Notes on UTF-8:
+-**
+-** Byte-0 Byte-1 Byte-2 Byte-3 Value
+-** 0xxxxxxx 00000000 00000000 0xxxxxxx
+-** 110yyyyy 10xxxxxx 00000000 00000yyy yyxxxxxx
+-** 1110zzzz 10yyyyyy 10xxxxxx 00000000 zzzzyyyy yyxxxxxx
+-** 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx 000uuuuu zzzzyyyy yyxxxxxx
+-**
+-**
+-** Notes on UTF-16: (with wwww+1==uuuuu)
+-**
+-** Word-0 Word-1 Value
+-** 110110ww wwzzzzyy 110111yy yyxxxxxx 000uuuuu zzzzyyyy yyxxxxxx
+-** zzzzyyyy yyxxxxxx 00000000 zzzzyyyy yyxxxxxx
+-**
+-**
+-** BOM or Byte Order Mark:
+-** 0xff 0xfe little-endian utf-16 follows
+-** 0xfe 0xff big-endian utf-16 follows
++** This file contains the C functions that implement mutexes for pthreads
++*/
++
++/*
++** The code in this file is only used if we are compiling threadsafe
++** under unix with pthreads.
+ **
++** Note that this implementation requires a version of pthreads that
++** supports recursive mutexes.
+ */
+-/* #include <assert.h> */
++#ifdef SQLITE_MUTEX_PTHREADS
++
++#include <pthread.h>
+
+-#ifndef SQLITE_AMALGAMATION
+ /*
+-** The following constant value is used by the SQLITE_BIGENDIAN and
+-** SQLITE_LITTLEENDIAN macros.
++** The sqlite3_mutex.id, sqlite3_mutex.nRef, and sqlite3_mutex.owner fields
++** are necessary under two condidtions: (1) Debug builds and (2) using
++** home-grown mutexes. Encapsulate these conditions into a single #define.
+ */
+-SQLITE_PRIVATE const int sqlite3one = 1;
+-#endif /* SQLITE_AMALGAMATION */
++#if defined(SQLITE_DEBUG) || defined(SQLITE_HOMEGROWN_RECURSIVE_MUTEX)
++# define SQLITE_MUTEX_NREF 1
++#else
++# define SQLITE_MUTEX_NREF 0
++#endif
+
+ /*
+-** This lookup table is used to help decode the first byte of
+-** a multi-byte UTF8 character.
++** Each recursive mutex is an instance of the following structure.
+ */
+-static const unsigned char sqlite3Utf8Trans1[] = {
+- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+- 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00,
++struct sqlite3_mutex {
++ pthread_mutex_t mutex; /* Mutex controlling the lock */
++#if SQLITE_MUTEX_NREF
++ int id; /* Mutex type */
++ volatile int nRef; /* Number of entrances */
++ volatile pthread_t owner; /* Thread that is within this mutex */
++ int trace; /* True to trace changes */
++#endif
+ };
++#if SQLITE_MUTEX_NREF
++#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, 0, 0, (pthread_t)0, 0 }
++#else
++#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER }
++#endif
+
+-
+-#define WRITE_UTF8(zOut, c) { \
+- if( c<0x00080 ){ \
+- *zOut++ = (u8)(c&0xFF); \
+- } \
+- else if( c<0x00800 ){ \
+- *zOut++ = 0xC0 + (u8)((c>>6)&0x1F); \
+- *zOut++ = 0x80 + (u8)(c & 0x3F); \
+- } \
+- else if( c<0x10000 ){ \
+- *zOut++ = 0xE0 + (u8)((c>>12)&0x0F); \
+- *zOut++ = 0x80 + (u8)((c>>6) & 0x3F); \
+- *zOut++ = 0x80 + (u8)(c & 0x3F); \
+- }else{ \
+- *zOut++ = 0xF0 + (u8)((c>>18) & 0x07); \
+- *zOut++ = 0x80 + (u8)((c>>12) & 0x3F); \
+- *zOut++ = 0x80 + (u8)((c>>6) & 0x3F); \
+- *zOut++ = 0x80 + (u8)(c & 0x3F); \
+- } \
+-}
+-
+-#define WRITE_UTF16LE(zOut, c) { \
+- if( c<=0xFFFF ){ \
+- *zOut++ = (u8)(c&0x00FF); \
+- *zOut++ = (u8)((c>>8)&0x00FF); \
+- }else{ \
+- *zOut++ = (u8)(((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \
+- *zOut++ = (u8)(0x00D8 + (((c-0x10000)>>18)&0x03)); \
+- *zOut++ = (u8)(c&0x00FF); \
+- *zOut++ = (u8)(0x00DC + ((c>>8)&0x03)); \
+- } \
++/*
++** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
++** intended for use only inside assert() statements. On some platforms,
++** there might be race conditions that can cause these routines to
++** deliver incorrect results. In particular, if pthread_equal() is
++** not an atomic operation, then these routines might delivery
++** incorrect results. On most platforms, pthread_equal() is a
++** comparison of two integers and is therefore atomic. But we are
++** told that HPUX is not such a platform. If so, then these routines
++** will not always work correctly on HPUX.
++**
++** On those platforms where pthread_equal() is not atomic, SQLite
++** should be compiled without -DSQLITE_DEBUG and with -DNDEBUG to
++** make sure no assert() statements are evaluated and hence these
++** routines are never called.
++*/
++#if !defined(NDEBUG) || defined(SQLITE_DEBUG)
++static int pthreadMutexHeld(sqlite3_mutex *p){
++ return (p->nRef!=0 && pthread_equal(p->owner, pthread_self()));
+ }
+-
+-#define WRITE_UTF16BE(zOut, c) { \
+- if( c<=0xFFFF ){ \
+- *zOut++ = (u8)((c>>8)&0x00FF); \
+- *zOut++ = (u8)(c&0x00FF); \
+- }else{ \
+- *zOut++ = (u8)(0x00D8 + (((c-0x10000)>>18)&0x03)); \
+- *zOut++ = (u8)(((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \
+- *zOut++ = (u8)(0x00DC + ((c>>8)&0x03)); \
+- *zOut++ = (u8)(c&0x00FF); \
+- } \
++static int pthreadMutexNotheld(sqlite3_mutex *p){
++ return p->nRef==0 || pthread_equal(p->owner, pthread_self())==0;
+ }
++#endif
+
+-#define READ_UTF16LE(zIn, TERM, c){ \
+- c = (*zIn++); \
+- c += ((*zIn++)<<8); \
+- if( c>=0xD800 && c<0xE000 && TERM ){ \
+- int c2 = (*zIn++); \
+- c2 += ((*zIn++)<<8); \
+- c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \
+- } \
+-}
+-
+-#define READ_UTF16BE(zIn, TERM, c){ \
+- c = ((*zIn++)<<8); \
+- c += (*zIn++); \
+- if( c>=0xD800 && c<0xE000 && TERM ){ \
+- int c2 = ((*zIn++)<<8); \
+- c2 += (*zIn++); \
+- c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \
+- } \
+-}
++/*
++** Initialize and deinitialize the mutex subsystem.
++*/
++static int pthreadMutexInit(void){ return SQLITE_OK; }
++static int pthreadMutexEnd(void){ return SQLITE_OK; }
+
+ /*
+-** Translate a single UTF-8 character. Return the unicode value.
+-**
+-** During translation, assume that the byte that zTerm points
+-** is a 0x00.
+-**
+-** Write a pointer to the next unread byte back into *pzNext.
+-**
+-** Notes On Invalid UTF-8:
++** 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:
+ **
+-** * This routine never allows a 7-bit character (0x00 through 0x7f) to
+-** be encoded as a multi-byte character. Any multi-byte character that
+-** attempts to encode a value between 0x00 and 0x7f is rendered as 0xfffd.
++** <ul>
++** <li> SQLITE_MUTEX_FAST
++** <li> SQLITE_MUTEX_RECURSIVE
++** <li> SQLITE_MUTEX_STATIC_MASTER
++** <li> SQLITE_MUTEX_STATIC_MEM
++** <li> SQLITE_MUTEX_STATIC_MEM2
++** <li> SQLITE_MUTEX_STATIC_PRNG
++** <li> SQLITE_MUTEX_STATIC_LRU
++** <li> SQLITE_MUTEX_STATIC_PMEM
++** </ul>
+ **
+-** * This routine never allows a UTF16 surrogate value to be encoded.
+-** If a multi-byte character attempts to encode a value between
+-** 0xd800 and 0xe000 then it is rendered as 0xfffd.
++** The first two constants cause sqlite3_mutex_alloc() to create
++** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
++** 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. But 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.
+ **
+-** * Bytes in the range of 0x80 through 0xbf which occur as the first
+-** byte of a character are interpreted as single-byte characters
+-** and rendered as themselves even though they are technically
+-** invalid characters.
++** The other allowed parameters to sqlite3_mutex_alloc() each return
++** a pointer to a static preexisting mutex. Six 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
++** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or
++** SQLITE_MUTEX_RECURSIVE.
+ **
+-** * This routine accepts an infinite number of different UTF8 encodings
+-** for unicode values 0x80 and greater. It do not change over-length
+-** encodings to 0xfffd as some systems recommend.
++** 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
++** mutex types, the same mutex is returned on every call that has
++** the same type number.
+ */
+-#define READ_UTF8(zIn, zTerm, c) \
+- c = *(zIn++); \
+- if( c>=0xc0 ){ \
+- c = sqlite3Utf8Trans1[c-0xc0]; \
+- while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \
+- c = (c<<6) + (0x3f & *(zIn++)); \
+- } \
+- if( c<0x80 \
+- || (c&0xFFFFF800)==0xD800 \
+- || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \
+- }
+-SQLITE_PRIVATE u32 sqlite3Utf8Read(
+- const unsigned char **pz /* Pointer to string from which to read char */
+-){
+- unsigned int c;
+-
+- /* Same as READ_UTF8() above but without the zTerm parameter.
+- ** For this routine, we assume the UTF8 string is always zero-terminated.
+- */
+- c = *((*pz)++);
+- if( c>=0xc0 ){
+- c = sqlite3Utf8Trans1[c-0xc0];
+- while( (*(*pz) & 0xc0)==0x80 ){
+- c = (c<<6) + (0x3f & *((*pz)++));
++static sqlite3_mutex *pthreadMutexAlloc(int iType){
++ static sqlite3_mutex staticMutexes[] = {
++ SQLITE3_MUTEX_INITIALIZER,
++ SQLITE3_MUTEX_INITIALIZER,
++ SQLITE3_MUTEX_INITIALIZER,
++ SQLITE3_MUTEX_INITIALIZER,
++ SQLITE3_MUTEX_INITIALIZER,
++ SQLITE3_MUTEX_INITIALIZER
++ };
++ sqlite3_mutex *p;
++ switch( iType ){
++ case SQLITE_MUTEX_RECURSIVE: {
++ p = sqlite3MallocZero( sizeof(*p) );
++ if( p ){
++#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
++ /* If recursive mutexes are not available, we will have to
++ ** build our own. See below. */
++ pthread_mutex_init(&p->mutex, 0);
++#else
++ /* Use a recursive mutex if it is available */
++ pthread_mutexattr_t recursiveAttr;
++ pthread_mutexattr_init(&recursiveAttr);
++ pthread_mutexattr_settype(&recursiveAttr, PTHREAD_MUTEX_RECURSIVE);
++ 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;
++#endif
++ break;
+ }
+- if( c<0x80
+- || (c&0xFFFFF800)==0xD800
+- || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; }
+ }
+- return c;
++ return p;
+ }
+
+
+-
+-
+ /*
+-** If the TRANSLATE_TRACE macro is defined, the value of each Mem is
+-** printed on stderr on the way into and out of sqlite3VdbeMemTranslate().
+-*/
+-/* #define TRANSLATE_TRACE 1 */
++** This routine deallocates a previously
++** allocated mutex. SQLite is careful to deallocate every
++** mutex that it allocates.
++*/
++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);
++}
+
+-#ifndef SQLITE_OMIT_UTF16
+ /*
+-** This routine transforms the internal text encoding used by pMem to
+-** desiredEnc. It is an error if the string is already of the desired
+-** encoding, or if *pMem does not contain a string value.
++** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
++** to enter a mutex. If another thread is already within the mutex,
++** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return
++** 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,
++** 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_PRIVATE 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 */
+- unsigned char *zTerm; /* End of input */
+- unsigned char *z; /* Output iterator */
+- unsigned int c;
+-
+- assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
+- assert( pMem->flags&MEM_Str );
+- assert( pMem->enc!=desiredEnc );
+- assert( pMem->enc!=0 );
+- assert( pMem->n>=0 );
+-
+-#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG)
+- {
+- char zBuf[100];
+- sqlite3VdbeMemPrettyPrint(pMem, zBuf);
+- fprintf(stderr, "INPUT: %s\n", zBuf);
+- }
+-#endif
++static void pthreadMutexEnter(sqlite3_mutex *p){
++ assert( p->id==SQLITE_MUTEX_RECURSIVE || pthreadMutexNotheld(p) );
+
+- /* If the translation is between UTF-16 little and big endian, then
+- ** all that is required is to swap the byte order. This case is handled
+- ** differently from the others.
++#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
++ /* If recursive mutexes are not available, then we have to grow
++ ** our own. This implementation assumes that pthread_equal()
++ ** is atomic - that it cannot be deceived into thinking self
++ ** and p->owner are equal if p->owner changes between two values
++ ** that are not equal to self while the comparison is taking place.
++ ** This implementation also assumes a coherent cache - that
++ ** separate processes cannot read different values from the same
++ ** address at the same time. If either of these two conditions
++ ** are not met, then the mutexes will fail and problems will result.
+ */
+- if( pMem->enc!=SQLITE_UTF8 && desiredEnc!=SQLITE_UTF8 ){
+- u8 temp;
+- int rc;
+- rc = sqlite3VdbeMemMakeWriteable(pMem);
+- if( rc!=SQLITE_OK ){
+- assert( rc==SQLITE_NOMEM );
+- return SQLITE_NOMEM;
+- }
+- zIn = (u8*)pMem->z;
+- zTerm = &zIn[pMem->n&~1];
+- while( zIn<zTerm ){
+- temp = *zIn;
+- *zIn = *(zIn+1);
+- zIn++;
+- *zIn++ = temp;
++ {
++ pthread_t self = pthread_self();
++ if( p->nRef>0 && pthread_equal(p->owner, self) ){
++ p->nRef++;
++ }else{
++ pthread_mutex_lock(&p->mutex);
++ assert( p->nRef==0 );
++ p->owner = self;
++ p->nRef = 1;
+ }
+- pMem->enc = desiredEnc;
+- goto translate_out;
+ }
++#else
++ /* Use the built-in recursive mutexes if they are available.
++ */
++ pthread_mutex_lock(&p->mutex);
++#if SQLITE_MUTEX_NREF
++ assert( p->nRef>0 || p->owner==0 );
++ p->owner = pthread_self();
++ p->nRef++;
++#endif
++#endif
+
+- /* Set len to the maximum number of bytes required in the output buffer. */
+- if( desiredEnc==SQLITE_UTF8 ){
+- /* When converting from UTF-16, the maximum growth results from
+- ** translating a 2-byte character to a 4-byte UTF-8 character.
+- ** A single byte is required for the output string
+- ** nul-terminator.
+- */
+- pMem->n &= ~1;
+- len = pMem->n * 2 + 1;
+- }else{
+- /* When converting from UTF-8 to UTF-16 the maximum growth is caused
+- ** when a 1-byte UTF-8 character is translated into a 2-byte UTF-16
+- ** character. Two bytes are required in the output buffer for the
+- ** nul-terminator.
+- */
+- len = pMem->n * 2 + 2;
++#ifdef SQLITE_DEBUG
++ if( p->trace ){
++ printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
+ }
++#endif
++}
++static int pthreadMutexTry(sqlite3_mutex *p){
++ int rc;
++ assert( p->id==SQLITE_MUTEX_RECURSIVE || pthreadMutexNotheld(p) );
+
+- /* Set zIn to point at the start of the input buffer and zTerm to point 1
+- ** byte past the end.
+- **
+- ** Variable zOut is set to point at the output buffer, space obtained
+- ** from sqlite3_malloc().
++#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
++ /* If recursive mutexes are not available, then we have to grow
++ ** our own. This implementation assumes that pthread_equal()
++ ** is atomic - that it cannot be deceived into thinking self
++ ** and p->owner are equal if p->owner changes between two values
++ ** that are not equal to self while the comparison is taking place.
++ ** This implementation also assumes a coherent cache - that
++ ** separate processes cannot read different values from the same
++ ** address at the same time. If either of these two conditions
++ ** are not met, then the mutexes will fail and problems will result.
+ */
+- zIn = (u8*)pMem->z;
+- zTerm = &zIn[pMem->n];
+- zOut = sqlite3DbMallocRaw(pMem->db, len);
+- if( !zOut ){
+- return SQLITE_NOMEM;
+- }
+- z = zOut;
+-
+- if( pMem->enc==SQLITE_UTF8 ){
+- if( desiredEnc==SQLITE_UTF16LE ){
+- /* UTF-8 -> UTF-16 Little-endian */
+- while( zIn<zTerm ){
+- READ_UTF8(zIn, zTerm, c);
+- WRITE_UTF16LE(z, c);
+- }
++ {
++ pthread_t self = pthread_self();
++ if( p->nRef>0 && pthread_equal(p->owner, self) ){
++ p->nRef++;
++ rc = SQLITE_OK;
++ }else if( pthread_mutex_trylock(&p->mutex)==0 ){
++ assert( p->nRef==0 );
++ p->owner = self;
++ p->nRef = 1;
++ rc = SQLITE_OK;
+ }else{
+- assert( desiredEnc==SQLITE_UTF16BE );
+- /* UTF-8 -> UTF-16 Big-endian */
+- while( zIn<zTerm ){
+- READ_UTF8(zIn, zTerm, c);
+- WRITE_UTF16BE(z, c);
+- }
++ rc = SQLITE_BUSY;
+ }
+- pMem->n = (int)(z - zOut);
+- *z++ = 0;
++ }
++#else
++ /* Use the built-in recursive mutexes if they are available.
++ */
++ if( pthread_mutex_trylock(&p->mutex)==0 ){
++#if SQLITE_MUTEX_NREF
++ p->owner = pthread_self();
++ p->nRef++;
++#endif
++ rc = SQLITE_OK;
+ }else{
+- assert( desiredEnc==SQLITE_UTF8 );
+- if( pMem->enc==SQLITE_UTF16LE ){
+- /* UTF-16 Little-endian -> UTF-8 */
+- while( zIn<zTerm ){
+- READ_UTF16LE(zIn, zIn<zTerm, c);
+- WRITE_UTF8(z, c);
+- }
+- }else{
+- /* UTF-16 Big-endian -> UTF-8 */
+- while( zIn<zTerm ){
+- READ_UTF16BE(zIn, zIn<zTerm, c);
+- WRITE_UTF8(z, c);
+- }
+- }
+- pMem->n = (int)(z - zOut);
++ rc = SQLITE_BUSY;
+ }
+- *z = 0;
+- assert( (pMem->n+(desiredEnc==SQLITE_UTF8?1:2))<=len );
+-
+- sqlite3VdbeMemRelease(pMem);
+- pMem->flags &= ~(MEM_Static|MEM_Dyn|MEM_Ephem);
+- pMem->enc = desiredEnc;
+- pMem->flags |= (MEM_Term|MEM_Dyn);
+- pMem->z = (char*)zOut;
+- pMem->zMalloc = pMem->z;
++#endif
+
+-translate_out:
+-#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG)
+- {
+- char zBuf[100];
+- sqlite3VdbeMemPrettyPrint(pMem, zBuf);
+- fprintf(stderr, "OUTPUT: %s\n", zBuf);
++#ifdef SQLITE_DEBUG
++ if( rc==SQLITE_OK && p->trace ){
++ printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
+ }
+ #endif
+- return SQLITE_OK;
++ return rc;
+ }
+
+ /*
+-** This routine checks for a byte-order mark at the beginning of the
+-** UTF-16 string stored in *pMem. If one is present, it is removed and
+-** the encoding of the Mem adjusted. This routine does not do any
+-** byte-swapping, it just sets Mem.enc appropriately.
+-**
+-** The allocation (static, dynamic etc.) and encoding of the Mem may be
+-** changed by this function.
++** The sqlite3_mutex_leave() routine exits a mutex that was
++** previously entered by the same thread. The behavior
++** is undefined if the mutex is not currently entered or
++** is not currently allocated. SQLite will never do either.
+ */
+-SQLITE_PRIVATE int sqlite3VdbeMemHandleBom(Mem *pMem){
+- int rc = SQLITE_OK;
+- u8 bom = 0;
++static void pthreadMutexLeave(sqlite3_mutex *p){
++ assert( pthreadMutexHeld(p) );
++#if SQLITE_MUTEX_NREF
++ p->nRef--;
++ if( p->nRef==0 ) p->owner = 0;
++#endif
++ assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
+
+- assert( pMem->n>=0 );
+- if( pMem->n>1 ){
+- u8 b1 = *(u8 *)pMem->z;
+- u8 b2 = *(((u8 *)pMem->z) + 1);
+- if( b1==0xFE && b2==0xFF ){
+- bom = SQLITE_UTF16BE;
+- }
+- if( b1==0xFF && b2==0xFE ){
+- bom = SQLITE_UTF16LE;
+- }
++#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
++ if( p->nRef==0 ){
++ pthread_mutex_unlock(&p->mutex);
+ }
+-
+- if( bom ){
+- rc = sqlite3VdbeMemMakeWriteable(pMem);
+- if( rc==SQLITE_OK ){
+- pMem->n -= 2;
+- memmove(pMem->z, &pMem->z[2], pMem->n);
+- pMem->z[pMem->n] = '\0';
+- pMem->z[pMem->n+1] = '\0';
+- pMem->flags |= MEM_Term;
+- pMem->enc = bom;
+- }
++#else
++ pthread_mutex_unlock(&p->mutex);
++#endif
++
++#ifdef SQLITE_DEBUG
++ if( p->trace ){
++ printf("leave mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
+ }
+- return rc;
++#endif
+ }
+-#endif /* SQLITE_OMIT_UTF16 */
+
+-/*
+-** pZ is a UTF-8 encoded unicode string. If nByte is less than zero,
+-** return the number of unicode characters in pZ up to (but not including)
+-** the first 0x00 byte. If nByte is not less than zero, return the
+-** number of unicode characters in the first nByte of pZ (or up to
+-** the first 0x00, whichever comes first).
+-*/
+-SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *zIn, int nByte){
+- int r = 0;
+- const u8 *z = (const u8*)zIn;
+- const u8 *zTerm;
+- if( nByte>=0 ){
+- zTerm = &z[nByte];
+- }else{
+- zTerm = (const u8*)(-1);
+- }
+- assert( z<=zTerm );
+- while( *z!=0 && z<zTerm ){
+- SQLITE_SKIP_UTF8(z);
+- r++;
+- }
+- return r;
++SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
++ static const sqlite3_mutex_methods sMutex = {
++ pthreadMutexInit,
++ pthreadMutexEnd,
++ pthreadMutexAlloc,
++ pthreadMutexFree,
++ pthreadMutexEnter,
++ pthreadMutexTry,
++ pthreadMutexLeave,
++#ifdef SQLITE_DEBUG
++ pthreadMutexHeld,
++ pthreadMutexNotheld
++#else
++ 0,
++ 0
++#endif
++ };
++
++ return &sMutex;
+ }
+
+-/* This test function is not currently used by the automated test-suite.
+-** Hence it is only available in debug builds.
+-*/
+-#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
++#endif /* SQLITE_MUTEX_PTHREADS */
++
++/************** End of mutex_unix.c ******************************************/
++/************** Begin file mutex_w32.c ***************************************/
+ /*
+-** Translate UTF-8 to UTF-8.
++** 2007 August 14
+ **
+-** This has the effect of making sure that the string is well-formed
+-** UTF-8. Miscoded characters are removed.
++** The author disclaims copyright to this source code. In place of
++** a legal notice, here is a blessing:
+ **
+-** The translation is done in-place and aborted if the output
+-** overruns the input.
++** 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 mutexes for win32
+ */
+-SQLITE_PRIVATE int sqlite3Utf8To8(unsigned char *zIn){
+- unsigned char *zOut = zIn;
+- unsigned char *zStart = zIn;
+- u32 c;
+-
+- while( zIn[0] && zOut<=zIn ){
+- c = sqlite3Utf8Read((const u8**)&zIn);
+- if( c!=0xfffd ){
+- WRITE_UTF8(zOut, c);
+- }
+- }
+- *zOut = 0;
+- return (int)(zOut - zStart);
+-}
+-#endif
+
+-#ifndef SQLITE_OMIT_UTF16
+ /*
+-** Convert a UTF-16 string in the native encoding into a UTF-8 string.
+-** Memory to hold the UTF-8 string is obtained from sqlite3_malloc and must
+-** be freed by the calling function.
++** The code in this file is only used if we are compiling multithreaded
++** on a win32 system.
++*/
++#ifdef SQLITE_MUTEX_W32
++
++/*
++** Each recursive mutex is an instance of the following structure.
++*/
++struct sqlite3_mutex {
++ CRITICAL_SECTION mutex; /* Mutex controlling the lock */
++ int id; /* Mutex type */
++#ifdef SQLITE_DEBUG
++ volatile int nRef; /* Number of enterances */
++ volatile DWORD owner; /* Thread holding this mutex */
++ int trace; /* True to trace changes */
++#endif
++};
++#define SQLITE_W32_MUTEX_INITIALIZER { 0 }
++#ifdef SQLITE_DEBUG
++#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0, 0L, (DWORD)0, 0 }
++#else
++#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0 }
++#endif
++
++/*
++** Return true (non-zero) if we are running under WinNT, Win2K, WinXP,
++** or WinCE. Return false (zero) for Win95, Win98, or WinME.
+ **
+-** NULL is returned if there is an allocation error.
++** 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 win 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.
++**
++** mutexIsNT() is only used for the TryEnterCriticalSection() API call,
++** which is only available if your application was compiled with
++** _WIN32_WINNT defined to a value >= 0x0400. Currently, the only
++** call to TryEnterCriticalSection() is #ifdef'ed out, so #ifdef
++** this out as well.
+ */
+-SQLITE_PRIVATE char *sqlite3Utf16to8(sqlite3 *db, const void *z, int nByte, u8 enc){
+- Mem m;
+- memset(&m, 0, sizeof(m));
+- m.db = db;
+- sqlite3VdbeMemSetStr(&m, z, nByte, enc, SQLITE_STATIC);
+- sqlite3VdbeChangeEncoding(&m, SQLITE_UTF8);
+- if( db->mallocFailed ){
+- sqlite3VdbeMemRelease(&m);
+- m.z = 0;
++#if 0
++#if SQLITE_OS_WINCE || SQLITE_OS_WINRT
++# define mutexIsNT() (1)
++#else
++ static int mutexIsNT(void){
++ static int osType = 0;
++ if( osType==0 ){
++ OSVERSIONINFO sInfo;
++ sInfo.dwOSVersionInfoSize = sizeof(sInfo);
++ GetVersionEx(&sInfo);
++ osType = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1;
++ }
++ return osType==2;
+ }
+- assert( (m.flags & MEM_Term)!=0 || db->mallocFailed );
+- assert( (m.flags & MEM_Str)!=0 || db->mallocFailed );
+- assert( (m.flags & MEM_Dyn)!=0 || db->mallocFailed );
+- assert( m.z || db->mallocFailed );
+- return m.z;
+-}
++#endif /* SQLITE_OS_WINCE */
++#endif
+
++#ifdef SQLITE_DEBUG
+ /*
+-** Convert a UTF-8 string to the UTF-16 encoding specified by parameter
+-** enc. A pointer to the new string is returned, and the value of *pnOut
+-** is set to the length of the returned string in bytes. The call should
+-** arrange to call sqlite3DbFree() on the returned pointer when it is
+-** no longer required.
+-**
+-** If a malloc failure occurs, NULL is returned and the db.mallocFailed
+-** flag set.
++** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
++** intended for use only inside assert() statements.
+ */
+-#ifdef SQLITE_ENABLE_STAT3
+-SQLITE_PRIVATE char *sqlite3Utf8to16(sqlite3 *db, u8 enc, char *z, int n, int *pnOut){
+- Mem m;
+- memset(&m, 0, sizeof(m));
+- m.db = db;
+- sqlite3VdbeMemSetStr(&m, z, n, SQLITE_UTF8, SQLITE_STATIC);
+- if( sqlite3VdbeMemTranslate(&m, enc) ){
+- assert( db->mallocFailed );
+- return 0;
+- }
+- assert( m.z==m.zMalloc );
+- *pnOut = m.n;
+- return m.z;
++static int winMutexHeld(sqlite3_mutex *p){
++ return p->nRef!=0 && p->owner==GetCurrentThreadId();
++}
++static int winMutexNotheld2(sqlite3_mutex *p, DWORD tid){
++ return p->nRef==0 || p->owner!=tid;
++}
++static int winMutexNotheld(sqlite3_mutex *p){
++ DWORD tid = GetCurrentThreadId();
++ return winMutexNotheld2(p, tid);
+ }
+ #endif
+
++
+ /*
+-** zIn is a UTF-16 encoded unicode string at least nChar characters long.
+-** Return the number of bytes in the first nChar unicode characters
+-** in pZ. nChar must be non-negative.
++** Initialize and deinitialize the mutex subsystem.
+ */
+-SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *zIn, int nChar){
+- int c;
+- unsigned char const *z = zIn;
+- int n = 0;
+-
+- if( SQLITE_UTF16NATIVE==SQLITE_UTF16BE ){
+- while( n<nChar ){
+- READ_UTF16BE(z, 1, c);
+- n++;
++static sqlite3_mutex winMutex_staticMutexes[6] = {
++ SQLITE3_MUTEX_INITIALIZER,
++ SQLITE3_MUTEX_INITIALIZER,
++ SQLITE3_MUTEX_INITIALIZER,
++ SQLITE3_MUTEX_INITIALIZER,
++ SQLITE3_MUTEX_INITIALIZER,
++ SQLITE3_MUTEX_INITIALIZER
++};
++static int winMutex_isInit = 0;
++/* As winMutexInit() and winMutexEnd() are called as part
++** of the sqlite3_initialize and sqlite3_shutdown()
++** processing, the "interlocked" magic is probably not
++** strictly necessary.
++*/
++static long winMutex_lock = 0;
++
++SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds); /* os_win.c */
++
++static int winMutexInit(void){
++ /* The first to increment to 1 does actual initialization */
++ if( InterlockedCompareExchange(&winMutex_lock, 1, 0)==0 ){
++ int i;
++ for(i=0; i<ArraySize(winMutex_staticMutexes); i++){
++#if SQLITE_OS_WINRT
++ InitializeCriticalSectionEx(&winMutex_staticMutexes[i].mutex, 0, 0);
++#else
++ InitializeCriticalSection(&winMutex_staticMutexes[i].mutex);
++#endif
+ }
++ winMutex_isInit = 1;
+ }else{
+- while( n<nChar ){
+- READ_UTF16LE(z, 1, c);
+- n++;
++ /* Someone else is in the process of initing the static mutexes */
++ while( !winMutex_isInit ){
++ sqlite3_win32_sleep(1);
+ }
+ }
+- return (int)(z-(unsigned char const *)zIn);
++ return SQLITE_OK;
+ }
+
+-#if defined(SQLITE_TEST)
+-/*
+-** This routine is called from the TCL test function "translate_selftest".
+-** It checks that the primitives for serializing and deserializing
+-** characters in each encoding are inverses of each other.
+-*/
+-SQLITE_PRIVATE void sqlite3UtfSelfTest(void){
+- unsigned int i, t;
+- unsigned char zBuf[20];
+- unsigned char *z;
+- int n;
+- unsigned int c;
+-
+- for(i=0; i<0x00110000; i++){
+- z = zBuf;
+- WRITE_UTF8(z, i);
+- n = (int)(z-zBuf);
+- assert( n>0 && n<=4 );
+- z[0] = 0;
+- z = zBuf;
+- c = sqlite3Utf8Read((const u8**)&z);
+- t = i;
+- if( i>=0xD800 && i<=0xDFFF ) t = 0xFFFD;
+- if( (i&0xFFFFFFFE)==0xFFFE ) t = 0xFFFD;
+- assert( c==t );
+- assert( (z-zBuf)==n );
+- }
+- for(i=0; i<0x00110000; i++){
+- if( i>=0xD800 && i<0xE000 ) continue;
+- z = zBuf;
+- WRITE_UTF16LE(z, i);
+- n = (int)(z-zBuf);
+- assert( n>0 && n<=4 );
+- z[0] = 0;
+- z = zBuf;
+- READ_UTF16LE(z, 1, c);
+- assert( c==i );
+- assert( (z-zBuf)==n );
+- }
+- for(i=0; i<0x00110000; i++){
+- if( i>=0xD800 && i<0xE000 ) continue;
+- z = zBuf;
+- WRITE_UTF16BE(z, i);
+- n = (int)(z-zBuf);
+- assert( n>0 && n<=4 );
+- z[0] = 0;
+- z = zBuf;
+- READ_UTF16BE(z, 1, c);
+- assert( c==i );
+- assert( (z-zBuf)==n );
++static int winMutexEnd(void){
++ /* The first to decrement to 0 does actual shutdown
++ ** (which should be the last to shutdown.) */
++ if( InterlockedCompareExchange(&winMutex_lock, 0, 1)==1 ){
++ if( winMutex_isInit==1 ){
++ int i;
++ for(i=0; i<ArraySize(winMutex_staticMutexes); i++){
++ DeleteCriticalSection(&winMutex_staticMutexes[i].mutex);
++ }
++ winMutex_isInit = 0;
++ }
+ }
++ return SQLITE_OK;
+ }
+-#endif /* SQLITE_TEST */
+-#endif /* SQLITE_OMIT_UTF16 */
+
+-/************** End of utf.c *************************************************/
+-/************** Begin file util.c ********************************************/
+ /*
+-** 2001 September 15
+-**
+-** The author disclaims copyright to this source code. In place of
+-** a legal notice, here is a blessing:
++** 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:
+ **
+-** 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.
++** <ul>
++** <li> SQLITE_MUTEX_FAST
++** <li> SQLITE_MUTEX_RECURSIVE
++** <li> SQLITE_MUTEX_STATIC_MASTER
++** <li> SQLITE_MUTEX_STATIC_MEM
++** <li> SQLITE_MUTEX_STATIC_MEM2
++** <li> SQLITE_MUTEX_STATIC_PRNG
++** <li> SQLITE_MUTEX_STATIC_LRU
++** <li> SQLITE_MUTEX_STATIC_PMEM
++** </ul>
+ **
+-*************************************************************************
+-** Utility functions used throughout sqlite.
++** The first two constants cause sqlite3_mutex_alloc() to create
++** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
++** 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. But 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.
+ **
+-** This file contains functions for allocating memory, comparing
+-** strings, and stuff like that.
++** The other allowed parameters to sqlite3_mutex_alloc() each return
++** a pointer to a static preexisting mutex. Six 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
++** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or
++** SQLITE_MUTEX_RECURSIVE.
+ **
++** 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
++** mutex types, the same mutex is returned on every call that has
++** the same type number.
+ */
+-/* #include <stdarg.h> */
+-#ifdef SQLITE_HAVE_ISNAN
+-# include <math.h>
++static sqlite3_mutex *winMutexAlloc(int iType){
++ sqlite3_mutex *p;
++
++ switch( iType ){
++ case SQLITE_MUTEX_FAST:
++ case SQLITE_MUTEX_RECURSIVE: {
++ p = sqlite3MallocZero( sizeof(*p) );
++ if( p ){
++#ifdef SQLITE_DEBUG
++ p->id = iType;
++#endif
++#if SQLITE_OS_WINRT
++ InitializeCriticalSectionEx(&p->mutex, 0, 0);
++#else
++ InitializeCriticalSection(&p->mutex);
++#endif
++ }
++ break;
++ }
++ default: {
++ assert( winMutex_isInit==1 );
++ assert( iType-2 >= 0 );
++ assert( iType-2 < ArraySize(winMutex_staticMutexes) );
++ p = &winMutex_staticMutexes[iType-2];
++#ifdef SQLITE_DEBUG
++ p->id = iType;
+ #endif
++ break;
++ }
++ }
++ return p;
++}
++
+
+ /*
+-** Routine needed to support the testcase() macro.
++** This routine deallocates a previously
++** allocated mutex. SQLite is careful to deallocate every
++** mutex that it allocates.
+ */
+-#ifdef SQLITE_COVERAGE_TEST
+-SQLITE_PRIVATE void sqlite3Coverage(int x){
+- static unsigned dummy = 0;
+- dummy += (unsigned)x;
++static void winMutexFree(sqlite3_mutex *p){
++ assert( p );
++ assert( p->nRef==0 && p->owner==0 );
++ assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
++ DeleteCriticalSection(&p->mutex);
++ sqlite3_free(p);
+ }
+-#endif
+
+-#ifndef SQLITE_OMIT_FLOATING_POINT
+ /*
+-** Return true if the floating point value is Not a Number (NaN).
+-**
+-** Use the math library isnan() function if compiled with SQLITE_HAVE_ISNAN.
+-** Otherwise, we have our own implementation that works on most systems.
++** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
++** to enter a mutex. If another thread is already within the mutex,
++** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return
++** 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,
++** 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_PRIVATE int sqlite3IsNaN(double x){
+- int rc; /* The value return */
+-#if !defined(SQLITE_HAVE_ISNAN)
++static void winMutexEnter(sqlite3_mutex *p){
++#ifdef SQLITE_DEBUG
++ DWORD tid = GetCurrentThreadId();
++ assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) );
++#endif
++ EnterCriticalSection(&p->mutex);
++#ifdef SQLITE_DEBUG
++ assert( p->nRef>0 || p->owner==0 );
++ p->owner = tid;
++ p->nRef++;
++ if( p->trace ){
++ printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
++ }
++#endif
++}
++static int winMutexTry(sqlite3_mutex *p){
++#ifndef NDEBUG
++ DWORD tid = GetCurrentThreadId();
++#endif
++ int rc = SQLITE_BUSY;
++ assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) );
+ /*
+- ** Systems that support the isnan() library function should probably
+- ** make use of it by compiling with -DSQLITE_HAVE_ISNAN. But we have
+- ** found that many systems do not have a working isnan() function so
+- ** this implementation is provided as an alternative.
+- **
+- ** This NaN test sometimes fails if compiled on GCC with -ffast-math.
+- ** On the other hand, the use of -ffast-math comes with the following
+- ** warning:
+- **
+- ** This option [-ffast-math] should never be turned on by any
+- ** -O option since it can result in incorrect output for programs
+- ** which depend on an exact implementation of IEEE or ISO
+- ** rules/specifications for math functions.
+- **
+- ** Under MSVC, this NaN test may fail if compiled with a floating-
+- ** point precision mode other than /fp:precise. From the MSDN
+- ** documentation:
++ ** The sqlite3_mutex_try() routine is very rarely used, and when it
++ ** is used it is merely an optimization. So it is OK for it to always
++ ** fail.
+ **
+- ** The compiler [with /fp:precise] will properly handle comparisons
+- ** involving NaN. For example, x != x evaluates to true if x is NaN
+- ** ...
++ ** The TryEnterCriticalSection() interface is only available on WinNT.
++ ** And some windows compilers complain if you try to use it without
++ ** first doing some #defines that prevent SQLite from building on Win98.
++ ** For that reason, we will omit this optimization for now. See
++ ** ticket #2685.
+ */
+-#ifdef __FAST_MATH__
+-# error SQLite will not work correctly with the -ffast-math option of GCC.
++#if 0
++ if( mutexIsNT() && TryEnterCriticalSection(&p->mutex) ){
++ p->owner = tid;
++ p->nRef++;
++ rc = SQLITE_OK;
++ }
++#else
++ UNUSED_PARAMETER(p);
++#endif
++#ifdef SQLITE_DEBUG
++ if( rc==SQLITE_OK && p->trace ){
++ printf("try mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
++ }
+ #endif
+- volatile double y = x;
+- volatile double z = y;
+- rc = (y!=z);
+-#else /* if defined(SQLITE_HAVE_ISNAN) */
+- rc = isnan(x);
+-#endif /* SQLITE_HAVE_ISNAN */
+- testcase( rc );
+ return rc;
+ }
+-#endif /* SQLITE_OMIT_FLOATING_POINT */
+
+ /*
+-** Compute a string length that is limited to what can be stored in
+-** lower 30 bits of a 32-bit signed integer.
+-**
+-** The value returned will never be negative. Nor will it ever be greater
+-** than the actual length of the string. For very long strings (greater
+-** than 1GiB) the value returned might be less than the true string length.
++** The sqlite3_mutex_leave() routine exits a mutex that was
++** previously entered by the same thread. The behavior
++** is undefined if the mutex is not currently entered or
++** is not currently allocated. SQLite will never do either.
+ */
+-SQLITE_PRIVATE int sqlite3Strlen30(const char *z){
+- const char *z2 = z;
+- if( z==0 ) return 0;
+- while( *z2 ){ z2++; }
+- return 0x3fffffff & (int)(z2 - z);
++static void winMutexLeave(sqlite3_mutex *p){
++#ifndef NDEBUG
++ DWORD tid = GetCurrentThreadId();
++ assert( p->nRef>0 );
++ assert( p->owner==tid );
++ p->nRef--;
++ if( p->nRef==0 ) p->owner = 0;
++ assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
++#endif
++ LeaveCriticalSection(&p->mutex);
++#ifdef SQLITE_DEBUG
++ if( p->trace ){
++ printf("leave mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
++ }
++#endif
++}
++
++SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
++ static const sqlite3_mutex_methods sMutex = {
++ winMutexInit,
++ winMutexEnd,
++ winMutexAlloc,
++ winMutexFree,
++ winMutexEnter,
++ winMutexTry,
++ winMutexLeave,
++#ifdef SQLITE_DEBUG
++ winMutexHeld,
++ winMutexNotheld
++#else
++ 0,
++ 0
++#endif
++ };
++
++ return &sMutex;
+ }
++#endif /* SQLITE_MUTEX_W32 */
+
++/************** End of mutex_w32.c *******************************************/
++/************** Begin file malloc.c ******************************************/
+ /*
+-** Set the most recent error code and error string for the sqlite
+-** handle "db". The error code is set to "err_code".
++** 2001 September 15
+ **
+-** If it is not NULL, string zFormat specifies the format of the
+-** error string in the style of the printf functions: The following
+-** format characters are allowed:
++** The author disclaims copyright to this source code. In place of
++** a legal notice, here is a blessing:
+ **
+-** %s Insert a string
+-** %z A string that should be freed after use
+-** %d Insert an integer
+-** %T Insert a token
+-** %S Insert the first element of a SrcList
++** 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.
+ **
+-** zFormat and any string tokens that follow it are assumed to be
+-** encoded in UTF-8.
++*************************************************************************
+ **
+-** To clear the most recent error for sqlite handle "db", sqlite3Error
+-** should be called with err_code set to SQLITE_OK and zFormat set
+-** to NULL.
++** Memory allocation functions used throughout sqlite.
+ */
+-SQLITE_PRIVATE void sqlite3Error(sqlite3 *db, int err_code, const char *zFormat, ...){
+- if( db && (db->pErr || (db->pErr = sqlite3ValueNew(db))!=0) ){
+- db->errCode = err_code;
+- if( zFormat ){
+- 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{
+- sqlite3ValueSetStr(db->pErr, 0, 0, SQLITE_UTF8, SQLITE_STATIC);
+- }
+- }
+-}
++/* #include <stdarg.h> */
+
+ /*
+-** Add an error message to pParse->zErrMsg and increment pParse->nErr.
+-** The following formatting characters are allowed:
+-**
+-** %s Insert a string
+-** %z A string that should be freed after use
+-** %d Insert an integer
+-** %T Insert a token
+-** %S Insert the first element of a SrcList
+-**
+-** This function should be used to report any error that occurs whilst
+-** 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.).
++** Attempt to release up to n bytes of non-essential memory currently
++** held by SQLite. An example of non-essential memory is memory used to
++** cache database pages that are not currently in use.
+ */
+-SQLITE_PRIVATE void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
+- char *zMsg;
+- va_list ap;
+- sqlite3 *db = pParse->db;
+- va_start(ap, zFormat);
+- zMsg = sqlite3VMPrintf(db, zFormat, ap);
+- va_end(ap);
+- if( db->suppressErr ){
+- sqlite3DbFree(db, zMsg);
+- }else{
+- pParse->nErr++;
+- sqlite3DbFree(db, pParse->zErrMsg);
+- pParse->zErrMsg = zMsg;
+- pParse->rc = SQLITE_ERROR;
+- }
++SQLITE_API int sqlite3_release_memory(int n){
++#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
++ return sqlite3PcacheReleaseMemory(n);
++#else
++ /* IMPLEMENTATION-OF: R-34391-24921 The sqlite3_release_memory() routine
++ ** is a no-op returning zero if SQLite is not compiled with
++ ** SQLITE_ENABLE_MEMORY_MANAGEMENT. */
++ UNUSED_PARAMETER(n);
++ return 0;
++#endif
+ }
+
+ /*
+-** Convert an SQL-style quoted string into a normal string by removing
+-** the quote characters. The conversion is done in-place. If the
+-** input does not begin with a quote character, then this routine
+-** is a no-op.
+-**
+-** The input string must be zero-terminated. A new zero-terminator
+-** is added to the dequoted string.
+-**
+-** The return value is -1 if no dequoting occurs or the length of the
+-** dequoted string, exclusive of the zero terminator, if dequoting does
+-** occur.
+-**
+-** 2002-Feb-14: This routine is extended to remove MS-Access style
+-** brackets from around identifers. For example: "[a-b-c]" becomes
+-** "a-b-c".
++** An instance of the following object records the location of
++** each unused scratch buffer.
+ */
+-SQLITE_PRIVATE int sqlite3Dequote(char *z){
+- char quote;
+- int i, j;
+- if( z==0 ) return -1;
+- quote = z[0];
+- switch( quote ){
+- case '\'': break;
+- case '"': break;
+- case '`': break; /* For MySQL compatibility */
+- case '[': quote = ']'; break; /* For MS SqlServer compatibility */
+- default: return -1;
+- }
+- for(i=1, j=0; ALWAYS(z[i]); i++){
+- if( z[i]==quote ){
+- if( z[i+1]==quote ){
+- z[j++] = quote;
+- i++;
+- }else{
+- break;
+- }
+- }else{
+- z[j++] = z[i];
+- }
+- }
+- z[j] = 0;
+- return j;
+-}
++typedef struct ScratchFreeslot {
++ struct ScratchFreeslot *pNext; /* Next unused scratch buffer */
++} ScratchFreeslot;
+
+-/* Convenient short-hand */
+-#define UpperToLower sqlite3UpperToLower
++/*
++** State information local to the memory allocation subsystem.
++*/
++static SQLITE_WSD struct Mem0Global {
++ sqlite3_mutex *mutex; /* Mutex to serialize access */
++
++ /*
++ ** The alarm callback and its arguments. The mem0.mutex lock will
++ ** be held while the callback is running. Recursive calls into
++ ** the memory subsystem are allowed, but no new callbacks will be
++ ** issued.
++ */
++ sqlite3_int64 alarmThreshold;
++ void (*alarmCallback)(void*, sqlite3_int64,int);
++ void *alarmArg;
++
++ /*
++ ** Pointers to the end of sqlite3GlobalConfig.pScratch memory
++ ** (so that a range test can be used to determine if an allocation
++ ** being freed came from pScratch) and a pointer to the list of
++ ** unused scratch allocations.
++ */
++ void *pScratchEnd;
++ ScratchFreeslot *pScratchFree;
++ u32 nScratchFree;
++
++ /*
++ ** True if heap is nearly "full" where "full" is defined by the
++ ** sqlite3_soft_heap_limit() setting.
++ */
++ int nearlyFull;
++} mem0 = { 0, 0, 0, 0, 0, 0, 0, 0 };
++
++#define mem0 GLOBAL(struct Mem0Global, mem0)
+
+ /*
+-** Some systems have stricmp(). Others have strcasecmp(). Because
+-** there is no consistency, we will define our own.
+-**
+-** IMPLEMENTATION-OF: R-30243-02494 The sqlite3_stricmp() and
+-** sqlite3_strnicmp() APIs allow applications and extensions to compare
+-** the contents of two buffers containing UTF-8 strings in a
+-** case-independent fashion, using the same definition of "case
+-** independence" that SQLite uses internally when comparing identifiers.
++** This routine runs when the memory allocator sees that the
++** total memory allocation is about to exceed the soft heap
++** limit.
+ */
+-SQLITE_API int sqlite3_stricmp(const char *zLeft, const char *zRight){
+- register unsigned char *a, *b;
+- 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){
+- register unsigned char *a, *b;
+- a = (unsigned char *)zLeft;
+- b = (unsigned char *)zRight;
+- while( N-- > 0 && *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }
+- return N<0 ? 0 : UpperToLower[*a] - UpperToLower[*b];
++static void softHeapLimitEnforcer(
++ void *NotUsed,
++ sqlite3_int64 NotUsed2,
++ int allocSize
++){
++ UNUSED_PARAMETER2(NotUsed, NotUsed2);
++ sqlite3_release_memory(allocSize);
+ }
+
+ /*
+-** The string z[] is an text representation of a real number.
+-** Convert this string to a double and write it into *pResult.
+-**
+-** The string z[] is length bytes in length (bytes, not characters) and
+-** uses the encoding enc. The string is not necessarily zero-terminated.
+-**
+-** Return TRUE if the result is a valid real number (or integer) and FALSE
+-** if the string is empty or contains extraneous text. Valid numbers
+-** are in one of these formats:
+-**
+-** [+-]digits[E[+-]digits]
+-** [+-]digits.[digits][E[+-]digits]
+-** [+-].digits[E[+-]digits]
+-**
+-** Leading and trailing whitespace is ignored for the purpose of determining
+-** validity.
+-**
+-** If some prefix of the input string is a valid number, this routine
+-** returns FALSE but it still converts the prefix and writes the result
+-** into *pResult.
++** Change the alarm callback
+ */
+-SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){
+-#ifndef SQLITE_OMIT_FLOATING_POINT
+- int incr;
+- const char *zEnd = z + length;
+- /* sign * significand * (10 ^ (esign * exponent)) */
+- int sign = 1; /* sign of significand */
+- i64 s = 0; /* significand */
+- int d = 0; /* adjust exponent for shifting decimal point */
+- int esign = 1; /* sign of exponent */
+- int e = 0; /* exponent */
+- int eValid = 1; /* True exponent is either not used or is well-formed */
+- double result;
+- int nDigits = 0;
+- int nonNum = 0;
++static int sqlite3MemoryAlarm(
++ void(*xCallback)(void *pArg, sqlite3_int64 used,int N),
++ void *pArg,
++ sqlite3_int64 iThreshold
++){
++ int nUsed;
++ sqlite3_mutex_enter(mem0.mutex);
++ mem0.alarmCallback = xCallback;
++ mem0.alarmArg = pArg;
++ mem0.alarmThreshold = iThreshold;
++ nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
++ mem0.nearlyFull = (iThreshold>0 && iThreshold<=nUsed);
++ sqlite3_mutex_leave(mem0.mutex);
++ return SQLITE_OK;
++}
+
+- assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
+- *pResult = 0.0; /* Default return value, in case of an error */
++#ifndef SQLITE_OMIT_DEPRECATED
++/*
++** Deprecated external interface. Internal/core SQLite code
++** should call sqlite3MemoryAlarm.
++*/
++SQLITE_API int sqlite3_memory_alarm(
++ void(*xCallback)(void *pArg, sqlite3_int64 used,int N),
++ void *pArg,
++ sqlite3_int64 iThreshold
++){
++ return sqlite3MemoryAlarm(xCallback, pArg, iThreshold);
++}
++#endif
+
+- if( enc==SQLITE_UTF8 ){
+- incr = 1;
++/*
++** 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){
++ sqlite3_int64 priorLimit;
++ sqlite3_int64 excess;
++#ifndef SQLITE_OMIT_AUTOINIT
++ int rc = sqlite3_initialize();
++ if( rc ) return -1;
++#endif
++ sqlite3_mutex_enter(mem0.mutex);
++ priorLimit = mem0.alarmThreshold;
++ sqlite3_mutex_leave(mem0.mutex);
++ if( n<0 ) return priorLimit;
++ if( n>0 ){
++ sqlite3MemoryAlarm(softHeapLimitEnforcer, 0, n);
+ }else{
+- int i;
+- incr = 2;
+- assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
+- for(i=3-enc; i<length && z[i]==0; i+=2){}
+- nonNum = i<length;
+- zEnd = z+i+enc-3;
+- z += (enc&1);
+- }
+-
+- /* skip leading spaces */
+- while( z<zEnd && sqlite3Isspace(*z) ) z+=incr;
+- if( z>=zEnd ) return 0;
+-
+- /* get sign of significand */
+- if( *z=='-' ){
+- sign = -1;
+- z+=incr;
+- }else if( *z=='+' ){
+- z+=incr;
++ sqlite3MemoryAlarm(0, 0, 0);
+ }
++ excess = sqlite3_memory_used() - n;
++ if( excess>0 ) sqlite3_release_memory((int)(excess & 0x7fffffff));
++ return priorLimit;
++}
++SQLITE_API void sqlite3_soft_heap_limit(int n){
++ if( n<0 ) n = 0;
++ sqlite3_soft_heap_limit64(n);
++}
+
+- /* skip leading zeroes */
+- while( z<zEnd && z[0]=='0' ) z+=incr, nDigits++;
+-
+- /* copy max significant digits to significand */
+- while( z<zEnd && sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){
+- s = s*10 + (*z - '0');
+- z+=incr, nDigits++;
++/*
++** Initialize the memory allocation subsystem.
++*/
++SQLITE_PRIVATE int sqlite3MallocInit(void){
++ if( sqlite3GlobalConfig.m.xMalloc==0 ){
++ sqlite3MemSetDefault();
+ }
+-
+- /* skip non-significant significand digits
+- ** (increase exponent by d to shift decimal left) */
+- while( z<zEnd && sqlite3Isdigit(*z) ) z+=incr, nDigits++, d++;
+- if( z>=zEnd ) goto do_atof_calc;
+-
+- /* if decimal point is present */
+- if( *z=='.' ){
+- z+=incr;
+- /* copy digits from after decimal to significand
+- ** (decrease exponent by d to shift decimal right) */
+- while( z<zEnd && sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){
+- s = s*10 + (*z - '0');
+- z+=incr, nDigits++, d--;
+- }
+- /* skip non-significant digits */
+- while( z<zEnd && sqlite3Isdigit(*z) ) z+=incr, nDigits++;
++ memset(&mem0, 0, sizeof(mem0));
++ if( sqlite3GlobalConfig.bCoreMutex ){
++ mem0.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
+ }
+- if( z>=zEnd ) goto do_atof_calc;
+-
+- /* if exponent is present */
+- if( *z=='e' || *z=='E' ){
+- z+=incr;
+- eValid = 0;
+- if( z>=zEnd ) goto do_atof_calc;
+- /* get sign of exponent */
+- if( *z=='-' ){
+- esign = -1;
+- z+=incr;
+- }else if( *z=='+' ){
+- z+=incr;
+- }
+- /* copy digits to exponent */
+- while( z<zEnd && sqlite3Isdigit(*z) ){
+- e = e<10000 ? (e*10 + (*z - '0')) : 10000;
+- z+=incr;
+- eValid = 1;
++ if( sqlite3GlobalConfig.pScratch && sqlite3GlobalConfig.szScratch>=100
++ && sqlite3GlobalConfig.nScratch>0 ){
++ int i, n, sz;
++ ScratchFreeslot *pSlot;
++ sz = ROUNDDOWN8(sqlite3GlobalConfig.szScratch);
++ sqlite3GlobalConfig.szScratch = sz;
++ pSlot = (ScratchFreeslot*)sqlite3GlobalConfig.pScratch;
++ n = sqlite3GlobalConfig.nScratch;
++ mem0.pScratchFree = pSlot;
++ mem0.nScratchFree = n;
++ for(i=0; i<n-1; i++){
++ pSlot->pNext = (ScratchFreeslot*)(sz+(char*)pSlot);
++ pSlot = pSlot->pNext;
+ }
++ pSlot->pNext = 0;
++ mem0.pScratchEnd = (void*)&pSlot[1];
++ }else{
++ mem0.pScratchEnd = 0;
++ sqlite3GlobalConfig.pScratch = 0;
++ sqlite3GlobalConfig.szScratch = 0;
++ sqlite3GlobalConfig.nScratch = 0;
+ }
+-
+- /* skip trailing spaces */
+- if( nDigits && eValid ){
+- while( z<zEnd && sqlite3Isspace(*z) ) z+=incr;
+- }
+-
+-do_atof_calc:
+- /* adjust exponent by d, and update sign */
+- e = (e*esign) + d;
+- if( e<0 ) {
+- esign = -1;
+- e *= -1;
+- } else {
+- esign = 1;
++ if( sqlite3GlobalConfig.pPage==0 || sqlite3GlobalConfig.szPage<512
++ || sqlite3GlobalConfig.nPage<1 ){
++ sqlite3GlobalConfig.pPage = 0;
++ sqlite3GlobalConfig.szPage = 0;
++ sqlite3GlobalConfig.nPage = 0;
+ }
++ return sqlite3GlobalConfig.m.xInit(sqlite3GlobalConfig.m.pAppData);
++}
+
+- /* if 0 significand */
+- if( !s ) {
+- /* In the IEEE 754 standard, zero is signed.
+- ** Add the sign if we've seen at least one digit */
+- result = (sign<0 && nDigits) ? -(double)0 : (double)0;
+- } else {
+- /* attempt to reduce exponent */
+- if( esign>0 ){
+- while( s<(LARGEST_INT64/10) && e>0 ) e--,s*=10;
+- }else{
+- while( !(s%10) && e>0 ) e--,s/=10;
+- }
+-
+- /* adjust the sign of significand */
+- s = sign<0 ? -s : s;
++/*
++** Return true if the heap is currently under memory pressure - in other
++** words if the amount of heap used is close to the limit set by
++** sqlite3_soft_heap_limit().
++*/
++SQLITE_PRIVATE int sqlite3HeapNearlyFull(void){
++ return mem0.nearlyFull;
++}
+
+- /* if exponent, scale significand as appropriate
+- ** and store in result. */
+- if( e ){
+- LONGDOUBLE_TYPE scale = 1.0;
+- /* attempt to handle extremely small/large numbers better */
+- if( e>307 && e<342 ){
+- while( e%308 ) { scale *= 1.0e+1; e -= 1; }
+- if( esign<0 ){
+- result = s / scale;
+- result /= 1.0e+308;
+- }else{
+- result = s * scale;
+- result *= 1.0e+308;
+- }
+- }else if( e>=342 ){
+- if( esign<0 ){
+- result = 0.0*s;
+- }else{
+- result = 1e308*1e308*s; /* Infinity */
+- }
+- }else{
+- /* 1.0e+22 is the largest power of 10 than can be
+- ** represented exactly. */
+- while( e%22 ) { scale *= 1.0e+1; e -= 1; }
+- while( e>0 ) { scale *= 1.0e+22; e -= 22; }
+- if( esign<0 ){
+- result = s / scale;
+- }else{
+- result = s * scale;
+- }
+- }
+- } else {
+- result = (double)s;
+- }
++/*
++** Deinitialize the memory allocation subsystem.
++*/
++SQLITE_PRIVATE void sqlite3MallocEnd(void){
++ if( sqlite3GlobalConfig.m.xShutdown ){
++ sqlite3GlobalConfig.m.xShutdown(sqlite3GlobalConfig.m.pAppData);
+ }
++ memset(&mem0, 0, sizeof(mem0));
++}
+
+- /* store the result */
+- *pResult = result;
+-
+- /* return true if number and no extra non-whitespace chracters after */
+- return z>=zEnd && nDigits>0 && eValid && nonNum==0;
+-#else
+- return !sqlite3Atoi64(z, pResult, length, enc);
+-#endif /* SQLITE_OMIT_FLOATING_POINT */
++/*
++** Return the amount of memory currently checked out.
++*/
++SQLITE_API sqlite3_int64 sqlite3_memory_used(void){
++ int n, mx;
++ sqlite3_int64 res;
++ sqlite3_status(SQLITE_STATUS_MEMORY_USED, &n, &mx, 0);
++ res = (sqlite3_int64)n; /* Work around bug in Borland C. Ticket #3216 */
++ return res;
+ }
+
+ /*
+-** Compare the 19-character string zNum against the text representation
+-** value 2^63: 9223372036854775808. Return negative, zero, or positive
+-** if zNum is less than, equal to, or greater than the string.
+-** Note that zNum must contain exactly 19 characters.
+-**
+-** Unlike memcmp() this routine is guaranteed to return the difference
+-** in the values of the last digit if the only difference is in the
+-** last digit. So, for example,
+-**
+-** compare2pow63("9223372036854775800", 1)
+-**
+-** will return -8.
++** Return the maximum amount of memory that has ever been
++** checked out since either the beginning of this process
++** or since the most recent reset.
+ */
+-static int compare2pow63(const char *zNum, int incr){
+- int c = 0;
+- int i;
+- /* 012345678901234567 */
+- const char *pow63 = "922337203685477580";
+- for(i=0; c==0 && i<18; i++){
+- c = (zNum[i*incr]-pow63[i])*10;
+- }
+- if( c==0 ){
+- c = zNum[18*incr] - '8';
+- testcase( c==(-1) );
+- testcase( c==0 );
+- testcase( c==(+1) );
+- }
+- return c;
++SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag){
++ int n, mx;
++ sqlite3_int64 res;
++ sqlite3_status(SQLITE_STATUS_MEMORY_USED, &n, &mx, resetFlag);
++ res = (sqlite3_int64)mx; /* Work around bug in Borland C. Ticket #3216 */
++ return res;
+ }
+
++/*
++** Trigger the alarm
++*/
++static void sqlite3MallocAlarm(int nByte){
++ void (*xCallback)(void*,sqlite3_int64,int);
++ sqlite3_int64 nowUsed;
++ void *pArg;
++ if( mem0.alarmCallback==0 ) return;
++ xCallback = mem0.alarmCallback;
++ nowUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
++ pArg = mem0.alarmArg;
++ mem0.alarmCallback = 0;
++ sqlite3_mutex_leave(mem0.mutex);
++ xCallback(pArg, nowUsed, nByte);
++ sqlite3_mutex_enter(mem0.mutex);
++ mem0.alarmCallback = xCallback;
++ mem0.alarmArg = pArg;
++}
+
+ /*
+-** Convert zNum to a 64-bit signed integer.
+-**
+-** If the zNum value is representable as a 64-bit twos-complement
+-** integer, then write that value into *pNum and return 0.
+-**
+-** If zNum is exactly 9223372036854665808, return 2. This special
+-** case is broken out because while 9223372036854665808 cannot be a
+-** signed 64-bit integer, its negative -9223372036854665808 can be.
+-**
+-** If zNum is too big for a 64-bit integer and is not
+-** 9223372036854665808 or if zNum contains any non-numeric text,
+-** then return 1.
+-**
+-** length is the number of bytes in the string (bytes, not characters).
+-** The string is not necessarily zero-terminated. The encoding is
+-** given by enc.
++** Do a memory allocation with statistics and alarms. Assume the
++** lock is already held.
+ */
+-SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
+- int incr;
+- u64 u = 0;
+- int neg = 0; /* assume positive */
+- int i;
+- int c = 0;
+- int nonNum = 0;
+- const char *zStart;
+- const char *zEnd = zNum + length;
+- assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
+- if( enc==SQLITE_UTF8 ){
+- incr = 1;
+- }else{
+- incr = 2;
+- assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
+- for(i=3-enc; i<length && zNum[i]==0; i+=2){}
+- nonNum = i<length;
+- zEnd = zNum+i+enc-3;
+- zNum += (enc&1);
+- }
+- while( zNum<zEnd && sqlite3Isspace(*zNum) ) zNum+=incr;
+- if( zNum<zEnd ){
+- if( *zNum=='-' ){
+- neg = 1;
+- zNum+=incr;
+- }else if( *zNum=='+' ){
+- zNum+=incr;
++static int mallocWithAlarm(int n, void **pp){
++ int nFull;
++ void *p;
++ assert( sqlite3_mutex_held(mem0.mutex) );
++ nFull = sqlite3GlobalConfig.m.xRoundup(n);
++ sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, n);
++ if( mem0.alarmCallback!=0 ){
++ int nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
++ if( nUsed >= mem0.alarmThreshold - nFull ){
++ mem0.nearlyFull = 1;
++ sqlite3MallocAlarm(nFull);
++ }else{
++ mem0.nearlyFull = 0;
+ }
+ }
+- zStart = zNum;
+- while( zNum<zEnd && zNum[0]=='0' ){ zNum+=incr; } /* Skip leading zeros. */
+- for(i=0; &zNum[i]<zEnd && (c=zNum[i])>='0' && c<='9'; i+=incr){
+- u = u*10 + c - '0';
++ p = sqlite3GlobalConfig.m.xMalloc(nFull);
++#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
++ if( p==0 && mem0.alarmCallback ){
++ sqlite3MallocAlarm(nFull);
++ p = sqlite3GlobalConfig.m.xMalloc(nFull);
+ }
+- if( u>LARGEST_INT64 ){
+- *pNum = SMALLEST_INT64;
+- }else if( neg ){
+- *pNum = -(i64)u;
+- }else{
+- *pNum = (i64)u;
++#endif
++ if( p ){
++ nFull = sqlite3MallocSize(p);
++ sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nFull);
++ sqlite3StatusAdd(SQLITE_STATUS_MALLOC_COUNT, 1);
+ }
+- testcase( i==18 );
+- testcase( i==19 );
+- testcase( i==20 );
+- if( (c!=0 && &zNum[i]<zEnd) || (i==0 && zStart==zNum) || i>19*incr || nonNum ){
+- /* zNum is empty or contains non-numeric text or is longer
+- ** than 19 digits (thus guaranteeing that it is too large) */
+- return 1;
+- }else if( i<19*incr ){
+- /* Less than 19 digits, so we know that it fits in 64 bits */
+- assert( u<=LARGEST_INT64 );
+- return 0;
++ *pp = p;
++ return nFull;
++}
++
++/*
++** 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){
++ void *p;
++ if( n<=0 /* IMP: R-65312-04917 */
++ || 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
++ ** 255 bytes of overhead. SQLite itself will never use anything near
++ ** this amount. The only way to reach the limit is with sqlite3_malloc() */
++ p = 0;
++ }else if( sqlite3GlobalConfig.bMemstat ){
++ sqlite3_mutex_enter(mem0.mutex);
++ mallocWithAlarm(n, &p);
++ sqlite3_mutex_leave(mem0.mutex);
+ }else{
+- /* zNum is a 19-digit numbers. Compare it against 9223372036854775808. */
+- c = compare2pow63(zNum, incr);
+- if( c<0 ){
+- /* zNum is less than 9223372036854775808 so it fits */
+- assert( u<=LARGEST_INT64 );
+- return 0;
+- }else if( c>0 ){
+- /* zNum is greater than 9223372036854775808 so it overflows */
+- return 1;
+- }else{
+- /* zNum is exactly 9223372036854775808. Fits if negative. The
+- ** special case 2 overflow if positive */
+- assert( u-1==LARGEST_INT64 );
+- assert( (*pNum)==SMALLEST_INT64 );
+- return neg ? 0 : 2;
+- }
++ p = sqlite3GlobalConfig.m.xMalloc(n);
+ }
++ assert( EIGHT_BYTE_ALIGNMENT(p) ); /* IMP: R-04675-44850 */
++ return p;
+ }
+
+ /*
+-** If zNum represents an integer that will fit in 32-bits, then set
+-** *pValue to that integer and return true. Otherwise return false.
+-**
+-** Any non-numeric characters that following zNum are ignored.
+-** This is different from sqlite3Atoi64() which requires the
+-** input number to be zero-terminated.
++** This version of the memory allocation is for use by the application.
++** First make sure the memory subsystem is initialized, then do the
++** allocation.
+ */
+-SQLITE_PRIVATE int sqlite3GetInt32(const char *zNum, int *pValue){
+- sqlite_int64 v = 0;
+- int i, c;
+- int neg = 0;
+- if( zNum[0]=='-' ){
+- neg = 1;
+- zNum++;
+- }else if( zNum[0]=='+' ){
+- zNum++;
+- }
+- while( zNum[0]=='0' ) zNum++;
+- for(i=0; i<11 && (c = zNum[i] - '0')>=0 && c<=9; i++){
+- v = v*10 + c;
+- }
++SQLITE_API void *sqlite3_malloc(int n){
++#ifndef SQLITE_OMIT_AUTOINIT
++ if( sqlite3_initialize() ) return 0;
++#endif
++ return sqlite3Malloc(n);
++}
+
+- /* The longest decimal representation of a 32 bit integer is 10 digits:
+- **
+- ** 1234567890
+- ** 2^31 -> 2147483648
+- */
+- testcase( i==10 );
+- if( i>10 ){
+- return 0;
+- }
+- testcase( v-neg==2147483647 );
+- if( v-neg>2147483647 ){
+- return 0;
++/*
++** Each thread may only have a single outstanding allocation from
++** xScratchMalloc(). We verify this constraint in the single-threaded
++** case by setting scratchAllocOut to 1 when an allocation
++** is outstanding clearing it when the allocation is freed.
++*/
++#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
++static int scratchAllocOut = 0;
++#endif
++
++
++/*
++** Allocate memory that is to be used and released right away.
++** This routine is similar to alloca() in that it is not intended
++** for situations where the memory might be held long-term. This
++** routine is intended to get memory to old large transient data
++** structures that would not normally fit on the stack of an
++** embedded processor.
++*/
++SQLITE_PRIVATE void *sqlite3ScratchMalloc(int n){
++ void *p;
++ assert( n>0 );
++
++ sqlite3_mutex_enter(mem0.mutex);
++ 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);
++ 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 = sqlite3GlobalConfig.m.xMalloc(n);
++ }
++ sqlite3MemdebugSetType(p, MEMTYPE_SCRATCH);
+ }
+- if( neg ){
+- v = -v;
++ assert( sqlite3_mutex_notheld(mem0.mutex) );
++
++
++#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 );
++ if( p ) scratchAllocOut++;
++#endif
++
++ return p;
++}
++SQLITE_PRIVATE void sqlite3ScratchFree(void *p){
++ if( p ){
++
++#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
++ /* Verify that no more than two scratch allocation per thread
++ ** is 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 && scratchAllocOut<=2 );
++ scratchAllocOut--;
++#endif
++
++ if( p>=sqlite3GlobalConfig.pScratch && p<mem0.pScratchEnd ){
++ /* Release memory from the SQLITE_CONFIG_SCRATCH allocation */
++ ScratchFreeslot *pSlot;
++ pSlot = (ScratchFreeslot*)p;
++ sqlite3_mutex_enter(mem0.mutex);
++ pSlot->pNext = mem0.pScratchFree;
++ mem0.pScratchFree = pSlot;
++ mem0.nScratchFree++;
++ assert( mem0.nScratchFree <= (u32)sqlite3GlobalConfig.nScratch );
++ sqlite3StatusAdd(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) );
++ 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);
++ sqlite3GlobalConfig.m.xFree(p);
++ sqlite3_mutex_leave(mem0.mutex);
++ }else{
++ sqlite3GlobalConfig.m.xFree(p);
++ }
++ }
+ }
+- *pValue = (int)v;
+- return 1;
+ }
+
+ /*
+-** Return a 32-bit integer value extracted from a string. If the
+-** string is not an integer, just return 0.
++** TRUE if p is a lookaside memory allocation from db
+ */
+-SQLITE_PRIVATE int sqlite3Atoi(const char *z){
+- int x = 0;
+- if( z ) sqlite3GetInt32(z, &x);
+- return x;
++#ifndef SQLITE_OMIT_LOOKASIDE
++static int isLookaside(sqlite3 *db, void *p){
++ return p && p>=db->lookaside.pStart && p<db->lookaside.pEnd;
+ }
++#else
++#define isLookaside(A,B) 0
++#endif
+
+ /*
+-** The variable-length integer encoding is as follows:
+-**
+-** KEY:
+-** A = 0xxxxxxx 7 bits of data and one flag bit
+-** B = 1xxxxxxx 7 bits of data and one flag bit
+-** C = xxxxxxxx 8 bits of data
+-**
+-** 7 bits - A
+-** 14 bits - BA
+-** 21 bits - BBA
+-** 28 bits - BBBA
+-** 35 bits - BBBBA
+-** 42 bits - BBBBBA
+-** 49 bits - BBBBBBA
+-** 56 bits - BBBBBBBA
+-** 64 bits - BBBBBBBBC
++** Return the size of a memory allocation previously obtained from
++** sqlite3Malloc() or sqlite3_malloc().
+ */
++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 || sqlite3_mutex_held(db->mutex) );
++ if( db && isLookaside(db, p) ){
++ return db->lookaside.sz;
++ }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);
++ }
++}
+
+ /*
+-** Write a 64-bit variable-length integer to memory starting at p[0].
+-** The length of data write will be between 1 and 9 bytes. The number
+-** of bytes written is returned.
+-**
+-** A variable-length integer consists of the lower 7 bits of each byte
+-** for all bytes that have the 8th bit set and one byte with the 8th
+-** bit clear. Except, if we get to the 9th byte, it stores the full
+-** 8 bits and is the last byte.
++** Free memory previously obtained from sqlite3Malloc().
+ */
+-SQLITE_PRIVATE int sqlite3PutVarint(unsigned char *p, u64 v){
+- int i, j, n;
+- u8 buf[10];
+- if( v & (((u64)0xff000000)<<32) ){
+- p[8] = (u8)v;
+- v >>= 8;
+- for(i=7; i>=0; i--){
+- p[i] = (u8)((v & 0x7f) | 0x80);
+- v >>= 7;
+- }
+- return 9;
+- }
+- n = 0;
+- do{
+- buf[n++] = (u8)((v & 0x7f) | 0x80);
+- v >>= 7;
+- }while( v!=0 );
+- buf[0] &= 0x7f;
+- assert( n<=9 );
+- for(i=0, j=n-1; j>=0; j--, i++){
+- p[i] = buf[j];
++SQLITE_API void sqlite3_free(void *p){
++ if( p==0 ) return; /* IMP: R-49053-54554 */
++ assert( sqlite3MemdebugNoType(p, MEMTYPE_DB) );
++ assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
++ if( sqlite3GlobalConfig.bMemstat ){
++ sqlite3_mutex_enter(mem0.mutex);
++ sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, -sqlite3MallocSize(p));
++ sqlite3StatusAdd(SQLITE_STATUS_MALLOC_COUNT, -1);
++ sqlite3GlobalConfig.m.xFree(p);
++ sqlite3_mutex_leave(mem0.mutex);
++ }else{
++ sqlite3GlobalConfig.m.xFree(p);
+ }
+- 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.
++** Free memory that might be associated with a particular database
++** connection.
+ */
+-SQLITE_PRIVATE int sqlite3PutVarint32(unsigned char *p, u32 v){
+-#ifndef putVarint32
+- if( (v & ~0x7f)==0 ){
+- p[0] = v;
+- return 1;
+- }
++SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){
++ assert( db==0 || sqlite3_mutex_held(db->mutex) );
++ if( db ){
++ if( db->pnBytesFreed ){
++ *db->pnBytesFreed += sqlite3DbMallocSize(db, p);
++ return;
++ }
++ if( isLookaside(db, p) ){
++ LookasideSlot *pBuf = (LookasideSlot*)p;
++#if SQLITE_DEBUG
++ /* Trash all content in the buffer being freed */
++ memset(p, 0xaa, db->lookaside.sz);
+ #endif
+- if( (v & ~0x3fff)==0 ){
+- p[0] = (u8)((v>>7) | 0x80);
+- p[1] = (u8)(v & 0x7f);
+- return 2;
++ pBuf->pNext = db->lookaside.pFree;
++ db->lookaside.pFree = pBuf;
++ db->lookaside.nOut--;
++ return;
++ }
+ }
+- return sqlite3PutVarint(p, v);
++ assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) );
++ assert( sqlite3MemdebugHasType(p, MEMTYPE_LOOKASIDE|MEMTYPE_HEAP) );
++ assert( db!=0 || sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) );
++ sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
++ sqlite3_free(p);
+ }
+
+ /*
+-** Bitmasks used by sqlite3GetVarint(). These precomputed constants
+-** are defined here rather than simply putting the constant expressions
+-** inline in order to work around bugs in the RVT compiler.
+-**
+-** SLOT_2_0 A mask for (0x7f<<14) | 0x7f
+-**
+-** SLOT_4_2_0 A mask for (0x7f<<28) | SLOT_2_0
++** Change the size of an existing memory allocation
+ */
+-#define SLOT_2_0 0x001fc07f
+-#define SLOT_4_2_0 0xf01fc07f
+-
++SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, int nBytes){
++ int nOld, nNew, nDiff;
++ void *pNew;
++ if( pOld==0 ){
++ return sqlite3Malloc(nBytes); /* IMP: R-28354-25769 */
++ }
++ if( nBytes<=0 ){
++ sqlite3_free(pOld); /* IMP: R-31593-10574 */
++ return 0;
++ }
++ if( nBytes>=0x7fffff00 ){
++ /* The 0x7ffff00 limit term is explained in comments on sqlite3Malloc() */
++ return 0;
++ }
++ nOld = sqlite3MallocSize(pOld);
++ /* 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);
++ if( nOld==nNew ){
++ pNew = pOld;
++ }else if( sqlite3GlobalConfig.bMemstat ){
++ sqlite3_mutex_enter(mem0.mutex);
++ sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, 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);
++ pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
++ }
++ if( pNew ){
++ nNew = sqlite3MallocSize(pNew);
++ sqlite3StatusAdd(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 */
++ return pNew;
++}
+
+ /*
+-** Read a 64-bit variable-length integer from memory starting at p[0].
+-** Return the number of bytes read. The value is stored in *v.
++** The public interface to sqlite3Realloc. Make sure that the memory
++** subsystem is initialized prior to invoking sqliteRealloc.
+ */
+-SQLITE_PRIVATE u8 sqlite3GetVarint(const unsigned char *p, u64 *v){
+- u32 a,b,s;
++SQLITE_API void *sqlite3_realloc(void *pOld, int n){
++#ifndef SQLITE_OMIT_AUTOINIT
++ if( sqlite3_initialize() ) return 0;
++#endif
++ return sqlite3Realloc(pOld, n);
++}
+
+- a = *p;
+- /* a: p0 (unmasked) */
+- if (!(a&0x80))
+- {
+- *v = a;
+- return 1;
+- }
+
+- p++;
+- b = *p;
+- /* b: p1 (unmasked) */
+- if (!(b&0x80))
+- {
+- a &= 0x7f;
+- a = a<<7;
+- a |= b;
+- *v = a;
+- return 2;
++/*
++** Allocate and zero memory.
++*/
++SQLITE_PRIVATE void *sqlite3MallocZero(int n){
++ void *p = sqlite3Malloc(n);
++ if( p ){
++ memset(p, 0, n);
+ }
++ return p;
++}
+
+- /* Verify that constants are precomputed correctly */
+- assert( SLOT_2_0 == ((0x7f<<14) | (0x7f)) );
+- assert( SLOT_4_2_0 == ((0xfU<<28) | (0x7f<<14) | (0x7f)) );
+-
+- p++;
+- a = a<<14;
+- a |= *p;
+- /* a: p0<<14 | p2 (unmasked) */
+- if (!(a&0x80))
+- {
+- a &= SLOT_2_0;
+- b &= 0x7f;
+- b = b<<7;
+- a |= b;
+- *v = a;
+- return 3;
++/*
++** Allocate and zero memory. If the allocation fails, make
++** the mallocFailed flag in the connection pointer.
++*/
++SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3 *db, int n){
++ void *p = sqlite3DbMallocRaw(db, n);
++ if( p ){
++ memset(p, 0, n);
+ }
++ return p;
++}
+
+- /* CSE1 from below */
+- a &= SLOT_2_0;
+- p++;
+- b = b<<14;
+- b |= *p;
+- /* b: p1<<14 | p3 (unmasked) */
+- if (!(b&0x80))
+- {
+- b &= SLOT_2_0;
+- /* moved CSE1 up */
+- /* a &= (0x7f<<14)|(0x7f); */
+- a = a<<7;
+- a |= b;
+- *v = a;
+- return 4;
++/*
++** Allocate and zero memory. If the allocation fails, make
++** the mallocFailed flag in the connection pointer.
++**
++** If db!=0 and db->mallocFailed is true (indicating a prior malloc
++** failure on the same database connection) then always return 0.
++** Hence for a particular database connection, once malloc starts
++** failing, it fails consistently until mallocFailed is reset.
++** This is an important assumption. There are many places in the
++** code that do things like this:
++**
++** int *a = (int*)sqlite3DbMallocRaw(db, 100);
++** int *b = (int*)sqlite3DbMallocRaw(db, 200);
++** if( b ) a[10] = 9;
++**
++** 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){
++ void *p;
++ assert( db==0 || sqlite3_mutex_held(db->mutex) );
++ assert( db==0 || db->pnBytesFreed==0 );
++#ifndef SQLITE_OMIT_LOOKASIDE
++ if( db ){
++ LookasideSlot *pBuf;
++ if( db->mallocFailed ){
++ return 0;
++ }
++ if( db->lookaside.bEnabled ){
++ if( n>db->lookaside.sz ){
++ db->lookaside.anStat[1]++;
++ }else if( (pBuf = db->lookaside.pFree)==0 ){
++ db->lookaside.anStat[2]++;
++ }else{
++ db->lookaside.pFree = pBuf->pNext;
++ db->lookaside.nOut++;
++ db->lookaside.anStat[0]++;
++ if( db->lookaside.nOut>db->lookaside.mxOut ){
++ db->lookaside.mxOut = db->lookaside.nOut;
++ }
++ return (void*)pBuf;
++ }
++ }
+ }
+-
+- /* a: p0<<14 | p2 (masked) */
+- /* b: p1<<14 | p3 (unmasked) */
+- /* 1:save off p0<<21 | p1<<14 | p2<<7 | p3 (masked) */
+- /* moved CSE1 up */
+- /* a &= (0x7f<<14)|(0x7f); */
+- b &= SLOT_2_0;
+- s = a;
+- /* s: p0<<14 | p2 (masked) */
+-
+- p++;
+- a = a<<14;
+- a |= *p;
+- /* a: p0<<28 | p2<<14 | p4 (unmasked) */
+- if (!(a&0x80))
+- {
+- /* we can skip these cause they were (effectively) done above in calc'ing s */
+- /* a &= (0x7f<<28)|(0x7f<<14)|(0x7f); */
+- /* b &= (0x7f<<14)|(0x7f); */
+- b = b<<7;
+- a |= b;
+- s = s>>18;
+- *v = ((u64)s)<<32 | a;
+- return 5;
++#else
++ if( db && db->mallocFailed ){
++ return 0;
+ }
+-
+- /* 2:save off p0<<21 | p1<<14 | p2<<7 | p3 (masked) */
+- s = s<<7;
+- s |= b;
+- /* s: p0<<21 | p1<<14 | p2<<7 | p3 (masked) */
+-
+- p++;
+- b = b<<14;
+- b |= *p;
+- /* b: p1<<28 | p3<<14 | p5 (unmasked) */
+- if (!(b&0x80))
+- {
+- /* we can skip this cause it was (effectively) done above in calc'ing s */
+- /* b &= (0x7f<<28)|(0x7f<<14)|(0x7f); */
+- a &= SLOT_2_0;
+- a = a<<7;
+- a |= b;
+- s = s>>18;
+- *v = ((u64)s)<<32 | a;
+- return 6;
++#endif
++ p = sqlite3Malloc(n);
++ if( !p && db ){
++ db->mallocFailed = 1;
+ }
++ sqlite3MemdebugSetType(p, MEMTYPE_DB |
++ ((db && db->lookaside.bEnabled) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP));
++ return p;
++}
+
+- p++;
+- a = a<<14;
+- a |= *p;
+- /* a: p2<<28 | p4<<14 | p6 (unmasked) */
+- if (!(a&0x80))
+- {
+- a &= SLOT_4_2_0;
+- b &= SLOT_2_0;
+- b = b<<7;
+- a |= b;
+- s = s>>11;
+- *v = ((u64)s)<<32 | a;
+- return 7;
++/*
++** 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){
++ void *pNew = 0;
++ assert( db!=0 );
++ assert( sqlite3_mutex_held(db->mutex) );
++ if( db->mallocFailed==0 ){
++ if( p==0 ){
++ return sqlite3DbMallocRaw(db, n);
++ }
++ if( isLookaside(db, p) ){
++ if( n<=db->lookaside.sz ){
++ return p;
++ }
++ pNew = sqlite3DbMallocRaw(db, n);
++ if( pNew ){
++ memcpy(pNew, p, db->lookaside.sz);
++ sqlite3DbFree(db, p);
++ }
++ }else{
++ assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) );
++ assert( sqlite3MemdebugHasType(p, MEMTYPE_LOOKASIDE|MEMTYPE_HEAP) );
++ sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
++ pNew = sqlite3_realloc(p, n);
++ if( !pNew ){
++ sqlite3MemdebugSetType(p, MEMTYPE_DB|MEMTYPE_HEAP);
++ db->mallocFailed = 1;
++ }
++ sqlite3MemdebugSetType(pNew, MEMTYPE_DB |
++ (db->lookaside.bEnabled ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP));
++ }
+ }
++ return pNew;
++}
+
+- /* CSE2 from below */
+- a &= SLOT_2_0;
+- p++;
+- b = b<<14;
+- b |= *p;
+- /* b: p3<<28 | p5<<14 | p7 (unmasked) */
+- if (!(b&0x80))
+- {
+- b &= SLOT_4_2_0;
+- /* moved CSE2 up */
+- /* a &= (0x7f<<14)|(0x7f); */
+- a = a<<7;
+- a |= b;
+- s = s>>4;
+- *v = ((u64)s)<<32 | a;
+- return 8;
++/*
++** 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){
++ void *pNew;
++ pNew = sqlite3DbRealloc(db, p, n);
++ if( !pNew ){
++ sqlite3DbFree(db, p);
+ }
+-
+- p++;
+- a = a<<15;
+- a |= *p;
+- /* a: p4<<29 | p6<<15 | p8 (unmasked) */
+-
+- /* moved CSE2 up */
+- /* a &= (0x7f<<29)|(0x7f<<15)|(0xff); */
+- b &= SLOT_2_0;
+- b = b<<8;
+- a |= b;
+-
+- s = s<<4;
+- b = p[-4];
+- b &= 0x7f;
+- b = b>>3;
+- s |= b;
+-
+- *v = ((u64)s)<<32 | a;
+-
+- return 9;
++ return pNew;
+ }
+
+ /*
+-** Read a 32-bit variable-length integer from memory starting at p[0].
+-** Return the number of bytes read. The value is stored in *v.
+-**
+-** If the varint stored in p[0] is larger than can fit in a 32-bit unsigned
+-** integer, then set *v to 0xffffffff.
+-**
+-** A MACRO version, getVarint32, 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.
++** Make a copy of a string in memory obtained from sqliteMalloc(). These
++** functions call sqlite3MallocRaw() directly instead of sqliteMalloc(). This
++** is because when memory debugging is turned on, these two functions are
++** called via macros that record the current file and line number in the
++** ThreadData structure.
+ */
+-SQLITE_PRIVATE u8 sqlite3GetVarint32(const unsigned char *p, u32 *v){
+- u32 a,b;
+-
+- /* The 1-byte case. Overwhelmingly the most common. Handled inline
+- ** by the getVarin32() macro */
+- a = *p;
+- /* a: p0 (unmasked) */
+-#ifndef getVarint32
+- if (!(a&0x80))
+- {
+- /* Values between 0 and 127 */
+- *v = a;
+- return 1;
++SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3 *db, const char *z){
++ char *zNew;
++ size_t n;
++ if( z==0 ){
++ return 0;
+ }
+-#endif
+-
+- /* The 2-byte case */
+- p++;
+- b = *p;
+- /* b: p1 (unmasked) */
+- if (!(b&0x80))
+- {
+- /* Values between 128 and 16383 */
+- a &= 0x7f;
+- a = a<<7;
+- *v = a | b;
+- return 2;
++ n = sqlite3Strlen30(z) + 1;
++ assert( (n&0x7fffffff)==n );
++ zNew = sqlite3DbMallocRaw(db, (int)n);
++ if( zNew ){
++ memcpy(zNew, z, n);
+ }
+-
+- /* The 3-byte case */
+- p++;
+- a = a<<14;
+- a |= *p;
+- /* a: p0<<14 | p2 (unmasked) */
+- if (!(a&0x80))
+- {
+- /* Values between 16384 and 2097151 */
+- a &= (0x7f<<14)|(0x7f);
+- b &= 0x7f;
+- b = b<<7;
+- *v = a | b;
+- return 3;
++ return zNew;
++}
++SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3 *db, const char *z, int n){
++ char *zNew;
++ if( z==0 ){
++ return 0;
+ }
+-
+- /* A 32-bit varint is used to store size information in btrees.
+- ** Objects are rarely larger than 2MiB limit of a 3-byte varint.
+- ** A 3-byte varint is sufficient, for example, to record the size
+- ** of a 1048569-byte BLOB or string.
+- **
+- ** We only unroll the first 1-, 2-, and 3- byte cases. The very
+- ** rare larger cases can be handled by the slower 64-bit varint
+- ** routine.
+- */
+-#if 1
+- {
+- u64 v64;
+- u8 n;
+-
+- p -= 2;
+- n = sqlite3GetVarint(p, &v64);
+- assert( n>3 && n<=9 );
+- if( (v64 & SQLITE_MAX_U32)!=v64 ){
+- *v = 0xffffffff;
+- }else{
+- *v = (u32)v64;
+- }
+- return n;
++ assert( (n&0x7fffffff)==n );
++ zNew = sqlite3DbMallocRaw(db, n+1);
++ if( zNew ){
++ memcpy(zNew, z, n);
++ zNew[n] = 0;
+ }
++ return zNew;
++}
+
+-#else
+- /* For following code (kept for historical record only) shows an
+- ** unrolling for the 3- and 4-byte varint cases. This code is
+- ** slightly faster, but it is also larger and much harder to test.
+- */
+- p++;
+- b = b<<14;
+- b |= *p;
+- /* b: p1<<14 | p3 (unmasked) */
+- if (!(b&0x80))
+- {
+- /* Values between 2097152 and 268435455 */
+- b &= (0x7f<<14)|(0x7f);
+- a &= (0x7f<<14)|(0x7f);
+- a = a<<7;
+- *v = a | b;
+- return 4;
+- }
++/*
++** Create a string from the zFromat argument and the va_list that follows.
++** Store the string in memory obtained from sqliteMalloc() and make *pz
++** point to that string.
++*/
++SQLITE_PRIVATE void sqlite3SetString(char **pz, sqlite3 *db, const char *zFormat, ...){
++ va_list ap;
++ char *z;
+
+- p++;
+- a = a<<14;
+- a |= *p;
+- /* a: p0<<28 | p2<<14 | p4 (unmasked) */
+- if (!(a&0x80))
+- {
+- /* Values between 268435456 and 34359738367 */
+- a &= SLOT_4_2_0;
+- b &= SLOT_4_2_0;
+- b = b<<7;
+- *v = a | b;
+- return 5;
+- }
++ va_start(ap, zFormat);
++ z = sqlite3VMPrintf(db, zFormat, ap);
++ va_end(ap);
++ sqlite3DbFree(db, *pz);
++ *pz = z;
++}
+
+- /* We can only reach this point when reading a corrupt database
+- ** file. In that case we are not in any hurry. Use the (relatively
+- ** slow) general-purpose sqlite3GetVarint() routine to extract the
+- ** value. */
+- {
+- u64 v64;
+- u8 n;
+
+- p -= 4;
+- n = sqlite3GetVarint(p, &v64);
+- assert( n>5 && n<=9 );
+- *v = (u32)v64;
+- return n;
++/*
++** This function must be called before exiting any API function (i.e.
++** returning control to the user) that has called sqlite3_malloc or
++** sqlite3_realloc.
++**
++** The returned value is normally a copy of the second argument to this
++** function. However, if a malloc() failure has occurred since the previous
++** invocation SQLITE_NOMEM is returned instead.
++**
++** If the first argument, db, is not NULL and a malloc() error has occurred,
++** then the connection error-code (the value returned by sqlite3_errcode())
++** is set to SQLITE_NOMEM.
++*/
++SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){
++ /* If the db handle is not NULL, then we must hold the connection handle
++ ** mutex here. Otherwise the read (and possible write) of db->mallocFailed
++ ** 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;
+ }
+-#endif
++ return rc & (db ? db->errMask : 0xff);
+ }
+
++/************** End of malloc.c **********************************************/
++/************** Begin file printf.c ******************************************/
+ /*
+-** Return the number of bytes that will be needed to store the given
+-** 64-bit integer.
++** The "printf" code that follows dates from the 1980's. It is in
++** the public domain. The original comments are included here for
++** completeness. They are very out-of-date but might be useful as
++** an historical reference. Most of the "enhancements" have been backed
++** out so that the functionality is now the same as standard printf().
++**
++**************************************************************************
++**
++** This file contains code for a set of "printf"-like routines. These
++** routines format strings much like the printf() from the standard C
++** library, though the implementation here has enhancements to support
++** SQLlite.
+ */
+-SQLITE_PRIVATE int sqlite3VarintLen(u64 v){
+- int i = 0;
+- do{
+- i++;
+- v >>= 7;
+- }while( v!=0 && ALWAYS(i<9) );
+- return i;
+-}
+-
+
+ /*
+-** Read or write a four-byte big-endian integer value.
++** Conversion types fall into various categories as defined by the
++** following enumeration.
+ */
+-SQLITE_PRIVATE u32 sqlite3Get4byte(const u8 *p){
+- return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
+-}
+-SQLITE_PRIVATE void sqlite3Put4byte(unsigned char *p, u32 v){
+- p[0] = (u8)(v>>24);
+- p[1] = (u8)(v>>16);
+- p[2] = (u8)(v>>8);
+- p[3] = (u8)v;
+-}
++#define etRADIX 1 /* Integer types. %d, %x, %o, and so forth */
++#define etFLOAT 2 /* Floating point. %f */
++#define etEXP 3 /* Exponentional notation. %e and %E */
++#define etGENERIC 4 /* Floating or exponential, depending on exponent. %g */
++#define etSIZE 5 /* Return number of characters processed so far. %n */
++#define etSTRING 6 /* Strings. %s */
++#define etDYNSTRING 7 /* Dynamically allocated strings. %z */
++#define etPERCENT 8 /* Percent symbol. %% */
++#define etCHARX 9 /* Characters. %c */
++/* The rest are extensions, not normally found in printf() */
++#define etSQLESCAPE 10 /* Strings with '\'' doubled. %q */
++#define etSQLESCAPE2 11 /* Strings with '\'' doubled and enclosed in '',
++ NULL pointers replaced by SQL NULL. %Q */
++#define etTOKEN 12 /* a pointer to a Token structure */
++#define etSRCLIST 13 /* a pointer to a SrcList */
++#define etPOINTER 14 /* The %p conversion */
++#define etSQLESCAPE3 15 /* %w -> Strings with '\"' doubled */
++#define etORDINAL 16 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */
+
++#define etINVALID 0 /* Any unrecognized conversion type */
+
+
+ /*
+-** Translate a single byte of Hex into an integer.
+-** This routine only works if h really is a valid hexadecimal
+-** character: 0..9a..fA..F
++** An "etByte" is an 8-bit unsigned value.
+ */
+-SQLITE_PRIVATE u8 sqlite3HexToInt(int h){
+- assert( (h>='0' && h<='9') || (h>='a' && h<='f') || (h>='A' && h<='F') );
+-#ifdef SQLITE_ASCII
+- h += 9*(1&(h>>6));
+-#endif
+-#ifdef SQLITE_EBCDIC
+- h += 9*(1&~(h>>4));
+-#endif
+- return (u8)(h & 0xf);
+-}
++typedef unsigned char etByte;
+
+-#if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC)
+ /*
+-** Convert a BLOB literal of the form "x'hhhhhh'" into its binary
+-** value. Return a pointer to its binary value. Space to hold the
+-** binary value has been obtained from malloc and must be freed by
+-** the calling routine.
++** Each builtin conversion character (ex: the 'd' in "%d") is described
++** by an instance of the following structure
+ */
+-SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){
+- char *zBlob;
+- int i;
+-
+- zBlob = (char *)sqlite3DbMallocRaw(db, n/2 + 1);
+- n--;
+- if( zBlob ){
+- for(i=0; i<n; i+=2){
+- zBlob[i/2] = (sqlite3HexToInt(z[i])<<4) | sqlite3HexToInt(z[i+1]);
+- }
+- zBlob[i/2] = 0;
+- }
+- return zBlob;
+-}
+-#endif /* !SQLITE_OMIT_BLOB_LITERAL || SQLITE_HAS_CODEC */
++typedef struct et_info { /* Information about each format field */
++ char fmttype; /* The format field code letter */
++ etByte base; /* The base for radix conversion */
++ etByte flags; /* One or more of FLAG_ constants below */
++ etByte type; /* Conversion paradigm */
++ etByte charset; /* Offset into aDigits[] of the digits string */
++ etByte prefix; /* Offset into aPrefix[] of the prefix string */
++} et_info;
+
+ /*
+-** Log an error that is an API call on a connection pointer that should
+-** not have been used. The "type" of connection pointer is given as the
+-** argument. The zType is a word like "NULL" or "closed" or "invalid".
++** Allowed values for et_info.flags
+ */
+-static void logBadConnection(const char *zType){
+- sqlite3_log(SQLITE_MISUSE,
+- "API call with %s database connection pointer",
+- zType
+- );
+-}
++#define FLAG_SIGNED 1 /* True if the value to convert is signed */
++#define FLAG_INTERN 2 /* True if for internal use only */
++#define FLAG_STRING 4 /* Allow infinity precision */
++
+
+ /*
+-** Check to make sure we have a valid db pointer. This test is not
+-** foolproof but it does provide some measure of protection against
+-** misuse of the interface such as passing in db pointers that are
+-** NULL or which have been previously closed. If this routine returns
+-** 1 it means that the db pointer is valid and 0 if it should not be
+-** dereferenced for any reason. The calling function should invoke
+-** SQLITE_MISUSE immediately.
+-**
+-** sqlite3SafetyCheckOk() requires that the db pointer be valid for
+-** use. sqlite3SafetyCheckSickOrOk() allows a db pointer that failed to
+-** open properly and is not fit for general use but which can be
+-** used as an argument to sqlite3_errmsg() or sqlite3_close().
++** The following table is searched linearly, so it is good to put the
++** most frequently used conversion types first.
+ */
+-SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3 *db){
+- u32 magic;
+- if( db==0 ){
+- logBadConnection("NULL");
+- return 0;
+- }
+- magic = db->magic;
+- if( magic!=SQLITE_MAGIC_OPEN ){
+- if( sqlite3SafetyCheckSickOrOk(db) ){
+- testcase( sqlite3GlobalConfig.xLog!=0 );
+- logBadConnection("unopened");
+- }
+- return 0;
+- }else{
+- return 1;
+- }
+-}
+-SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3 *db){
+- u32 magic;
+- magic = db->magic;
+- if( magic!=SQLITE_MAGIC_SICK &&
+- magic!=SQLITE_MAGIC_OPEN &&
+- magic!=SQLITE_MAGIC_BUSY ){
+- testcase( sqlite3GlobalConfig.xLog!=0 );
+- logBadConnection("invalid");
+- return 0;
+- }else{
+- return 1;
+- }
+-}
+-
+-/*
+-** Attempt to add, substract, or multiply the 64-bit signed value iB against
+-** the other 64-bit signed integer at *pA and store the result in *pA.
+-** Return 0 on success. Or if the operation would have resulted in an
+-** overflow, leave *pA unchanged and return 1.
+-*/
+-SQLITE_PRIVATE int sqlite3AddInt64(i64 *pA, i64 iB){
+- i64 iA = *pA;
+- testcase( iA==0 ); testcase( iA==1 );
+- testcase( iB==-1 ); testcase( iB==0 );
+- if( iB>=0 ){
+- testcase( iA>0 && LARGEST_INT64 - iA == iB );
+- testcase( iA>0 && LARGEST_INT64 - iA == iB - 1 );
+- if( iA>0 && LARGEST_INT64 - iA < iB ) return 1;
+- *pA += iB;
+- }else{
+- testcase( iA<0 && -(iA + LARGEST_INT64) == iB + 1 );
+- testcase( iA<0 && -(iA + LARGEST_INT64) == iB + 2 );
+- if( iA<0 && -(iA + LARGEST_INT64) > iB + 1 ) return 1;
+- *pA += iB;
+- }
+- return 0;
+-}
+-SQLITE_PRIVATE int sqlite3SubInt64(i64 *pA, i64 iB){
+- testcase( iB==SMALLEST_INT64+1 );
+- if( iB==SMALLEST_INT64 ){
+- testcase( (*pA)==(-1) ); testcase( (*pA)==0 );
+- if( (*pA)>=0 ) return 1;
+- *pA -= iB;
+- return 0;
+- }else{
+- return sqlite3AddInt64(pA, -iB);
+- }
+-}
+-#define TWOPOWER32 (((i64)1)<<32)
+-#define TWOPOWER31 (((i64)1)<<31)
+-SQLITE_PRIVATE int sqlite3MulInt64(i64 *pA, i64 iB){
+- i64 iA = *pA;
+- i64 iA1, iA0, iB1, iB0, r;
++static const char aDigits[] = "0123456789ABCDEF0123456789abcdef";
++static const char aPrefix[] = "-x0\000X0";
++static const et_info fmtinfo[] = {
++ { 'd', 10, 1, etRADIX, 0, 0 },
++ { 's', 0, 4, etSTRING, 0, 0 },
++ { 'g', 0, 1, etGENERIC, 30, 0 },
++ { 'z', 0, 4, etDYNSTRING, 0, 0 },
++ { 'q', 0, 4, etSQLESCAPE, 0, 0 },
++ { 'Q', 0, 4, etSQLESCAPE2, 0, 0 },
++ { 'w', 0, 4, etSQLESCAPE3, 0, 0 },
++ { 'c', 0, 0, etCHARX, 0, 0 },
++ { 'o', 8, 0, etRADIX, 0, 2 },
++ { 'u', 10, 0, etRADIX, 0, 0 },
++ { 'x', 16, 0, etRADIX, 16, 1 },
++ { 'X', 16, 0, etRADIX, 0, 4 },
++#ifndef SQLITE_OMIT_FLOATING_POINT
++ { 'f', 0, 1, etFLOAT, 0, 0 },
++ { 'e', 0, 1, etEXP, 30, 0 },
++ { 'E', 0, 1, etEXP, 14, 0 },
++ { 'G', 0, 1, etGENERIC, 14, 0 },
++#endif
++ { 'i', 10, 1, etRADIX, 0, 0 },
++ { 'n', 0, 0, etSIZE, 0, 0 },
++ { '%', 0, 0, etPERCENT, 0, 0 },
++ { 'p', 16, 0, etPOINTER, 0, 1 },
+
+- iA1 = iA/TWOPOWER32;
+- iA0 = iA % TWOPOWER32;
+- iB1 = iB/TWOPOWER32;
+- iB0 = iB % TWOPOWER32;
+- if( iA1*iB1 != 0 ) return 1;
+- assert( iA1*iB0==0 || iA0*iB1==0 );
+- r = iA1*iB0 + iA0*iB1;
+- testcase( r==(-TWOPOWER31)-1 );
+- testcase( r==(-TWOPOWER31) );
+- testcase( r==TWOPOWER31 );
+- testcase( r==TWOPOWER31-1 );
+- if( r<(-TWOPOWER31) || r>=TWOPOWER31 ) return 1;
+- r *= TWOPOWER32;
+- if( sqlite3AddInt64(&r, iA0*iB0) ) return 1;
+- *pA = r;
+- return 0;
+-}
++/* All the rest have the FLAG_INTERN bit set and are thus for internal
++** use only */
++ { 'T', 0, 2, etTOKEN, 0, 0 },
++ { 'S', 0, 2, etSRCLIST, 0, 0 },
++ { 'r', 10, 3, etORDINAL, 0, 0 },
++};
+
+ /*
+-** Compute the absolute value of a 32-bit signed integer, of possible. Or
+-** if the integer has a value of -2147483648, return +2147483647
++** If SQLITE_OMIT_FLOATING_POINT is defined, then none of the floating point
++** conversions will work.
+ */
+-SQLITE_PRIVATE int sqlite3AbsInt32(int x){
+- if( x>=0 ) return x;
+- if( x==(int)0x80000000 ) return 0x7fffffff;
+- return -x;
+-}
+-
+-#ifdef SQLITE_ENABLE_8_3_NAMES
++#ifndef SQLITE_OMIT_FLOATING_POINT
+ /*
+-** If SQLITE_ENABLE_8_3_NAMES is set at compile-time and if the database
+-** filename in zBaseFilename is a URI with the "8_3_names=1" parameter and
+-** if filename in z[] has a suffix (a.k.a. "extension") that is longer than
+-** three characters, then shorten the suffix on z[] to be the last three
+-** characters of the original suffix.
+-**
+-** If SQLITE_ENABLE_8_3_NAMES is set to 2 at compile-time, then always
+-** do the suffix shortening regardless of URI parameter.
++** "*val" is a double such that 0.1 <= *val < 10.0
++** Return the ascii code for the leading digit of *val, then
++** multiply "*val" by 10.0 to renormalize.
+ **
+-** Examples:
++** Example:
++** input: *val = 3.14159
++** output: *val = 1.4159 function return = '3'
+ **
+-** test.db-journal => test.nal
+-** test.db-wal => test.wal
+-** test.db-shm => test.shm
+-** test.db-mj7f3319fa => test.9fa
++** The counter *cnt is incremented each time. After counter exceeds
++** 16 (the number of significant digits in a 64-bit float) '0' is
++** always returned.
+ */
+-SQLITE_PRIVATE void sqlite3FileSuffix3(const char *zBaseFilename, char *z){
+-#if SQLITE_ENABLE_8_3_NAMES<2
+- if( sqlite3_uri_boolean(zBaseFilename, "8_3_names", 0) )
+-#endif
+- {
+- int i, sz;
+- sz = sqlite3Strlen30(z);
+- for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){}
+- if( z[i]=='.' && ALWAYS(sz>i+4) ) memmove(&z[i+1], &z[sz-3], 4);
+- }
++static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
++ int digit;
++ LONGDOUBLE_TYPE d;
++ if( (*cnt)<=0 ) return '0';
++ (*cnt)--;
++ digit = (int)*val;
++ d = digit;
++ digit += '0';
++ *val = (*val - d)*10.0;
++ return (char)digit;
+ }
+-#endif
++#endif /* SQLITE_OMIT_FLOATING_POINT */
+
+-/************** End of util.c ************************************************/
+-/************** Begin file hash.c ********************************************/
+ /*
+-** 2001 September 22
+-**
+-** 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 generic hash-tables
+-** used in SQLite.
+-*/
+-/* #include <assert.h> */
+-
+-/* Turn bulk memory into a hash table object by initializing the
+-** fields of the Hash structure.
+-**
+-** "pNew" is a pointer to the hash table that is to be initialized.
+-*/
+-SQLITE_PRIVATE void sqlite3HashInit(Hash *pNew){
+- assert( pNew!=0 );
+- pNew->first = 0;
+- pNew->count = 0;
+- pNew->htsize = 0;
+- pNew->ht = 0;
+-}
+-
+-/* Remove all entries from a hash table. Reclaim all memory.
+-** Call this routine to delete a hash table or to reset a hash table
+-** to the empty state.
++** Append N space characters to the given string buffer.
+ */
+-SQLITE_PRIVATE void sqlite3HashClear(Hash *pH){
+- HashElem *elem; /* For looping over all elements of the table */
+-
+- assert( pH!=0 );
+- elem = pH->first;
+- pH->first = 0;
+- sqlite3_free(pH->ht);
+- pH->ht = 0;
+- pH->htsize = 0;
+- while( elem ){
+- HashElem *next_elem = elem->next;
+- sqlite3_free(elem);
+- elem = next_elem;
++SQLITE_PRIVATE void sqlite3AppendSpace(StrAccum *pAccum, int N){
++ static const char zSpaces[] = " ";
++ while( N>=(int)sizeof(zSpaces)-1 ){
++ sqlite3StrAccumAppend(pAccum, zSpaces, sizeof(zSpaces)-1);
++ N -= sizeof(zSpaces)-1;
++ }
++ if( N>0 ){
++ sqlite3StrAccumAppend(pAccum, zSpaces, N);
+ }
+- pH->count = 0;
+ }
+
+ /*
+-** The hashing function.
++** On machines with a small stack size, you can redefine the
++** SQLITE_PRINT_BUF_SIZE to be something smaller, if desired.
+ */
+-static unsigned int strHash(const char *z, int nKey){
+- int h = 0;
+- assert( nKey>=0 );
+- while( nKey > 0 ){
+- h = (h<<3) ^ h ^ sqlite3UpperToLower[(unsigned char)*z++];
+- nKey--;
+- }
+- return h;
+-}
+-
++#ifndef SQLITE_PRINT_BUF_SIZE
++# define SQLITE_PRINT_BUF_SIZE 70
++#endif
++#define etBUFSIZE SQLITE_PRINT_BUF_SIZE /* Size of the output buffer */
+
+-/* Link pNew element into the hash table pH. If pEntry!=0 then also
+-** insert pNew into the pEntry hash bucket.
++/*
++** Render a string given by "fmt" into the StrAccum object.
+ */
+-static void insertElement(
+- Hash *pH, /* The complete hash table */
+- struct _ht *pEntry, /* The entry into which pNew is inserted */
+- HashElem *pNew /* The element to be inserted */
++SQLITE_PRIVATE void sqlite3VXPrintf(
++ StrAccum *pAccum, /* Accumulate results here */
++ int useExtended, /* Allow extended %-conversions */
++ const char *fmt, /* Format string */
++ va_list ap /* arguments */
+ ){
+- HashElem *pHead; /* First element already in pEntry */
+- if( pEntry ){
+- pHead = pEntry->count ? pEntry->chain : 0;
+- pEntry->count++;
+- pEntry->chain = pNew;
+- }else{
+- pHead = 0;
+- }
+- if( pHead ){
+- pNew->next = pHead;
+- pNew->prev = pHead->prev;
+- if( pHead->prev ){ pHead->prev->next = pNew; }
+- else { pH->first = pNew; }
+- pHead->prev = pNew;
+- }else{
+- pNew->next = pH->first;
+- if( pH->first ){ pH->first->prev = pNew; }
+- pNew->prev = 0;
+- pH->first = pNew;
+- }
+-}
+-
+-
+-/* Resize the hash table so that it cantains "new_size" buckets.
+-**
+-** The hash table might fail to resize if sqlite3_malloc() fails or
+-** if the new size is the same as the prior size.
+-** Return TRUE if the resize occurs and false if not.
+-*/
+-static int rehash(Hash *pH, unsigned int new_size){
+- struct _ht *new_ht; /* The new hash table */
+- HashElem *elem, *next_elem; /* For looping over existing elements */
+-
+-#if SQLITE_MALLOC_SOFT_LIMIT>0
+- if( new_size*sizeof(struct _ht)>SQLITE_MALLOC_SOFT_LIMIT ){
+- new_size = SQLITE_MALLOC_SOFT_LIMIT/sizeof(struct _ht);
+- }
+- if( new_size==pH->htsize ) return 0;
++ int c; /* Next character in the format string */
++ char *bufpt; /* Pointer to the conversion buffer */
++ int precision; /* Precision of the current field */
++ int length; /* Length of the field */
++ int idx; /* A general purpose loop counter */
++ int width; /* Width of the current field */
++ etByte flag_leftjustify; /* True if "-" flag is present */
++ etByte flag_plussign; /* True if "+" flag is present */
++ etByte flag_blanksign; /* True if " " flag is present */
++ etByte flag_alternateform; /* True if "#" flag is present */
++ etByte flag_altform2; /* True if "!" flag is present */
++ etByte flag_zeropad; /* True if field width constant starts with zero */
++ etByte flag_long; /* True if "l" flag is present */
++ etByte flag_longlong; /* True if the "ll" flag is present */
++ etByte done; /* Loop termination flag */
++ etByte xtype = 0; /* Conversion paradigm */
++ char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */
++ sqlite_uint64 longvalue; /* Value for integer types */
++ LONGDOUBLE_TYPE realvalue; /* Value for real types */
++ 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 */
++#ifndef SQLITE_OMIT_FLOATING_POINT
++ int exp, e2; /* exponent of real numbers */
++ int nsd; /* Number of significant digits returned */
++ double rounder; /* Used for rounding floating point values */
++ etByte flag_dp; /* True if decimal point should be shown */
++ etByte flag_rtz; /* True if trailing zeros should be removed */
+ #endif
++ char buf[etBUFSIZE]; /* Conversion buffer */
+
+- /* The inability to allocates space for a larger hash table is
+- ** a performance hit but it is not a fatal error. So mark the
+- ** allocation as a benign. Use sqlite3Malloc()/memset(0) instead of
+- ** sqlite3MallocZero() to make the allocation, as sqlite3MallocZero()
+- ** only zeroes the requested number of bytes whereas this module will
+- ** use the actual amount of space allocated for the hash table (which
+- ** may be larger than the requested amount).
+- */
+- sqlite3BeginBenignMalloc();
+- new_ht = (struct _ht *)sqlite3Malloc( new_size*sizeof(struct _ht) );
+- sqlite3EndBenignMalloc();
++ bufpt = 0;
++ for(; (c=(*fmt))!=0; ++fmt){
++ if( c!='%' ){
++ int amt;
++ bufpt = (char *)fmt;
++ amt = 1;
++ while( (c=(*++fmt))!='%' && c!=0 ) amt++;
++ sqlite3StrAccumAppend(pAccum, bufpt, amt);
++ if( c==0 ) break;
++ }
++ if( (c=(*++fmt))==0 ){
++ sqlite3StrAccumAppend(pAccum, "%", 1);
++ break;
++ }
++ /* Find out what flags are present */
++ flag_leftjustify = flag_plussign = flag_blanksign =
++ flag_alternateform = flag_altform2 = flag_zeropad = 0;
++ done = 0;
++ do{
++ switch( c ){
++ case '-': flag_leftjustify = 1; break;
++ case '+': flag_plussign = 1; break;
++ case ' ': flag_blanksign = 1; break;
++ case '#': flag_alternateform = 1; break;
++ case '!': flag_altform2 = 1; break;
++ case '0': flag_zeropad = 1; break;
++ default: done = 1; break;
++ }
++ }while( !done && (c=(*++fmt))!=0 );
++ /* Get the field width */
++ width = 0;
++ if( c=='*' ){
++ width = va_arg(ap,int);
++ if( width<0 ){
++ flag_leftjustify = 1;
++ width = -width;
++ }
++ c = *++fmt;
++ }else{
++ while( c>='0' && c<='9' ){
++ width = width*10 + c - '0';
++ c = *++fmt;
++ }
++ }
++ /* Get the precision */
++ if( c=='.' ){
++ precision = 0;
++ c = *++fmt;
++ if( c=='*' ){
++ precision = va_arg(ap,int);
++ if( precision<0 ) precision = -precision;
++ c = *++fmt;
++ }else{
++ while( c>='0' && c<='9' ){
++ precision = precision*10 + c - '0';
++ c = *++fmt;
++ }
++ }
++ }else{
++ precision = -1;
++ }
++ /* Get the conversion type modifier */
++ if( c=='l' ){
++ flag_long = 1;
++ c = *++fmt;
++ if( c=='l' ){
++ flag_longlong = 1;
++ c = *++fmt;
++ }else{
++ flag_longlong = 0;
++ }
++ }else{
++ flag_long = flag_longlong = 0;
++ }
++ /* Fetch the info entry for the field */
++ infop = &fmtinfo[0];
++ xtype = etINVALID;
++ for(idx=0; idx<ArraySize(fmtinfo); idx++){
++ if( c==fmtinfo[idx].fmttype ){
++ infop = &fmtinfo[idx];
++ if( useExtended || (infop->flags & FLAG_INTERN)==0 ){
++ xtype = infop->type;
++ }else{
++ return;
++ }
++ break;
++ }
++ }
++ zExtra = 0;
+
+- if( new_ht==0 ) return 0;
+- sqlite3_free(pH->ht);
+- pH->ht = new_ht;
+- 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;
+- next_elem = elem->next;
+- insertElement(pH, &new_ht[h], elem);
+- }
+- return 1;
+-}
++ /*
++ ** At this point, variables are initialized as follows:
++ **
++ ** flag_alternateform TRUE if a '#' is present.
++ ** flag_altform2 TRUE if a '!' is present.
++ ** flag_plussign TRUE if a '+' is present.
++ ** flag_leftjustify TRUE if a '-' is present or if the
++ ** field width was negative.
++ ** flag_zeropad TRUE if the width began with 0.
++ ** flag_long TRUE if the letter 'l' (ell) prefixed
++ ** the conversion character.
++ ** flag_longlong TRUE if the letter 'll' (ell ell) prefixed
++ ** the conversion character.
++ ** flag_blanksign TRUE if a ' ' is present.
++ ** width The specified field width. This is
++ ** always non-negative. Zero is the default.
++ ** precision The specified precision. The default
++ ** is -1.
++ ** xtype The class of the conversion.
++ ** infop Pointer to the appropriate info struct.
++ */
++ switch( xtype ){
++ case etPOINTER:
++ flag_longlong = sizeof(char*)==sizeof(i64);
++ flag_long = sizeof(char*)==sizeof(long int);
++ /* Fall through into the next case */
++ case etORDINAL:
++ case etRADIX:
++ if( infop->flags & FLAG_SIGNED ){
++ i64 v;
++ if( flag_longlong ){
++ v = va_arg(ap,i64);
++ }else if( flag_long ){
++ v = va_arg(ap,long int);
++ }else{
++ v = va_arg(ap,int);
++ }
++ if( v<0 ){
++ if( v==SMALLEST_INT64 ){
++ longvalue = ((u64)1)<<63;
++ }else{
++ longvalue = -v;
++ }
++ prefix = '-';
++ }else{
++ longvalue = v;
++ if( flag_plussign ) prefix = '+';
++ else if( flag_blanksign ) prefix = ' ';
++ else prefix = 0;
++ }
++ }else{
++ if( flag_longlong ){
++ longvalue = va_arg(ap,u64);
++ }else if( flag_long ){
++ longvalue = va_arg(ap,unsigned long int);
++ }else{
++ longvalue = va_arg(ap,unsigned int);
++ }
++ prefix = 0;
++ }
++ if( longvalue==0 ) flag_alternateform = 0;
++ if( flag_zeropad && precision<width-(prefix!=0) ){
++ precision = width-(prefix!=0);
++ }
++ if( precision<etBUFSIZE-10 ){
++ nOut = etBUFSIZE;
++ zOut = buf;
++ }else{
++ nOut = precision + 10;
++ zOut = zExtra = sqlite3Malloc( nOut );
++ if( zOut==0 ){
++ pAccum->mallocFailed = 1;
++ return;
++ }
++ }
++ bufpt = &zOut[nOut-1];
++ if( xtype==etORDINAL ){
++ static const char zOrd[] = "thstndrd";
++ int x = (int)(longvalue % 10);
++ if( x>=4 || (longvalue/10)%10==1 ){
++ x = 0;
++ }
++ *(--bufpt) = zOrd[x*2+1];
++ *(--bufpt) = zOrd[x*2];
++ }
++ {
++ register const char *cset; /* Use registers for speed */
++ register int base;
++ cset = &aDigits[infop->charset];
++ base = infop->base;
++ do{ /* Convert to ascii */
++ *(--bufpt) = cset[longvalue%base];
++ longvalue = longvalue/base;
++ }while( longvalue>0 );
++ }
++ length = (int)(&zOut[nOut-1]-bufpt);
++ for(idx=precision-length; idx>0; idx--){
++ *(--bufpt) = '0'; /* Zero pad */
++ }
++ if( prefix ) *(--bufpt) = prefix; /* Add sign */
++ if( flag_alternateform && infop->prefix ){ /* Add "0" or "0x" */
++ const char *pre;
++ char x;
++ pre = &aPrefix[infop->prefix];
++ for(; (x=(*pre))!=0; pre++) *(--bufpt) = x;
++ }
++ length = (int)(&zOut[nOut-1]-bufpt);
++ break;
++ case etFLOAT:
++ case etEXP:
++ case etGENERIC:
++ realvalue = va_arg(ap,double);
++#ifdef SQLITE_OMIT_FLOATING_POINT
++ length = 0;
++#else
++ if( precision<0 ) precision = 6; /* Set default precision */
++ if( realvalue<0.0 ){
++ realvalue = -realvalue;
++ prefix = '-';
++ }else{
++ if( flag_plussign ) prefix = '+';
++ else if( flag_blanksign ) prefix = ' ';
++ else prefix = 0;
++ }
++ if( xtype==etGENERIC && precision>0 ) precision--;
++#if 0
++ /* Rounding works like BSD when the constant 0.4999 is used. Wierd! */
++ for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1);
++#else
++ /* It makes more sense to use 0.5 */
++ for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1){}
++#endif
++ if( xtype==etFLOAT ) realvalue += rounder;
++ /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
++ exp = 0;
++ if( sqlite3IsNaN((double)realvalue) ){
++ bufpt = "NaN";
++ length = 3;
++ break;
++ }
++ if( realvalue>0.0 ){
++ LONGDOUBLE_TYPE scale = 1.0;
++ while( realvalue>=1e100*scale && exp<=350 ){ scale *= 1e100;exp+=100;}
++ while( realvalue>=1e64*scale && exp<=350 ){ scale *= 1e64; exp+=64; }
++ while( realvalue>=1e8*scale && exp<=350 ){ scale *= 1e8; exp+=8; }
++ while( realvalue>=10.0*scale && exp<=350 ){ scale *= 10.0; exp++; }
++ realvalue /= scale;
++ while( realvalue<1e-8 ){ realvalue *= 1e8; exp-=8; }
++ while( realvalue<1.0 ){ realvalue *= 10.0; exp--; }
++ if( exp>350 ){
++ if( prefix=='-' ){
++ bufpt = "-Inf";
++ }else if( prefix=='+' ){
++ bufpt = "+Inf";
++ }else{
++ bufpt = "Inf";
++ }
++ length = sqlite3Strlen30(bufpt);
++ break;
++ }
++ }
++ bufpt = buf;
++ /*
++ ** If the field type is etGENERIC, then convert to either etEXP
++ ** or etFLOAT, as appropriate.
++ */
++ if( xtype!=etFLOAT ){
++ realvalue += rounder;
++ if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; }
++ }
++ if( xtype==etGENERIC ){
++ flag_rtz = !flag_alternateform;
++ if( exp<-4 || exp>precision ){
++ xtype = etEXP;
++ }else{
++ precision = precision - exp;
++ xtype = etFLOAT;
++ }
++ }else{
++ flag_rtz = flag_altform2;
++ }
++ if( xtype==etEXP ){
++ e2 = 0;
++ }else{
++ e2 = exp;
++ }
++ if( e2+precision+width > etBUFSIZE - 15 ){
++ bufpt = zExtra = sqlite3Malloc( e2+precision+width+15 );
++ if( bufpt==0 ){
++ pAccum->mallocFailed = 1;
++ return;
++ }
++ }
++ zOut = bufpt;
++ nsd = 16 + flag_altform2*10;
++ flag_dp = (precision>0 ?1:0) | flag_alternateform | flag_altform2;
++ /* The sign in front of the number */
++ if( prefix ){
++ *(bufpt++) = prefix;
++ }
++ /* Digits prior to the decimal point */
++ if( e2<0 ){
++ *(bufpt++) = '0';
++ }else{
++ for(; e2>=0; e2--){
++ *(bufpt++) = et_getdigit(&realvalue,&nsd);
++ }
++ }
++ /* The decimal point */
++ if( flag_dp ){
++ *(bufpt++) = '.';
++ }
++ /* "0" digits after the decimal point but before the first
++ ** significant digit of the number */
++ for(e2++; e2<0; precision--, e2++){
++ assert( precision>0 );
++ *(bufpt++) = '0';
++ }
++ /* Significant digits after the decimal point */
++ while( (precision--)>0 ){
++ *(bufpt++) = et_getdigit(&realvalue,&nsd);
++ }
++ /* Remove trailing zeros and the "." if no digits follow the "." */
++ if( flag_rtz && flag_dp ){
++ while( bufpt[-1]=='0' ) *(--bufpt) = 0;
++ assert( bufpt>zOut );
++ if( bufpt[-1]=='.' ){
++ if( flag_altform2 ){
++ *(bufpt++) = '0';
++ }else{
++ *(--bufpt) = 0;
++ }
++ }
++ }
++ /* Add the "eNNN" suffix */
++ if( xtype==etEXP ){
++ *(bufpt++) = aDigits[infop->charset];
++ if( exp<0 ){
++ *(bufpt++) = '-'; exp = -exp;
++ }else{
++ *(bufpt++) = '+';
++ }
++ if( exp>=100 ){
++ *(bufpt++) = (char)((exp/100)+'0'); /* 100's digit */
++ exp %= 100;
++ }
++ *(bufpt++) = (char)(exp/10+'0'); /* 10's digit */
++ *(bufpt++) = (char)(exp%10+'0'); /* 1's digit */
++ }
++ *bufpt = 0;
+
+-/* 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.
+-*/
+-static HashElem *findElementGivenHash(
+- 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. */
+-){
+- HashElem *elem; /* Used to loop thru the element list */
+- int count; /* Number of elements left to test */
++ /* The converted number is in buf[] and zero terminated. Output it.
++ ** Note that the number is in the usual order, not reversed as with
++ ** integer conversions. */
++ length = (int)(bufpt-zOut);
++ bufpt = zOut;
+
+- if( pH->ht ){
+- struct _ht *pEntry = &pH->ht[h];
+- elem = pEntry->chain;
+- count = pEntry->count;
+- }else{
+- elem = pH->first;
+- count = pH->count;
+- }
+- while( count-- && ALWAYS(elem) ){
+- if( elem->nKey==nKey && sqlite3StrNICmp(elem->pKey,pKey,nKey)==0 ){
+- return elem;
++ /* Special case: Add leading zeros if the flag_zeropad flag is
++ ** set and we are not left justified */
++ if( flag_zeropad && !flag_leftjustify && length < width){
++ int i;
++ int nPad = width - length;
++ for(i=width; i>=nPad; i--){
++ bufpt[i] = bufpt[i-nPad];
++ }
++ i = prefix!=0;
++ while( nPad-- ) bufpt[i++] = '0';
++ length = width;
++ }
++#endif /* !defined(SQLITE_OMIT_FLOATING_POINT) */
++ break;
++ case etSIZE:
++ *(va_arg(ap,int*)) = pAccum->nChar;
++ length = width = 0;
++ break;
++ case etPERCENT:
++ buf[0] = '%';
++ bufpt = buf;
++ length = 1;
++ break;
++ case etCHARX:
++ 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;
++ }
++ bufpt = buf;
++ break;
++ case etSTRING:
++ case etDYNSTRING:
++ bufpt = va_arg(ap,char*);
++ if( bufpt==0 ){
++ bufpt = "";
++ }else if( xtype==etDYNSTRING ){
++ zExtra = bufpt;
++ }
++ if( precision>=0 ){
++ for(length=0; length<precision && bufpt[length]; length++){}
++ }else{
++ length = sqlite3Strlen30(bufpt);
++ }
++ break;
++ case etSQLESCAPE:
++ case etSQLESCAPE2:
++ case etSQLESCAPE3: {
++ int i, j, k, n, isnull;
++ int needQuote;
++ char ch;
++ char q = ((xtype==etSQLESCAPE3)?'"':'\''); /* Quote character */
++ char *escarg = va_arg(ap,char*);
++ isnull = escarg==0;
++ if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
++ k = precision;
++ for(i=n=0; k!=0 && (ch=escarg[i])!=0; i++, k--){
++ if( ch==q ) n++;
++ }
++ needQuote = !isnull && xtype==etSQLESCAPE2;
++ n += i + 1 + needQuote*2;
++ if( n>etBUFSIZE ){
++ bufpt = zExtra = sqlite3Malloc( n );
++ if( bufpt==0 ){
++ pAccum->mallocFailed = 1;
++ return;
++ }
++ }else{
++ bufpt = buf;
++ }
++ j = 0;
++ if( needQuote ) bufpt[j++] = q;
++ k = i;
++ for(i=0; i<k; i++){
++ bufpt[j++] = ch = escarg[i];
++ if( ch==q ) bufpt[j++] = ch;
++ }
++ if( needQuote ) bufpt[j++] = q;
++ bufpt[j] = 0;
++ length = j;
++ /* The precision in %q and %Q means how many input characters to
++ ** consume, not the length of the output...
++ ** if( precision>=0 && precision<length ) length = precision; */
++ break;
++ }
++ case etTOKEN: {
++ Token *pToken = va_arg(ap, Token*);
++ if( pToken ){
++ sqlite3StrAccumAppend(pAccum, (const char*)pToken->z, pToken->n);
++ }
++ length = width = 0;
++ break;
++ }
++ case etSRCLIST: {
++ SrcList *pSrc = va_arg(ap, SrcList*);
++ int k = va_arg(ap, int);
++ struct SrcList_item *pItem = &pSrc->a[k];
++ assert( k>=0 && k<pSrc->nSrc );
++ if( pItem->zDatabase ){
++ sqlite3StrAccumAppend(pAccum, pItem->zDatabase, -1);
++ sqlite3StrAccumAppend(pAccum, ".", 1);
++ }
++ sqlite3StrAccumAppend(pAccum, pItem->zName, -1);
++ length = width = 0;
++ break;
++ }
++ default: {
++ assert( xtype==etINVALID );
++ return;
++ }
++ }/* End switch over the format type */
++ /*
++ ** The text of the conversion is pointed to by "bufpt" and is
++ ** "length" characters long. The field width is "width". Do
++ ** the output.
++ */
++ if( !flag_leftjustify ){
++ register int nspace;
++ nspace = width-length;
++ if( nspace>0 ){
++ sqlite3AppendSpace(pAccum, nspace);
++ }
+ }
+- elem = elem->next;
+- }
+- return 0;
+-}
++ if( length>0 ){
++ sqlite3StrAccumAppend(pAccum, bufpt, length);
++ }
++ if( flag_leftjustify ){
++ register int nspace;
++ nspace = width-length;
++ if( nspace>0 ){
++ sqlite3AppendSpace(pAccum, nspace);
++ }
++ }
++ sqlite3_free(zExtra);
++ }/* End for loop over the format string */
++} /* End of function */
+
+-/* Remove a single entry from the hash table given a pointer to that
+-** element and a hash on the element's key.
++/*
++** Append N bytes of text from z to the StrAccum object.
+ */
+-static void removeElementGivenHash(
+- Hash *pH, /* The pH containing "elem" */
+- HashElem* elem, /* The element to be removed from the pH */
+- unsigned int h /* Hash value for the element */
+-){
+- struct _ht *pEntry;
+- if( elem->prev ){
+- elem->prev->next = elem->next;
+- }else{
+- pH->first = elem->next;
++SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
++ assert( z!=0 || N==0 );
++ if( p->tooBig | p->mallocFailed ){
++ testcase(p->tooBig);
++ testcase(p->mallocFailed);
++ return;
+ }
+- if( elem->next ){
+- elem->next->prev = elem->prev;
++ assert( p->zText!=0 || p->nChar==0 );
++ if( N<0 ){
++ N = sqlite3Strlen30(z);
+ }
+- if( pH->ht ){
+- pEntry = &pH->ht[h];
+- if( pEntry->chain==elem ){
+- pEntry->chain = elem->next;
+- }
+- pEntry->count--;
+- assert( pEntry->count>=0 );
++ if( N==0 || NEVER(z==0) ){
++ return;
+ }
+- sqlite3_free( elem );
+- pH->count--;
+- if( pH->count==0 ){
+- assert( pH->first==0 );
+- assert( pH->count==0 );
+- sqlite3HashClear(pH);
++ if( p->nChar+N >= p->nAlloc ){
++ char *zNew;
++ if( !p->useMalloc ){
++ p->tooBig = 1;
++ N = p->nAlloc - p->nChar - 1;
++ if( N<=0 ){
++ return;
++ }
++ }else{
++ char *zOld = (p->zText==p->zBase ? 0 : p->zText);
++ i64 szNew = p->nChar;
++ szNew += N + 1;
++ if( szNew > p->mxAlloc ){
++ sqlite3StrAccumReset(p);
++ p->tooBig = 1;
++ return;
++ }else{
++ p->nAlloc = (int)szNew;
++ }
++ if( p->useMalloc==1 ){
++ zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc);
++ }else{
++ zNew = sqlite3_realloc(zOld, p->nAlloc);
++ }
++ if( zNew ){
++ if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar);
++ p->zText = zNew;
++ }else{
++ p->mallocFailed = 1;
++ sqlite3StrAccumReset(p);
++ return;
++ }
++ }
+ }
++ assert( p->zText );
++ memcpy(&p->zText[p->nChar], z, N);
++ p->nChar += N;
+ }
+
+-/* 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
+-** found, or NULL if there is no match.
++/*
++** Finish off a string by making sure it is zero-terminated.
++** Return a pointer to the resulting string. Return a NULL
++** pointer if any kind of error was encountered.
+ */
+-SQLITE_PRIVATE void *sqlite3HashFind(const Hash *pH, const char *pKey, int nKey){
+- 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;
++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->zText ){
++ memcpy(p->zText, p->zBase, p->nChar+1);
++ }else{
++ p->mallocFailed = 1;
++ }
++ }
+ }
+- elem = findElementGivenHash(pH, pKey, nKey, h);
+- return elem ? elem->data : 0;
++ return p->zText;
+ }
+
+-/* Insert an element into the hash table pH. The key is pKey,nKey
+-** and the data is "data".
+-**
+-** If no element exists with a matching key, then a new
+-** element is created and NULL is returned.
+-**
+-** If another element already exists with the same key, then the
+-** new data replaces the old data and the old data is returned.
+-** The key is not copied in this instance. If a malloc fails, then
+-** the new data is returned and the hash table is unchanged.
+-**
+-** If the "data" parameter to this function is NULL, then the
+-** element corresponding to "key" is removed from the hash table.
++/*
++** Reset an StrAccum string. Reclaim all malloced memory.
+ */
+-SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, int nKey, 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);
+- if( elem ){
+- void *old_data = elem->data;
+- if( data==0 ){
+- removeElementGivenHash(pH,elem,h);
++SQLITE_PRIVATE void sqlite3StrAccumReset(StrAccum *p){
++ if( p->zText!=p->zBase ){
++ if( p->useMalloc==1 ){
++ sqlite3DbFree(p->db, p->zText);
+ }else{
+- elem->data = data;
+- elem->pKey = pKey;
+- assert(nKey==elem->nKey);
+- }
+- return old_data;
+- }
+- if( data==0 ) return 0;
+- 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;
++ sqlite3_free(p->zText);
+ }
+ }
+- if( pH->ht ){
+- insertElement(pH, &pH->ht[h], new_elem);
+- }else{
+- insertElement(pH, 0, new_elem);
+- }
+- return 0;
++ p->zText = 0;
+ }
+
+-/************** End of hash.c ************************************************/
+-/************** Begin file opcodes.c *****************************************/
+-/* Automatically generated. Do not edit */
+-/* See the mkopcodec.awk script for details. */
+-#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
+-SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
+- static const char *const azName[] = { "?",
+- /* 1 */ "Goto",
+- /* 2 */ "Gosub",
+- /* 3 */ "Return",
+- /* 4 */ "Yield",
+- /* 5 */ "HaltIfNull",
+- /* 6 */ "Halt",
+- /* 7 */ "Integer",
+- /* 8 */ "Int64",
+- /* 9 */ "String",
+- /* 10 */ "Null",
+- /* 11 */ "Blob",
+- /* 12 */ "Variable",
+- /* 13 */ "Move",
+- /* 14 */ "Copy",
+- /* 15 */ "SCopy",
+- /* 16 */ "ResultRow",
+- /* 17 */ "CollSeq",
+- /* 18 */ "Function",
+- /* 19 */ "Not",
+- /* 20 */ "AddImm",
+- /* 21 */ "MustBeInt",
+- /* 22 */ "RealAffinity",
+- /* 23 */ "Permutation",
+- /* 24 */ "Compare",
+- /* 25 */ "Jump",
+- /* 26 */ "Once",
+- /* 27 */ "If",
+- /* 28 */ "IfNot",
+- /* 29 */ "Column",
+- /* 30 */ "Affinity",
+- /* 31 */ "MakeRecord",
+- /* 32 */ "Count",
+- /* 33 */ "Savepoint",
+- /* 34 */ "AutoCommit",
+- /* 35 */ "Transaction",
+- /* 36 */ "ReadCookie",
+- /* 37 */ "SetCookie",
+- /* 38 */ "VerifyCookie",
+- /* 39 */ "OpenRead",
+- /* 40 */ "OpenWrite",
+- /* 41 */ "OpenAutoindex",
+- /* 42 */ "OpenEphemeral",
+- /* 43 */ "SorterOpen",
+- /* 44 */ "OpenPseudo",
+- /* 45 */ "Close",
+- /* 46 */ "SeekLt",
+- /* 47 */ "SeekLe",
+- /* 48 */ "SeekGe",
+- /* 49 */ "SeekGt",
+- /* 50 */ "Seek",
+- /* 51 */ "NotFound",
+- /* 52 */ "Found",
+- /* 53 */ "IsUnique",
+- /* 54 */ "NotExists",
+- /* 55 */ "Sequence",
+- /* 56 */ "NewRowid",
+- /* 57 */ "Insert",
+- /* 58 */ "InsertInt",
+- /* 59 */ "Delete",
+- /* 60 */ "ResetCount",
+- /* 61 */ "SorterCompare",
+- /* 62 */ "SorterData",
+- /* 63 */ "RowKey",
+- /* 64 */ "RowData",
+- /* 65 */ "Rowid",
+- /* 66 */ "NullRow",
+- /* 67 */ "Last",
+- /* 68 */ "Or",
+- /* 69 */ "And",
+- /* 70 */ "SorterSort",
+- /* 71 */ "Sort",
+- /* 72 */ "Rewind",
+- /* 73 */ "IsNull",
+- /* 74 */ "NotNull",
+- /* 75 */ "Ne",
+- /* 76 */ "Eq",
+- /* 77 */ "Gt",
+- /* 78 */ "Le",
+- /* 79 */ "Lt",
+- /* 80 */ "Ge",
+- /* 81 */ "SorterNext",
+- /* 82 */ "BitAnd",
+- /* 83 */ "BitOr",
+- /* 84 */ "ShiftLeft",
+- /* 85 */ "ShiftRight",
+- /* 86 */ "Add",
+- /* 87 */ "Subtract",
+- /* 88 */ "Multiply",
+- /* 89 */ "Divide",
+- /* 90 */ "Remainder",
+- /* 91 */ "Concat",
+- /* 92 */ "Prev",
+- /* 93 */ "BitNot",
+- /* 94 */ "String8",
+- /* 95 */ "Next",
+- /* 96 */ "SorterInsert",
+- /* 97 */ "IdxInsert",
+- /* 98 */ "IdxDelete",
+- /* 99 */ "IdxRowid",
+- /* 100 */ "IdxLT",
+- /* 101 */ "IdxGE",
+- /* 102 */ "Destroy",
+- /* 103 */ "Clear",
+- /* 104 */ "CreateIndex",
+- /* 105 */ "CreateTable",
+- /* 106 */ "ParseSchema",
+- /* 107 */ "LoadAnalysis",
+- /* 108 */ "DropTable",
+- /* 109 */ "DropIndex",
+- /* 110 */ "DropTrigger",
+- /* 111 */ "IntegrityCk",
+- /* 112 */ "RowSetAdd",
+- /* 113 */ "RowSetRead",
+- /* 114 */ "RowSetTest",
+- /* 115 */ "Program",
+- /* 116 */ "Param",
+- /* 117 */ "FkCounter",
+- /* 118 */ "FkIfZero",
+- /* 119 */ "MemMax",
+- /* 120 */ "IfPos",
+- /* 121 */ "IfNeg",
+- /* 122 */ "IfZero",
+- /* 123 */ "AggStep",
+- /* 124 */ "AggFinal",
+- /* 125 */ "Checkpoint",
+- /* 126 */ "JournalMode",
+- /* 127 */ "Vacuum",
+- /* 128 */ "IncrVacuum",
+- /* 129 */ "Expire",
+- /* 130 */ "Real",
+- /* 131 */ "TableLock",
+- /* 132 */ "VBegin",
+- /* 133 */ "VCreate",
+- /* 134 */ "VDestroy",
+- /* 135 */ "VOpen",
+- /* 136 */ "VFilter",
+- /* 137 */ "VColumn",
+- /* 138 */ "VNext",
+- /* 139 */ "VRename",
+- /* 140 */ "VUpdate",
+- /* 141 */ "ToText",
+- /* 142 */ "ToBlob",
+- /* 143 */ "ToNumeric",
+- /* 144 */ "ToInt",
+- /* 145 */ "ToReal",
+- /* 146 */ "Pagecount",
+- /* 147 */ "MaxPgcnt",
+- /* 148 */ "Trace",
+- /* 149 */ "Noop",
+- /* 150 */ "Explain",
+- };
+- return azName[i];
++/*
++** Initialize a string accumulator
++*/
++SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum *p, char *zBase, int n, int mx){
++ p->zText = p->zBase = zBase;
++ p->db = 0;
++ p->nChar = 0;
++ p->nAlloc = n;
++ p->mxAlloc = mx;
++ p->useMalloc = 1;
++ p->tooBig = 0;
++ p->mallocFailed = 0;
+ }
+-#endif
+
+-/************** End of opcodes.c *********************************************/
+-/************** Begin file os_unix.c *****************************************/
+ /*
+-** 2004 May 22
+-**
+-** 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 VFS implementation for unix-like operating systems
+-** include Linux, MacOSX, *BSD, QNX, VxWorks, AIX, HPUX, and others.
+-**
+-** There are actually several different VFS implementations in this file.
+-** The differences are in the way that file locking is done. The default
+-** implementation uses Posix Advisory Locks. Alternative implementations
+-** use flock(), dot-files, various proprietary locking schemas, or simply
+-** skip locking all together.
+-**
+-** This source file is organized into divisions where the logic for various
+-** subfunctions is contained within the appropriate division. PLEASE
+-** KEEP THE STRUCTURE OF THIS FILE INTACT. New code should be placed
+-** in the correct division and should be clearly labeled.
+-**
+-** The layout of divisions is as follows:
+-**
+-** * General-purpose declarations and utility functions.
+-** * Unique file ID logic used by VxWorks.
+-** * Various locking primitive implementations (all except proxy locking):
+-** + for Posix Advisory Locks
+-** + for no-op locks
+-** + for dot-file locks
+-** + for flock() locking
+-** + for named semaphore locks (VxWorks only)
+-** + for AFP filesystem locks (MacOSX only)
+-** * sqlite3_file methods not associated with locking.
+-** * Definitions of sqlite3_io_methods objects for all locking
+-** methods plus "finder" functions for each locking method.
+-** * sqlite3_vfs method implementations.
+-** * Locking primitives for the proxy uber-locking-method. (MacOSX only)
+-** * Definitions of sqlite3_vfs objects for all locking methods
+-** plus implementations of sqlite3_os_init() and sqlite3_os_end().
++** Print into memory obtained from sqliteMalloc(). Use the internal
++** %-conversion extensions.
+ */
+-#if SQLITE_OS_UNIX /* This file is used on unix only */
++SQLITE_PRIVATE char *sqlite3VMPrintf(sqlite3 *db, const char *zFormat, va_list ap){
++ char *z;
++ char zBase[SQLITE_PRINT_BUF_SIZE];
++ StrAccum acc;
++ assert( db!=0 );
++ sqlite3StrAccumInit(&acc, zBase, sizeof(zBase),
++ db->aLimit[SQLITE_LIMIT_LENGTH]);
++ acc.db = db;
++ sqlite3VXPrintf(&acc, 1, zFormat, ap);
++ z = sqlite3StrAccumFinish(&acc);
++ if( acc.mallocFailed ){
++ db->mallocFailed = 1;
++ }
++ return z;
++}
+
+-/* Use posix_fallocate() if it is available
++/*
++** Print into memory obtained from sqliteMalloc(). Use the internal
++** %-conversion extensions.
+ */
+-#if !defined(HAVE_POSIX_FALLOCATE) \
+- && (_XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L)
+-# define HAVE_POSIX_FALLOCATE 1
+-#endif
++SQLITE_PRIVATE char *sqlite3MPrintf(sqlite3 *db, const char *zFormat, ...){
++ va_list ap;
++ char *z;
++ va_start(ap, zFormat);
++ z = sqlite3VMPrintf(db, zFormat, ap);
++ va_end(ap);
++ return z;
++}
+
+ /*
+-** There are various methods for file locking used for concurrency
+-** control:
++** Like sqlite3MPrintf(), but call sqlite3DbFree() on zStr after formatting
++** the string and before returnning. This routine is intended to be used
++** to modify an existing string. For example:
+ **
+-** 1. POSIX locking (the default),
+-** 2. No locking,
+-** 3. Dot-file locking,
+-** 4. flock() locking,
+-** 5. AFP locking (OSX only),
+-** 6. Named POSIX semaphores (VXWorks only),
+-** 7. proxy locking. (OSX only)
++** x = sqlite3MPrintf(db, x, "prefix %s suffix", x);
+ **
+-** Styles 4, 5, and 7 are only available of SQLITE_ENABLE_LOCKING_STYLE
+-** is defined to 1. The SQLITE_ENABLE_LOCKING_STYLE also enables automatic
+-** selection of the appropriate locking style based on the filesystem
+-** where the database is located.
+ */
+-#if !defined(SQLITE_ENABLE_LOCKING_STYLE)
+-# if defined(__APPLE__)
+-# define SQLITE_ENABLE_LOCKING_STYLE 1
+-# else
+-# define SQLITE_ENABLE_LOCKING_STYLE 0
+-# endif
++SQLITE_PRIVATE char *sqlite3MAppendf(sqlite3 *db, char *zStr, const char *zFormat, ...){
++ va_list ap;
++ char *z;
++ va_start(ap, zFormat);
++ z = sqlite3VMPrintf(db, zFormat, ap);
++ va_end(ap);
++ sqlite3DbFree(db, zStr);
++ return z;
++}
++
++/*
++** Print into memory obtained from sqlite3_malloc(). Omit the internal
++** %-conversion extensions.
++*/
++SQLITE_API char *sqlite3_vmprintf(const char *zFormat, va_list ap){
++ char *z;
++ char zBase[SQLITE_PRINT_BUF_SIZE];
++ StrAccum acc;
++#ifndef SQLITE_OMIT_AUTOINIT
++ if( sqlite3_initialize() ) return 0;
+ #endif
++ sqlite3StrAccumInit(&acc, zBase, sizeof(zBase), SQLITE_MAX_LENGTH);
++ acc.useMalloc = 2;
++ sqlite3VXPrintf(&acc, 0, zFormat, ap);
++ z = sqlite3StrAccumFinish(&acc);
++ return z;
++}
+
+ /*
+-** Define the OS_VXWORKS pre-processor macro to 1 if building on
+-** vxworks, or 0 otherwise.
++** Print into memory obtained from sqlite3_malloc()(). Omit the internal
++** %-conversion extensions.
+ */
+-#ifndef OS_VXWORKS
+-# if defined(__RTP__) || defined(_WRS_KERNEL)
+-# define OS_VXWORKS 1
+-# else
+-# define OS_VXWORKS 0
+-# endif
++SQLITE_API char *sqlite3_mprintf(const char *zFormat, ...){
++ va_list ap;
++ char *z;
++#ifndef SQLITE_OMIT_AUTOINIT
++ if( sqlite3_initialize() ) return 0;
+ #endif
++ va_start(ap, zFormat);
++ z = sqlite3_vmprintf(zFormat, ap);
++ va_end(ap);
++ return z;
++}
+
+ /*
+-** These #defines should enable >2GB file support on Posix if the
+-** underlying operating system supports it. If the OS lacks
+-** large file support, these should be no-ops.
++** sqlite3_snprintf() works like snprintf() except that it ignores the
++** current locale settings. This is important for SQLite because we
++** are not able to use a "," as the decimal point in place of "." as
++** specified by some locales.
+ **
+-** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch
+-** on the compiler command line. This is necessary if you are compiling
+-** on a recent machine (ex: RedHat 7.2) but you want your code to work
+-** on an older machine (ex: RedHat 6.0). If you compile on RedHat 7.2
+-** without this option, LFS is enable. But LFS does not exist in the kernel
+-** in RedHat 6.0, so the code won't work. Hence, for maximum binary
+-** portability you should omit LFS.
++** Oops: The first two arguments of sqlite3_snprintf() are backwards
++** from the snprintf() standard. Unfortunately, it is too late to change
++** this without breaking compatibility, so we just have to live with the
++** mistake.
+ **
+-** The previous paragraph was written in 2005. (This paragraph is written
+-** on 2008-11-28.) These days, all Linux kernels support large files, so
+-** you should probably leave LFS enabled. But some embedded platforms might
+-** lack LFS in which case the SQLITE_DISABLE_LFS macro might still be useful.
++** sqlite3_vsnprintf() is the varargs version.
+ */
+-#ifndef SQLITE_DISABLE_LFS
+-# define _LARGE_FILE 1
+-# ifndef _FILE_OFFSET_BITS
+-# define _FILE_OFFSET_BITS 64
+-# endif
+-# define _LARGEFILE_SOURCE 1
+-#endif
++SQLITE_API char *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;
++ sqlite3VXPrintf(&acc, 0, zFormat, ap);
++ return sqlite3StrAccumFinish(&acc);
++}
++SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
++ char *z;
++ va_list ap;
++ va_start(ap,zFormat);
++ z = sqlite3_vsnprintf(n, zBuf, zFormat, ap);
++ va_end(ap);
++ return z;
++}
+
+ /*
+-** standard include files.
++** This is the routine that actually formats the sqlite3_log() message.
++** We house it in a separate routine from sqlite3_log() to avoid using
++** stack space on small-stack systems when logging is disabled.
++**
++** sqlite3_log() must render into a static buffer. It cannot dynamically
++** allocate memory because it might be called while the memory allocator
++** mutex is held.
+ */
+-#include <sys/types.h>
+-#include <sys/stat.h>
+-#include <fcntl.h>
+-#include <unistd.h>
+-/* #include <time.h> */
+-#include <sys/time.h>
+-#include <errno.h>
+-#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
-#include <sys/mman.h>
+-#endif
+-
+-
+-#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
+-#endif /* SQLITE_ENABLE_LOCKING_STYLE */
+-
+-#if defined(__APPLE__) || (SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS)
+-# include <sys/mount.h>
+-#endif
++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 */
+
+-#ifdef HAVE_UTIME
+-# include <utime.h>
+-#endif
++ sqlite3StrAccumInit(&acc, zMsg, sizeof(zMsg), 0);
++ acc.useMalloc = 0;
++ sqlite3VXPrintf(&acc, 0, zFormat, ap);
++ sqlite3GlobalConfig.xLog(sqlite3GlobalConfig.pLogArg, iErrCode,
++ sqlite3StrAccumFinish(&acc));
++}
+
+ /*
+-** Allowed values of unixFile.fsFlags
++** Format and write a message to the log if logging is enabled.
+ */
+-#define SQLITE_FSFLAGS_IS_MSDOS 0x1
++SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...){
++ va_list ap; /* Vararg list */
++ if( sqlite3GlobalConfig.xLog ){
++ va_start(ap, zFormat);
++ renderLogMsg(iErrCode, zFormat, ap);
++ va_end(ap);
++ }
++}
+
++#if defined(SQLITE_DEBUG)
+ /*
+-** If we are to be thread-safe, include the pthreads header and define
+-** the SQLITE_UNIX_THREADS macro.
++** A version of printf() that understands %lld. Used for debugging.
++** The printf() built into some versions of windows does not understand %lld
++** and segfaults if you give it a long long int.
+ */
+-#if SQLITE_THREADSAFE
+-/* # include <pthread.h> */
+-# define SQLITE_UNIX_THREADS 1
++SQLITE_PRIVATE void sqlite3DebugPrintf(const char *zFormat, ...){
++ va_list ap;
++ StrAccum acc;
++ char zBuf[500];
++ sqlite3StrAccumInit(&acc, zBuf, sizeof(zBuf), 0);
++ acc.useMalloc = 0;
++ va_start(ap,zFormat);
++ sqlite3VXPrintf(&acc, 0, zFormat, ap);
++ va_end(ap);
++ sqlite3StrAccumFinish(&acc);
++ fprintf(stdout,"%s", zBuf);
++ fflush(stdout);
++}
+ #endif
+
++#ifndef SQLITE_OMIT_TRACE
+ /*
+-** Default permissions when creating a new file
++** variable-argument wrapper around sqlite3VXPrintf().
+ */
+-#ifndef SQLITE_DEFAULT_FILE_PERMISSIONS
+-# define SQLITE_DEFAULT_FILE_PERMISSIONS 0644
++SQLITE_PRIVATE void sqlite3XPrintf(StrAccum *p, const char *zFormat, ...){
++ va_list ap;
++ va_start(ap,zFormat);
++ sqlite3VXPrintf(p, 1, zFormat, ap);
++ va_end(ap);
++}
+ #endif
+
++/************** End of printf.c **********************************************/
++/************** Begin file random.c ******************************************/
+ /*
+-** Default permissions when creating auto proxy dir
++** 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 file contains code to implement a pseudo-random number
++** generator (PRNG) for SQLite.
++**
++** Random numbers are used by some of the database backends in order
++** to generate random integer keys for tables or random filenames.
+ */
+-#ifndef SQLITE_DEFAULT_PROXYDIR_PERMISSIONS
+-# define SQLITE_DEFAULT_PROXYDIR_PERMISSIONS 0755
+-#endif
+
+-/*
+-** Maximum supported path-length.
+-*/
+-#define MAX_PATHNAME 512
+
+-/*
+-** 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
++/* All threads share a single random number generator.
++** This structure is the current state of the generator.
+ */
+-#define IS_LOCK_ERROR(x) ((x != SQLITE_OK) && (x != SQLITE_BUSY))
+-
+-/* Forward references */
+-typedef struct unixShm unixShm; /* Connection shared memory */
+-typedef struct unixShmNode unixShmNode; /* Shared memory instance */
+-typedef struct unixInodeInfo unixInodeInfo; /* An i-node */
+-typedef struct UnixUnusedFd UnixUnusedFd; /* An unused file descriptor */
++static SQLITE_WSD struct sqlite3PrngType {
++ unsigned char isInit; /* True if initialized */
++ unsigned char i, j; /* State variables */
++ unsigned char s[256]; /* State variables */
++} sqlite3Prng;
+
+ /*
+-** Sometimes, after a file handle is closed by SQLite, the file descriptor
+-** cannot be closed immediately. In these cases, instances of the following
+-** structure are used to store the file descriptor while waiting for an
+-** opportunity to either close or reuse it.
++** Get a single 8-bit random value from the RC4 PRNG. The Mutex
++** must be held while executing this routine.
++**
++** Why not just use a library random generator like lrand48() for this?
++** Because the OP_NewRowid opcode in the VDBE depends on having a very
++** good source of random numbers. The lrand48() library function may
++** well be good enough. But maybe not. Or maybe lrand48() has some
++** subtle problems on some systems that could cause problems. It is hard
++** to know. To minimize the risk of problems due to bad lrand48()
++** implementations, SQLite uses this random number generator based
++** on RC4, which we know works very well.
++**
++** (Later): Actually, OP_NewRowid does not depend on a good source of
++** randomness any more. But we will leave this code in all the same.
+ */
+-struct UnixUnusedFd {
+- int fd; /* File descriptor to close */
+- int flags; /* Flags this file descriptor was opened with */
+- UnixUnusedFd *pNext; /* Next unused file descriptor on same file */
+-};
++static u8 randomByte(void){
++ unsigned char t;
+
+-/*
+-** The unixFile structure is subclass of sqlite3_file specific to the unix
+-** VFS implementations.
+-*/
+-typedef struct unixFile unixFile;
+-struct unixFile {
+- sqlite3_io_methods const *pMethod; /* Always the first entry */
+- sqlite3_vfs *pVfs; /* The VFS that created this unixFile */
+- unixInodeInfo *pInode; /* Info about locks on this inode */
+- int h; /* The file descriptor */
+- unsigned char eFileLock; /* The type of lock held on this fd */
+- unsigned short int ctrlFlags; /* Behavioral bits. UNIXFILE_* flags */
+- int lastErrno; /* The unix errno from last I/O error */
+- void *lockingContext; /* Locking style specific state */
+- UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */
+- const char *zPath; /* Name of the file */
+- unixShm *pShm; /* Shared memory segment information */
+- int szChunk; /* Configured by FCNTL_CHUNK_SIZE */
+- int nFetchOut; /* Number of outstanding xFetch refs */
+- sqlite3_int64 mmapSize; /* Usable size of mapping at pMapRegion */
+- sqlite3_int64 mmapSizeActual; /* Actual size of mapping at pMapRegion */
+- sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */
+- void *pMapRegion; /* Memory mapped region */
+-#ifdef __QNXNTO__
+- int sectorSize; /* Device sector size */
+- int deviceCharacteristics; /* Precomputed device characteristics */
+-#endif
+-#if SQLITE_ENABLE_LOCKING_STYLE
+- int openFlags; /* The flags specified at open() */
+-#endif
+-#if SQLITE_ENABLE_LOCKING_STYLE || defined(__APPLE__)
+- unsigned fsFlags; /* cached details from statfs() */
+-#endif
+-#if OS_VXWORKS
+- struct vxworksFileId *pId; /* Unique file ID */
+-#endif
+-#ifdef SQLITE_DEBUG
+- /* The next group of variables are used to track whether or not the
+- ** transaction counter in bytes 24-27 of database files are updated
+- ** whenever any part of the database changes. An assertion fault will
+- ** occur if a file is updated without also updating the transaction
+- ** counter. This test is made to avoid new problems similar to the
+- ** one described by ticket #3584.
+- */
+- unsigned char transCntrChng; /* True if the transaction counter changed */
+- unsigned char dbUpdate; /* True if any part of database file changed */
+- unsigned char inNormalWrite; /* True if in a normal write operation */
+
++ /* The "wsdPrng" macro will resolve to the pseudo-random number generator
++ ** 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, wsdPrng can refer directly
++ ** to the "sqlite3Prng" state vector declared above.
++ */
++#ifdef SQLITE_OMIT_WSD
++ struct sqlite3PrngType *p = &GLOBAL(struct sqlite3PrngType, sqlite3Prng);
++# define wsdPrng p[0]
++#else
++# define wsdPrng sqlite3Prng
+ #endif
+
+-#ifdef SQLITE_TEST
+- /* In test mode, increase the size of this structure a bit so that
+- ** it is larger than the struct CrashFile defined in test6.c.
++
++ /* Initialize the state of the random number generator once,
++ ** the first time this routine is called. The seed value does
++ ** not need to contain a lot of randomness since we are not
++ ** trying to do secure encryption or anything like that...
++ **
++ ** Nothing in this file or anywhere else in SQLite does any kind of
++ ** encryption. The RC4 algorithm is being used as a PRNG (pseudo-random
++ ** number generator) not as an encryption device.
+ */
+- char aPadding[32];
+-#endif
+-};
++ if( !wsdPrng.isInit ){
++ int i;
++ char k[256];
++ wsdPrng.j = 0;
++ wsdPrng.i = 0;
++ sqlite3OsRandomness(sqlite3_vfs_find(0), 256, k);
++ for(i=0; i<256; i++){
++ wsdPrng.s[i] = (u8)i;
++ }
++ for(i=0; i<256; i++){
++ wsdPrng.j += wsdPrng.s[i] + k[i];
++ t = wsdPrng.s[wsdPrng.j];
++ wsdPrng.s[wsdPrng.j] = wsdPrng.s[i];
++ wsdPrng.s[i] = t;
++ }
++ wsdPrng.isInit = 1;
++ }
++
++ /* Generate and return single random byte
++ */
++ wsdPrng.i++;
++ t = wsdPrng.s[wsdPrng.i];
++ wsdPrng.j += t;
++ wsdPrng.s[wsdPrng.i] = wsdPrng.s[wsdPrng.j];
++ wsdPrng.s[wsdPrng.j] = t;
++ t += wsdPrng.s[wsdPrng.i];
++ return wsdPrng.s[t];
++}
+
+ /*
+-** Allowed values for the unixFile.ctrlFlags bitmask:
++** Return N random bytes.
+ */
+-#define UNIXFILE_EXCL 0x01 /* Connections from one process only */
+-#define UNIXFILE_RDONLY 0x02 /* Connection is read only */
+-#define UNIXFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */
+-#ifndef SQLITE_DISABLE_DIRSYNC
+-# define UNIXFILE_DIRSYNC 0x08 /* Directory sync needed */
+-#else
+-# define UNIXFILE_DIRSYNC 0x00
++SQLITE_API void sqlite3_randomness(int N, void *pBuf){
++ unsigned char *zBuf = pBuf;
++#if SQLITE_THREADSAFE
++ sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PRNG);
+ #endif
+-#define UNIXFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */
+-#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 */
++ sqlite3_mutex_enter(mutex);
++ while( N-- ){
++ *(zBuf++) = randomByte();
++ }
++ sqlite3_mutex_leave(mutex);
++}
+
++#ifndef SQLITE_OMIT_BUILTIN_TEST
+ /*
+-** Include code that is common to all os_*.c files
++** For testing purposes, we sometimes want to preserve the state of
++** PRNG and restore the PRNG to its saved state at a later time, or
++** to reset the PRNG to its initial state. These routines accomplish
++** those tasks.
++**
++** The sqlite3_test_control() interface calls these routines to
++** control the PRNG.
+ */
+-/************** Include os_common.h in the middle of os_unix.c ***************/
+-/************** Begin file os_common.h ***************************************/
++static SQLITE_WSD struct sqlite3PrngType sqlite3SavedPrng;
++SQLITE_PRIVATE void sqlite3PrngSaveState(void){
++ memcpy(
++ &GLOBAL(struct sqlite3PrngType, sqlite3SavedPrng),
++ &GLOBAL(struct sqlite3PrngType, sqlite3Prng),
++ sizeof(sqlite3Prng)
++ );
++}
++SQLITE_PRIVATE void sqlite3PrngRestoreState(void){
++ memcpy(
++ &GLOBAL(struct sqlite3PrngType, sqlite3Prng),
++ &GLOBAL(struct sqlite3PrngType, sqlite3SavedPrng),
++ sizeof(sqlite3Prng)
++ );
++}
++SQLITE_PRIVATE void sqlite3PrngResetState(void){
++ GLOBAL(struct sqlite3PrngType, sqlite3Prng).isInit = 0;
++}
++#endif /* SQLITE_OMIT_BUILTIN_TEST */
++
++/************** End of random.c **********************************************/
++/************** Begin file utf.c *********************************************/
+ /*
+-** 2004 May 22
++** 2004 April 13
+ **
+ ** The author disclaims copyright to this source code. In place of
+ ** a legal notice, here is a blessing:
+@@ -23182,13485 +23650,14956 @@
+ ** May you find forgiveness for yourself and forgive others.
+ ** May you share freely, never taking more than you give.
+ **
+-******************************************************************************
++*************************************************************************
++** This file contains routines used to translate between UTF-8,
++** UTF-16, UTF-16BE, and UTF-16LE.
+ **
+-** This file contains macros and a little bit of code that is common to
+-** all of the platform-specific files (os_*.c) and is #included into those
+-** files.
++** Notes on UTF-8:
++**
++** Byte-0 Byte-1 Byte-2 Byte-3 Value
++** 0xxxxxxx 00000000 00000000 0xxxxxxx
++** 110yyyyy 10xxxxxx 00000000 00000yyy yyxxxxxx
++** 1110zzzz 10yyyyyy 10xxxxxx 00000000 zzzzyyyy yyxxxxxx
++** 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx 000uuuuu zzzzyyyy yyxxxxxx
++**
++**
++** Notes on UTF-16: (with wwww+1==uuuuu)
++**
++** Word-0 Word-1 Value
++** 110110ww wwzzzzyy 110111yy yyxxxxxx 000uuuuu zzzzyyyy yyxxxxxx
++** zzzzyyyy yyxxxxxx 00000000 zzzzyyyy yyxxxxxx
++**
++**
++** BOM or Byte Order Mark:
++** 0xff 0xfe little-endian utf-16 follows
++** 0xfe 0xff big-endian utf-16 follows
+ **
+-** This file should be #included by the os_*.c files only. It is not a
+-** general purpose header file.
+ */
+-#ifndef _OS_COMMON_H_
+-#define _OS_COMMON_H_
++/* #include <assert.h> */
+
++#ifndef SQLITE_AMALGAMATION
+ /*
+-** At least two bugs have slipped in because we changed the MEMORY_DEBUG
+-** macro to SQLITE_DEBUG and some older makefiles have not yet made the
+-** switch. The following code should catch this problem at compile-time.
++** The following constant value is used by the SQLITE_BIGENDIAN and
++** SQLITE_LITTLEENDIAN macros.
+ */
+-#ifdef MEMORY_DEBUG
+-# 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
++SQLITE_PRIVATE const int sqlite3one = 1;
++#endif /* SQLITE_AMALGAMATION */
+
+ /*
+-** Macros for performance tracing. Normally turned off. Only works
+-** on i486 hardware.
++** This lookup table is used to help decode the first byte of
++** a multi-byte UTF8 character.
+ */
+-#ifdef SQLITE_PERFORMANCE_TRACE
++static const unsigned char sqlite3Utf8Trans1[] = {
++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
++ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
++ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
++ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
++ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
++ 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00,
++};
++
++
++#define WRITE_UTF8(zOut, c) { \
++ if( c<0x00080 ){ \
++ *zOut++ = (u8)(c&0xFF); \
++ } \
++ else if( c<0x00800 ){ \
++ *zOut++ = 0xC0 + (u8)((c>>6)&0x1F); \
++ *zOut++ = 0x80 + (u8)(c & 0x3F); \
++ } \
++ else if( c<0x10000 ){ \
++ *zOut++ = 0xE0 + (u8)((c>>12)&0x0F); \
++ *zOut++ = 0x80 + (u8)((c>>6) & 0x3F); \
++ *zOut++ = 0x80 + (u8)(c & 0x3F); \
++ }else{ \
++ *zOut++ = 0xF0 + (u8)((c>>18) & 0x07); \
++ *zOut++ = 0x80 + (u8)((c>>12) & 0x3F); \
++ *zOut++ = 0x80 + (u8)((c>>6) & 0x3F); \
++ *zOut++ = 0x80 + (u8)(c & 0x3F); \
++ } \
++}
++
++#define WRITE_UTF16LE(zOut, c) { \
++ if( c<=0xFFFF ){ \
++ *zOut++ = (u8)(c&0x00FF); \
++ *zOut++ = (u8)((c>>8)&0x00FF); \
++ }else{ \
++ *zOut++ = (u8)(((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \
++ *zOut++ = (u8)(0x00D8 + (((c-0x10000)>>18)&0x03)); \
++ *zOut++ = (u8)(c&0x00FF); \
++ *zOut++ = (u8)(0x00DC + ((c>>8)&0x03)); \
++ } \
++}
++
++#define WRITE_UTF16BE(zOut, c) { \
++ if( c<=0xFFFF ){ \
++ *zOut++ = (u8)((c>>8)&0x00FF); \
++ *zOut++ = (u8)(c&0x00FF); \
++ }else{ \
++ *zOut++ = (u8)(0x00D8 + (((c-0x10000)>>18)&0x03)); \
++ *zOut++ = (u8)(((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \
++ *zOut++ = (u8)(0x00DC + ((c>>8)&0x03)); \
++ *zOut++ = (u8)(c&0x00FF); \
++ } \
++}
++
++#define READ_UTF16LE(zIn, TERM, c){ \
++ c = (*zIn++); \
++ c += ((*zIn++)<<8); \
++ if( c>=0xD800 && c<0xE000 && TERM ){ \
++ int c2 = (*zIn++); \
++ c2 += ((*zIn++)<<8); \
++ c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \
++ } \
++}
++
++#define READ_UTF16BE(zIn, TERM, c){ \
++ c = ((*zIn++)<<8); \
++ c += (*zIn++); \
++ if( c>=0xD800 && c<0xE000 && TERM ){ \
++ int c2 = ((*zIn++)<<8); \
++ c2 += (*zIn++); \
++ c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \
++ } \
++}
+
+-/*
+-** hwtime.h contains inline assembler code for implementing
+-** high-performance timing routines.
+-*/
+-/************** Include hwtime.h in the middle of os_common.h ****************/
+-/************** Begin file hwtime.h ******************************************/
+ /*
+-** 2008 May 27
++** Translate a single UTF-8 character. Return the unicode value.
+ **
+-** The author disclaims copyright to this source code. In place of
+-** a legal notice, here is a blessing:
++** During translation, assume that the byte that zTerm points
++** is a 0x00.
+ **
+-** 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.
++** Write a pointer to the next unread byte back into *pzNext.
+ **
+-******************************************************************************
++** Notes On Invalid UTF-8:
+ **
+-** This file contains inline asm code for retrieving "high-performance"
+-** counters for x86 class CPUs.
++** * This routine never allows a 7-bit character (0x00 through 0x7f) to
++** be encoded as a multi-byte character. Any multi-byte character that
++** attempts to encode a value between 0x00 and 0x7f is rendered as 0xfffd.
++**
++** * This routine never allows a UTF16 surrogate value to be encoded.
++** If a multi-byte character attempts to encode a value between
++** 0xd800 and 0xe000 then it is rendered as 0xfffd.
++**
++** * Bytes in the range of 0x80 through 0xbf which occur as the first
++** byte of a character are interpreted as single-byte characters
++** and rendered as themselves even though they are technically
++** invalid characters.
++**
++** * This routine accepts an infinite number of different UTF8 encodings
++** for unicode values 0x80 and greater. It do not change over-length
++** encodings to 0xfffd as some systems recommend.
+ */
+-#ifndef _HWTIME_H_
+-#define _HWTIME_H_
++#define READ_UTF8(zIn, zTerm, c) \
++ c = *(zIn++); \
++ if( c>=0xc0 ){ \
++ c = sqlite3Utf8Trans1[c-0xc0]; \
++ while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \
++ c = (c<<6) + (0x3f & *(zIn++)); \
++ } \
++ if( c<0x80 \
++ || (c&0xFFFFF800)==0xD800 \
++ || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \
++ }
++SQLITE_PRIVATE u32 sqlite3Utf8Read(
++ const unsigned char **pz /* Pointer to string from which to read char */
++){
++ unsigned int c;
++
++ /* Same as READ_UTF8() above but without the zTerm parameter.
++ ** For this routine, we assume the UTF8 string is always zero-terminated.
++ */
++ c = *((*pz)++);
++ if( c>=0xc0 ){
++ c = sqlite3Utf8Trans1[c-0xc0];
++ while( (*(*pz) & 0xc0)==0x80 ){
++ c = (c<<6) + (0x3f & *((*pz)++));
++ }
++ if( c<0x80
++ || (c&0xFFFFF800)==0xD800
++ || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; }
++ }
++ return c;
++}
++
++
++
+
+ /*
+-** The following routine only works on pentium-class (or newer) processors.
+-** It uses the RDTSC opcode to read the cycle count value out of the
+-** processor and returns that value. This can be used for high-res
+-** profiling.
++** If the TRANSLATE_TRACE macro is defined, the value of each Mem is
++** printed on stderr on the way into and out of sqlite3VdbeMemTranslate().
++*/
++/* #define TRANSLATE_TRACE 1 */
++
++#ifndef SQLITE_OMIT_UTF16
++/*
++** This routine transforms the internal text encoding used by pMem to
++** desiredEnc. It is an error if the string is already of the desired
++** encoding, or if *pMem does not contain a string value.
+ */
+-#if (defined(__GNUC__) || defined(_MSC_VER)) && \
+- (defined(i386) || defined(__i386__) || defined(_M_IX86))
++SQLITE_PRIVATE 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 */
++ unsigned char *zTerm; /* End of input */
++ unsigned char *z; /* Output iterator */
++ unsigned int c;
+
+- #if defined(__GNUC__)
++ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
++ assert( pMem->flags&MEM_Str );
++ assert( pMem->enc!=desiredEnc );
++ assert( pMem->enc!=0 );
++ assert( pMem->n>=0 );
+
+- __inline__ sqlite_uint64 sqlite3Hwtime(void){
+- unsigned int lo, hi;
+- __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
+- return (sqlite_uint64)hi << 32 | lo;
++#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG)
++ {
++ char zBuf[100];
++ sqlite3VdbeMemPrettyPrint(pMem, zBuf);
++ fprintf(stderr, "INPUT: %s\n", zBuf);
+ }
++#endif
+
+- #elif defined(_MSC_VER)
+-
+- __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){
+- __asm {
+- rdtsc
+- ret ; return value at EDX:EAX
+- }
++ /* If the translation is between UTF-16 little and big endian, then
++ ** all that is required is to swap the byte order. This case is handled
++ ** differently from the others.
++ */
++ if( pMem->enc!=SQLITE_UTF8 && desiredEnc!=SQLITE_UTF8 ){
++ u8 temp;
++ int rc;
++ rc = sqlite3VdbeMemMakeWriteable(pMem);
++ if( rc!=SQLITE_OK ){
++ assert( rc==SQLITE_NOMEM );
++ return SQLITE_NOMEM;
++ }
++ zIn = (u8*)pMem->z;
++ zTerm = &zIn[pMem->n&~1];
++ while( zIn<zTerm ){
++ temp = *zIn;
++ *zIn = *(zIn+1);
++ zIn++;
++ *zIn++ = temp;
++ }
++ pMem->enc = desiredEnc;
++ goto translate_out;
+ }
+
+- #endif
+-
+-#elif (defined(__GNUC__) && defined(__x86_64__))
++ /* Set len to the maximum number of bytes required in the output buffer. */
++ if( desiredEnc==SQLITE_UTF8 ){
++ /* When converting from UTF-16, the maximum growth results from
++ ** translating a 2-byte character to a 4-byte UTF-8 character.
++ ** A single byte is required for the output string
++ ** nul-terminator.
++ */
++ pMem->n &= ~1;
++ len = pMem->n * 2 + 1;
++ }else{
++ /* When converting from UTF-8 to UTF-16 the maximum growth is caused
++ ** when a 1-byte UTF-8 character is translated into a 2-byte UTF-16
++ ** character. Two bytes are required in the output buffer for the
++ ** nul-terminator.
++ */
++ len = pMem->n * 2 + 2;
++ }
+
+- __inline__ sqlite_uint64 sqlite3Hwtime(void){
+- unsigned long val;
+- __asm__ __volatile__ ("rdtsc" : "=A" (val));
+- return val;
++ /* Set zIn to point at the start of the input buffer and zTerm to point 1
++ ** byte past the end.
++ **
++ ** Variable zOut is set to point at the output buffer, space obtained
++ ** from sqlite3_malloc().
++ */
++ zIn = (u8*)pMem->z;
++ zTerm = &zIn[pMem->n];
++ zOut = sqlite3DbMallocRaw(pMem->db, len);
++ if( !zOut ){
++ return SQLITE_NOMEM;
+ }
+-
+-#elif (defined(__GNUC__) && defined(__ppc__))
++ z = zOut;
+
+- __inline__ sqlite_uint64 sqlite3Hwtime(void){
+- unsigned long long retval;
+- unsigned long junk;
+- __asm__ __volatile__ ("\n\
+- 1: mftbu %1\n\
+- mftb %L0\n\
+- mftbu %0\n\
+- cmpw %0,%1\n\
+- bne 1b"
+- : "=r" (retval), "=r" (junk));
+- return retval;
++ if( pMem->enc==SQLITE_UTF8 ){
++ if( desiredEnc==SQLITE_UTF16LE ){
++ /* UTF-8 -> UTF-16 Little-endian */
++ while( zIn<zTerm ){
++ READ_UTF8(zIn, zTerm, c);
++ WRITE_UTF16LE(z, c);
++ }
++ }else{
++ assert( desiredEnc==SQLITE_UTF16BE );
++ /* UTF-8 -> UTF-16 Big-endian */
++ while( zIn<zTerm ){
++ READ_UTF8(zIn, zTerm, c);
++ WRITE_UTF16BE(z, c);
++ }
++ }
++ pMem->n = (int)(z - zOut);
++ *z++ = 0;
++ }else{
++ assert( desiredEnc==SQLITE_UTF8 );
++ if( pMem->enc==SQLITE_UTF16LE ){
++ /* UTF-16 Little-endian -> UTF-8 */
++ while( zIn<zTerm ){
++ READ_UTF16LE(zIn, zIn<zTerm, c);
++ WRITE_UTF8(z, c);
++ }
++ }else{
++ /* UTF-16 Big-endian -> UTF-8 */
++ while( zIn<zTerm ){
++ READ_UTF16BE(zIn, zIn<zTerm, c);
++ WRITE_UTF8(z, c);
++ }
++ }
++ pMem->n = (int)(z - zOut);
+ }
++ *z = 0;
++ assert( (pMem->n+(desiredEnc==SQLITE_UTF8?1:2))<=len );
+
+-#else
++ sqlite3VdbeMemRelease(pMem);
++ pMem->flags &= ~(MEM_Static|MEM_Dyn|MEM_Ephem);
++ pMem->enc = desiredEnc;
++ pMem->flags |= (MEM_Term|MEM_Dyn);
++ pMem->z = (char*)zOut;
++ pMem->zMalloc = pMem->z;
+
+- #error Need implementation of sqlite3Hwtime() for your platform.
++translate_out:
++#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG)
++ {
++ char zBuf[100];
++ sqlite3VdbeMemPrettyPrint(pMem, zBuf);
++ fprintf(stderr, "OUTPUT: %s\n", zBuf);
++ }
++#endif
++ return SQLITE_OK;
++}
+
+- /*
+- ** To compile without implementing sqlite3Hwtime() for your platform,
+- ** you can remove the above #error and use the following
+- ** stub function. You will lose timing support for many
+- ** of the debugging and testing utilities, but it should at
+- ** least compile and run.
+- */
+-SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
++/*
++** This routine checks for a byte-order mark at the beginning of the
++** UTF-16 string stored in *pMem. If one is present, it is removed and
++** the encoding of the Mem adjusted. This routine does not do any
++** byte-swapping, it just sets Mem.enc appropriately.
++**
++** The allocation (static, dynamic etc.) and encoding of the Mem may be
++** changed by this function.
++*/
++SQLITE_PRIVATE int sqlite3VdbeMemHandleBom(Mem *pMem){
++ int rc = SQLITE_OK;
++ u8 bom = 0;
+
+-#endif
++ assert( pMem->n>=0 );
++ if( pMem->n>1 ){
++ u8 b1 = *(u8 *)pMem->z;
++ u8 b2 = *(((u8 *)pMem->z) + 1);
++ if( b1==0xFE && b2==0xFF ){
++ bom = SQLITE_UTF16BE;
++ }
++ if( b1==0xFF && b2==0xFE ){
++ bom = SQLITE_UTF16LE;
++ }
++ }
++
++ if( bom ){
++ rc = sqlite3VdbeMemMakeWriteable(pMem);
++ if( rc==SQLITE_OK ){
++ pMem->n -= 2;
++ memmove(pMem->z, &pMem->z[2], pMem->n);
++ pMem->z[pMem->n] = '\0';
++ pMem->z[pMem->n+1] = '\0';
++ pMem->flags |= MEM_Term;
++ pMem->enc = bom;
++ }
++ }
++ return rc;
++}
++#endif /* SQLITE_OMIT_UTF16 */
+
+-#endif /* !defined(_HWTIME_H_) */
++/*
++** pZ is a UTF-8 encoded unicode string. If nByte is less than zero,
++** return the number of unicode characters in pZ up to (but not including)
++** the first 0x00 byte. If nByte is not less than zero, return the
++** number of unicode characters in the first nByte of pZ (or up to
++** the first 0x00, whichever comes first).
++*/
++SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *zIn, int nByte){
++ int r = 0;
++ const u8 *z = (const u8*)zIn;
++ const u8 *zTerm;
++ if( nByte>=0 ){
++ zTerm = &z[nByte];
++ }else{
++ zTerm = (const u8*)(-1);
++ }
++ assert( z<=zTerm );
++ while( *z!=0 && z<zTerm ){
++ SQLITE_SKIP_UTF8(z);
++ r++;
++ }
++ return r;
++}
+
+-/************** End of hwtime.h **********************************************/
+-/************** Continuing where we left off in os_common.h ******************/
++/* This test function is not currently used by the automated test-suite.
++** Hence it is only available in debug builds.
++*/
++#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
++/*
++** Translate UTF-8 to UTF-8.
++**
++** This has the effect of making sure that the string is well-formed
++** UTF-8. Miscoded characters are removed.
++**
++** The translation is done in-place and aborted if the output
++** overruns the input.
++*/
++SQLITE_PRIVATE int sqlite3Utf8To8(unsigned char *zIn){
++ unsigned char *zOut = zIn;
++ unsigned char *zStart = zIn;
++ u32 c;
+
+-static sqlite_uint64 g_start;
+-static sqlite_uint64 g_elapsed;
+-#define TIMER_START g_start=sqlite3Hwtime()
+-#define TIMER_END g_elapsed=sqlite3Hwtime()-g_start
+-#define TIMER_ELAPSED g_elapsed
+-#else
+-#define TIMER_START
+-#define TIMER_END
+-#define TIMER_ELAPSED ((sqlite_uint64)0)
++ while( zIn[0] && zOut<=zIn ){
++ c = sqlite3Utf8Read((const u8**)&zIn);
++ if( c!=0xfffd ){
++ WRITE_UTF8(zOut, c);
++ }
++ }
++ *zOut = 0;
++ return (int)(zOut - zStart);
++}
+ #endif
+
++#ifndef SQLITE_OMIT_UTF16
+ /*
+-** If we compile with the SQLITE_TEST macro set, then the following block
+-** of code will give us the ability to simulate a disk I/O error. This
+-** is used for testing the I/O recovery logic.
++** Convert a UTF-16 string in the native encoding into a UTF-8 string.
++** Memory to hold the UTF-8 string is obtained from sqlite3_malloc and must
++** be freed by the calling function.
++**
++** NULL is returned if there is an allocation error.
+ */
+-#ifdef SQLITE_TEST
+-SQLITE_API int sqlite3_io_error_hit = 0; /* Total number of I/O Errors */
+-SQLITE_API int sqlite3_io_error_hardhit = 0; /* Number of non-benign errors */
+-SQLITE_API int sqlite3_io_error_pending = 0; /* Count down to first I/O error */
+-SQLITE_API int sqlite3_io_error_persist = 0; /* True if I/O errors persist */
+-SQLITE_API int sqlite3_io_error_benign = 0; /* True if errors are benign */
+-SQLITE_API int sqlite3_diskfull_pending = 0;
+-SQLITE_API int sqlite3_diskfull = 0;
+-#define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X)
+-#define SimulateIOError(CODE) \
+- if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \
+- || sqlite3_io_error_pending-- == 1 ) \
+- { local_ioerr(); CODE; }
+-static void local_ioerr(){
+- IOTRACE(("IOERR\n"));
+- sqlite3_io_error_hit++;
+- if( !sqlite3_io_error_benign ) sqlite3_io_error_hardhit++;
++SQLITE_PRIVATE char *sqlite3Utf16to8(sqlite3 *db, const void *z, int nByte, u8 enc){
++ Mem m;
++ memset(&m, 0, sizeof(m));
++ m.db = db;
++ sqlite3VdbeMemSetStr(&m, z, nByte, enc, SQLITE_STATIC);
++ sqlite3VdbeChangeEncoding(&m, SQLITE_UTF8);
++ if( db->mallocFailed ){
++ sqlite3VdbeMemRelease(&m);
++ m.z = 0;
++ }
++ assert( (m.flags & MEM_Term)!=0 || db->mallocFailed );
++ assert( (m.flags & MEM_Str)!=0 || db->mallocFailed );
++ assert( (m.flags & MEM_Dyn)!=0 || db->mallocFailed );
++ assert( m.z || db->mallocFailed );
++ return m.z;
++}
++
++/*
++** Convert a UTF-8 string to the UTF-16 encoding specified by parameter
++** enc. A pointer to the new string is returned, and the value of *pnOut
++** is set to the length of the returned string in bytes. The call should
++** arrange to call sqlite3DbFree() on the returned pointer when it is
++** no longer required.
++**
++** If a malloc failure occurs, NULL is returned and the db.mallocFailed
++** flag set.
++*/
++#ifdef SQLITE_ENABLE_STAT3
++SQLITE_PRIVATE char *sqlite3Utf8to16(sqlite3 *db, u8 enc, char *z, int n, int *pnOut){
++ Mem m;
++ memset(&m, 0, sizeof(m));
++ m.db = db;
++ sqlite3VdbeMemSetStr(&m, z, n, SQLITE_UTF8, SQLITE_STATIC);
++ if( sqlite3VdbeMemTranslate(&m, enc) ){
++ assert( db->mallocFailed );
++ return 0;
++ }
++ assert( m.z==m.zMalloc );
++ *pnOut = m.n;
++ return m.z;
+ }
+-#define SimulateDiskfullError(CODE) \
+- if( sqlite3_diskfull_pending ){ \
+- if( sqlite3_diskfull_pending == 1 ){ \
+- local_ioerr(); \
+- sqlite3_diskfull = 1; \
+- sqlite3_io_error_hit = 1; \
+- CODE; \
+- }else{ \
+- sqlite3_diskfull_pending--; \
+- } \
+- }
+-#else
+-#define SimulateIOErrorBenign(X)
+-#define SimulateIOError(A)
+-#define SimulateDiskfullError(A)
+ #endif
+
+ /*
+-** When testing, keep a count of the number of open files.
++** zIn is a UTF-16 encoded unicode string at least nChar characters long.
++** Return the number of bytes in the first nChar unicode characters
++** in pZ. nChar must be non-negative.
++*/
++SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *zIn, int nChar){
++ int c;
++ unsigned char const *z = zIn;
++ int n = 0;
++
++ if( SQLITE_UTF16NATIVE==SQLITE_UTF16BE ){
++ while( n<nChar ){
++ READ_UTF16BE(z, 1, c);
++ n++;
++ }
++ }else{
++ while( n<nChar ){
++ READ_UTF16LE(z, 1, c);
++ n++;
++ }
++ }
++ return (int)(z-(unsigned char const *)zIn);
++}
++
++#if defined(SQLITE_TEST)
++/*
++** This routine is called from the TCL test function "translate_selftest".
++** It checks that the primitives for serializing and deserializing
++** characters in each encoding are inverses of each other.
++*/
++SQLITE_PRIVATE void sqlite3UtfSelfTest(void){
++ unsigned int i, t;
++ unsigned char zBuf[20];
++ unsigned char *z;
++ int n;
++ unsigned int c;
++
++ for(i=0; i<0x00110000; i++){
++ z = zBuf;
++ WRITE_UTF8(z, i);
++ n = (int)(z-zBuf);
++ assert( n>0 && n<=4 );
++ z[0] = 0;
++ z = zBuf;
++ c = sqlite3Utf8Read((const u8**)&z);
++ t = i;
++ if( i>=0xD800 && i<=0xDFFF ) t = 0xFFFD;
++ if( (i&0xFFFFFFFE)==0xFFFE ) t = 0xFFFD;
++ assert( c==t );
++ assert( (z-zBuf)==n );
++ }
++ for(i=0; i<0x00110000; i++){
++ if( i>=0xD800 && i<0xE000 ) continue;
++ z = zBuf;
++ WRITE_UTF16LE(z, i);
++ n = (int)(z-zBuf);
++ assert( n>0 && n<=4 );
++ z[0] = 0;
++ z = zBuf;
++ READ_UTF16LE(z, 1, c);
++ assert( c==i );
++ assert( (z-zBuf)==n );
++ }
++ for(i=0; i<0x00110000; i++){
++ if( i>=0xD800 && i<0xE000 ) continue;
++ z = zBuf;
++ WRITE_UTF16BE(z, i);
++ n = (int)(z-zBuf);
++ assert( n>0 && n<=4 );
++ z[0] = 0;
++ z = zBuf;
++ READ_UTF16BE(z, 1, c);
++ assert( c==i );
++ assert( (z-zBuf)==n );
++ }
++}
++#endif /* SQLITE_TEST */
++#endif /* SQLITE_OMIT_UTF16 */
++
++/************** End of utf.c *************************************************/
++/************** Begin file util.c ********************************************/
++/*
++** 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.
++**
++*************************************************************************
++** Utility functions used throughout sqlite.
++**
++** This file contains functions for allocating memory, comparing
++** strings, and stuff like that.
++**
+ */
+-#ifdef SQLITE_TEST
+-SQLITE_API int sqlite3_open_file_count = 0;
+-#define OpenCounter(X) sqlite3_open_file_count+=(X)
+-#else
+-#define OpenCounter(X)
++/* #include <stdarg.h> */
++#ifdef SQLITE_HAVE_ISNAN
++# include <math.h>
+ #endif
+
+-#endif /* !defined(_OS_COMMON_H_) */
+-
+-/************** End of os_common.h *******************************************/
+-/************** Continuing where we left off in os_unix.c ********************/
+-
+ /*
+-** Define various macros that are missing from some systems.
++** Routine needed to support the testcase() macro.
+ */
+-#ifndef O_LARGEFILE
+-# define O_LARGEFILE 0
+-#endif
+-#ifdef SQLITE_DISABLE_LFS
+-# undef O_LARGEFILE
+-# define O_LARGEFILE 0
+-#endif
+-#ifndef O_NOFOLLOW
+-# define O_NOFOLLOW 0
+-#endif
+-#ifndef O_BINARY
+-# define O_BINARY 0
++#ifdef SQLITE_COVERAGE_TEST
++SQLITE_PRIVATE void sqlite3Coverage(int x){
++ static unsigned dummy = 0;
++ dummy += (unsigned)x;
++}
+ #endif
+
++#ifndef SQLITE_OMIT_FLOATING_POINT
+ /*
+-** The threadid macro resolves to the thread-id or to 0. Used for
+-** testing and debugging only.
++** Return true if the floating point value is Not a Number (NaN).
++**
++** Use the math library isnan() function if compiled with SQLITE_HAVE_ISNAN.
++** Otherwise, we have our own implementation that works on most systems.
+ */
+-#if SQLITE_THREADSAFE
+-#define threadid pthread_self()
+-#else
+-#define threadid 0
++SQLITE_PRIVATE int sqlite3IsNaN(double x){
++ int rc; /* The value return */
++#if !defined(SQLITE_HAVE_ISNAN)
++ /*
++ ** Systems that support the isnan() library function should probably
++ ** make use of it by compiling with -DSQLITE_HAVE_ISNAN. But we have
++ ** found that many systems do not have a working isnan() function so
++ ** this implementation is provided as an alternative.
++ **
++ ** This NaN test sometimes fails if compiled on GCC with -ffast-math.
++ ** On the other hand, the use of -ffast-math comes with the following
++ ** warning:
++ **
++ ** This option [-ffast-math] should never be turned on by any
++ ** -O option since it can result in incorrect output for programs
++ ** which depend on an exact implementation of IEEE or ISO
++ ** rules/specifications for math functions.
++ **
++ ** Under MSVC, this NaN test may fail if compiled with a floating-
++ ** point precision mode other than /fp:precise. From the MSDN
++ ** documentation:
++ **
++ ** The compiler [with /fp:precise] will properly handle comparisons
++ ** involving NaN. For example, x != x evaluates to true if x is NaN
++ ** ...
++ */
++#ifdef __FAST_MATH__
++# error SQLite will not work correctly with the -ffast-math option of GCC.
+ #endif
++ volatile double y = x;
++ volatile double z = y;
++ rc = (y!=z);
++#else /* if defined(SQLITE_HAVE_ISNAN) */
++ rc = isnan(x);
++#endif /* SQLITE_HAVE_ISNAN */
++ testcase( rc );
++ return rc;
++}
++#endif /* SQLITE_OMIT_FLOATING_POINT */
+
+ /*
+-** HAVE_MREMAP defaults to true on Linux and false everywhere else.
++** Compute a string length that is limited to what can be stored in
++** lower 30 bits of a 32-bit signed integer.
++**
++** The value returned will never be negative. Nor will it ever be greater
++** than the actual length of the string. For very long strings (greater
++** than 1GiB) the value returned might be less than the true string length.
+ */
+-#if !defined(HAVE_MREMAP)
+-# if defined(__linux__) && defined(_GNU_SOURCE)
+-# define HAVE_MREMAP 1
+-# else
+-# define HAVE_MREMAP 0
+-# endif
+-#endif
++SQLITE_PRIVATE int sqlite3Strlen30(const char *z){
++ const char *z2 = z;
++ if( z==0 ) return 0;
++ while( *z2 ){ z2++; }
++ return 0x3fffffff & (int)(z2 - z);
++}
+
+ /*
+-** 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.
++** Set the most recent error code and error string for the sqlite
++** handle "db". The error code is set to "err_code".
+ **
+-** The safest way to deal with the problem is to always use this wrapper
+-** which always has the same well-defined interface.
++** If it is not NULL, string zFormat specifies the format of the
++** error string in the style of the printf functions: The following
++** format characters are allowed:
++**
++** %s Insert a string
++** %z A string that should be freed after use
++** %d Insert an integer
++** %T Insert a token
++** %S Insert the first element of a SrcList
++**
++** zFormat and any string tokens that follow it are assumed to be
++** encoded in UTF-8.
++**
++** To clear the most recent error for sqlite handle "db", sqlite3Error
++** should be called with err_code set to SQLITE_OK and zFormat set
++** to NULL.
+ */
+-static int posixOpen(const char *zFile, int flags, int mode){
+- return open(zFile, flags, mode);
++SQLITE_PRIVATE void sqlite3Error(sqlite3 *db, int err_code, const char *zFormat, ...){
++ if( db && (db->pErr || (db->pErr = sqlite3ValueNew(db))!=0) ){
++ db->errCode = err_code;
++ if( zFormat ){
++ 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{
++ sqlite3ValueSetStr(db->pErr, 0, 0, SQLITE_UTF8, SQLITE_STATIC);
++ }
++ }
+ }
+
+ /*
+-** On some systems, calls to fchown() will trigger a message in a security
+-** log if they come from non-root processes. So avoid calling fchown() if
+-** we are not running as root.
++** Add an error message to pParse->zErrMsg and increment pParse->nErr.
++** The following formatting characters are allowed:
++**
++** %s Insert a string
++** %z A string that should be freed after use
++** %d Insert an integer
++** %T Insert a token
++** %S Insert the first element of a SrcList
++**
++** This function should be used to report any error that occurs whilst
++** 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.).
+ */
+-static int posixFchown(int fd, uid_t uid, gid_t gid){
+- return geteuid() ? 0 : fchown(fd,uid,gid);
++SQLITE_PRIVATE void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
++ char *zMsg;
++ va_list ap;
++ sqlite3 *db = pParse->db;
++ va_start(ap, zFormat);
++ zMsg = sqlite3VMPrintf(db, zFormat, ap);
++ va_end(ap);
++ if( db->suppressErr ){
++ sqlite3DbFree(db, zMsg);
++ }else{
++ pParse->nErr++;
++ sqlite3DbFree(db, pParse->zErrMsg);
++ pParse->zErrMsg = zMsg;
++ pParse->rc = SQLITE_ERROR;
++ }
+ }
+
+-/* Forward reference */
+-static int openDirectory(const char*, int*);
+-
+ /*
+-** Many system calls are accessed through pointer-to-functions so that
+-** they may be overridden at runtime to facilitate fault injection during
+-** testing and sandboxing. The following array holds the names and pointers
+-** to all overrideable system calls.
++** Convert an SQL-style quoted string into a normal string by removing
++** the quote characters. The conversion is done in-place. If the
++** input does not begin with a quote character, then this routine
++** is a no-op.
++**
++** The input string must be zero-terminated. A new zero-terminator
++** is added to the dequoted string.
++**
++** The return value is -1 if no dequoting occurs or the length of the
++** dequoted string, exclusive of the zero terminator, if dequoting does
++** occur.
++**
++** 2002-Feb-14: This routine is extended to remove MS-Access style
++** brackets from around identifers. For example: "[a-b-c]" becomes
++** "a-b-c".
+ */
+-static struct unix_syscall {
+- const char *zName; /* Name of the system call */
+- sqlite3_syscall_ptr pCurrent; /* Current value of the system call */
+- sqlite3_syscall_ptr pDefault; /* Default value */
+-} aSyscall[] = {
+- { "open", (sqlite3_syscall_ptr)posixOpen, 0 },
+-#define osOpen ((int(*)(const char*,int,int))aSyscall[0].pCurrent)
+-
+- { "close", (sqlite3_syscall_ptr)close, 0 },
+-#define osClose ((int(*)(int))aSyscall[1].pCurrent)
+-
+- { "access", (sqlite3_syscall_ptr)access, 0 },
+-#define osAccess ((int(*)(const char*,int))aSyscall[2].pCurrent)
+-
+- { "getcwd", (sqlite3_syscall_ptr)getcwd, 0 },
+-#define osGetcwd ((char*(*)(char*,size_t))aSyscall[3].pCurrent)
++SQLITE_PRIVATE int sqlite3Dequote(char *z){
++ char quote;
++ int i, j;
++ if( z==0 ) return -1;
++ quote = z[0];
++ switch( quote ){
++ case '\'': break;
++ case '"': break;
++ case '`': break; /* For MySQL compatibility */
++ case '[': quote = ']'; break; /* For MS SqlServer compatibility */
++ default: return -1;
++ }
++ for(i=1, j=0; ALWAYS(z[i]); i++){
++ if( z[i]==quote ){
++ if( z[i+1]==quote ){
++ z[j++] = quote;
++ i++;
++ }else{
++ break;
++ }
++ }else{
++ z[j++] = z[i];
++ }
++ }
++ z[j] = 0;
++ return j;
++}
+
+- { "stat", (sqlite3_syscall_ptr)stat, 0 },
+-#define osStat ((int(*)(const char*,struct stat*))aSyscall[4].pCurrent)
++/* Convenient short-hand */
++#define UpperToLower sqlite3UpperToLower
+
+ /*
+-** The DJGPP compiler environment looks mostly like Unix, but it
+-** lacks the fcntl() system call. So redefine fcntl() to be something
+-** that always succeeds. This means that locking does not occur under
+-** DJGPP. But it is DOS - what did you expect?
++** Some systems have stricmp(). Others have strcasecmp(). Because
++** there is no consistency, we will define our own.
++**
++** IMPLEMENTATION-OF: R-30243-02494 The sqlite3_stricmp() and
++** sqlite3_strnicmp() APIs allow applications and extensions to compare
++** the contents of two buffers containing UTF-8 strings in a
++** case-independent fashion, using the same definition of "case
++** independence" that SQLite uses internally when comparing identifiers.
+ */
+-#ifdef __DJGPP__
+- { "fstat", 0, 0 },
+-#define osFstat(a,b,c) 0
+-#else
+- { "fstat", (sqlite3_syscall_ptr)fstat, 0 },
+-#define osFstat ((int(*)(int,struct stat*))aSyscall[5].pCurrent)
+-#endif
+-
+- { "ftruncate", (sqlite3_syscall_ptr)ftruncate, 0 },
+-#define osFtruncate ((int(*)(int,off_t))aSyscall[6].pCurrent)
+-
+- { "fcntl", (sqlite3_syscall_ptr)fcntl, 0 },
+-#define osFcntl ((int(*)(int,int,...))aSyscall[7].pCurrent)
+-
+- { "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
+- { "pread", (sqlite3_syscall_ptr)pread, 0 },
+-#else
+- { "pread", (sqlite3_syscall_ptr)0, 0 },
+-#endif
+-#define osPread ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[9].pCurrent)
+-
+-#if defined(USE_PREAD64)
+- { "pread64", (sqlite3_syscall_ptr)pread64, 0 },
+-#else
+- { "pread64", (sqlite3_syscall_ptr)0, 0 },
+-#endif
+-#define osPread64 ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].pCurrent)
+-
+- { "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
+- { "pwrite", (sqlite3_syscall_ptr)pwrite, 0 },
+-#else
+- { "pwrite", (sqlite3_syscall_ptr)0, 0 },
+-#endif
+-#define osPwrite ((ssize_t(*)(int,const void*,size_t,off_t))\
+- aSyscall[12].pCurrent)
+-
+-#if defined(USE_PREAD64)
+- { "pwrite64", (sqlite3_syscall_ptr)pwrite64, 0 },
+-#else
+- { "pwrite64", (sqlite3_syscall_ptr)0, 0 },
+-#endif
+-#define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\
+- aSyscall[13].pCurrent)
+-
+- { "fchmod", (sqlite3_syscall_ptr)fchmod, 0 },
+-#define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent)
+-
+-#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
+- { "fallocate", (sqlite3_syscall_ptr)posix_fallocate, 0 },
+-#else
+- { "fallocate", (sqlite3_syscall_ptr)0, 0 },
+-#endif
+-#define osFallocate ((int(*)(int,off_t,off_t))aSyscall[15].pCurrent)
+-
+- { "unlink", (sqlite3_syscall_ptr)unlink, 0 },
+-#define osUnlink ((int(*)(const char*))aSyscall[16].pCurrent)
+-
+- { "openDirectory", (sqlite3_syscall_ptr)openDirectory, 0 },
+-#define osOpenDirectory ((int(*)(const char*,int*))aSyscall[17].pCurrent)
++SQLITE_API int sqlite3_stricmp(const char *zLeft, const char *zRight){
++ register unsigned char *a, *b;
++ 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){
++ register unsigned char *a, *b;
++ a = (unsigned char *)zLeft;
++ b = (unsigned char *)zRight;
++ while( N-- > 0 && *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }
++ return N<0 ? 0 : UpperToLower[*a] - UpperToLower[*b];
++}
+
+- { "mkdir", (sqlite3_syscall_ptr)mkdir, 0 },
+-#define osMkdir ((int(*)(const char*,mode_t))aSyscall[18].pCurrent)
++/*
++** The string z[] is an text representation of a real number.
++** Convert this string to a double and write it into *pResult.
++**
++** The string z[] is length bytes in length (bytes, not characters) and
++** uses the encoding enc. The string is not necessarily zero-terminated.
++**
++** Return TRUE if the result is a valid real number (or integer) and FALSE
++** if the string is empty or contains extraneous text. Valid numbers
++** are in one of these formats:
++**
++** [+-]digits[E[+-]digits]
++** [+-]digits.[digits][E[+-]digits]
++** [+-].digits[E[+-]digits]
++**
++** Leading and trailing whitespace is ignored for the purpose of determining
++** validity.
++**
++** If some prefix of the input string is a valid number, this routine
++** returns FALSE but it still converts the prefix and writes the result
++** into *pResult.
++*/
++SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){
++#ifndef SQLITE_OMIT_FLOATING_POINT
++ int incr;
++ const char *zEnd = z + length;
++ /* sign * significand * (10 ^ (esign * exponent)) */
++ int sign = 1; /* sign of significand */
++ i64 s = 0; /* significand */
++ int d = 0; /* adjust exponent for shifting decimal point */
++ int esign = 1; /* sign of exponent */
++ int e = 0; /* exponent */
++ int eValid = 1; /* True exponent is either not used or is well-formed */
++ double result;
++ int nDigits = 0;
++ int nonNum = 0;
+
+- { "rmdir", (sqlite3_syscall_ptr)rmdir, 0 },
+-#define osRmdir ((int(*)(const char*))aSyscall[19].pCurrent)
++ assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
++ *pResult = 0.0; /* Default return value, in case of an error */
+
+- { "fchown", (sqlite3_syscall_ptr)posixFchown, 0 },
+-#define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent)
++ if( enc==SQLITE_UTF8 ){
++ incr = 1;
++ }else{
++ int i;
++ incr = 2;
++ assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
++ for(i=3-enc; i<length && z[i]==0; i+=2){}
++ nonNum = i<length;
++ zEnd = z+i+enc-3;
++ z += (enc&1);
++ }
+
+- { "mmap", (sqlite3_syscall_ptr)mmap, 0 },
+-#define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[21].pCurrent)
++ /* skip leading spaces */
++ while( z<zEnd && sqlite3Isspace(*z) ) z+=incr;
++ if( z>=zEnd ) return 0;
+
+- { "munmap", (sqlite3_syscall_ptr)munmap, 0 },
+-#define osMunmap ((void*(*)(void*,size_t))aSyscall[22].pCurrent)
++ /* get sign of significand */
++ if( *z=='-' ){
++ sign = -1;
++ z+=incr;
++ }else if( *z=='+' ){
++ z+=incr;
++ }
+
+-#if HAVE_MREMAP
+- { "mremap", (sqlite3_syscall_ptr)mremap, 0 },
+-#else
+- { "mremap", (sqlite3_syscall_ptr)0, 0 },
+-#endif
+-#define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[23].pCurrent)
++ /* skip leading zeroes */
++ while( z<zEnd && z[0]=='0' ) z+=incr, nDigits++;
+
+-}; /* End of the overrideable system calls */
++ /* copy max significant digits to significand */
++ while( z<zEnd && sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){
++ s = s*10 + (*z - '0');
++ z+=incr, nDigits++;
++ }
+
+-/*
+-** This is the xSetSystemCall() method of sqlite3_vfs for all of the
+-** "unix" 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 unixSetSystemCall(
+- 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;
++ /* skip non-significant significand digits
++ ** (increase exponent by d to shift decimal left) */
++ while( z<zEnd && sqlite3Isdigit(*z) ) z+=incr, nDigits++, d++;
++ if( z>=zEnd ) goto do_atof_calc;
+
+- 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 decimal point is present */
++ if( *z=='.' ){
++ z+=incr;
++ /* copy digits from after decimal to significand
++ ** (decrease exponent by d to shift decimal right) */
++ while( z<zEnd && sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){
++ s = s*10 + (*z - '0');
++ z+=incr, nDigits++, d--;
+ }
+- }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;
+- }
++ /* skip non-significant digits */
++ while( z<zEnd && sqlite3Isdigit(*z) ) z+=incr, nDigits++;
++ }
++ if( z>=zEnd ) goto do_atof_calc;
++
++ /* if exponent is present */
++ if( *z=='e' || *z=='E' ){
++ z+=incr;
++ eValid = 0;
++ if( z>=zEnd ) goto do_atof_calc;
++ /* get sign of exponent */
++ if( *z=='-' ){
++ esign = -1;
++ z+=incr;
++ }else if( *z=='+' ){
++ z+=incr;
++ }
++ /* copy digits to exponent */
++ while( z<zEnd && sqlite3Isdigit(*z) ){
++ e = e<10000 ? (e*10 + (*z - '0')) : 10000;
++ z+=incr;
++ eValid = 1;
+ }
+ }
+- return rc;
+-}
+-
+-/*
+-** 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 unixGetSystemCall(
+- sqlite3_vfs *pNotUsed,
+- const char *zName
+-){
+- unsigned int i;
+
+- UNUSED_PARAMETER(pNotUsed);
+- for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
+- if( strcmp(zName, aSyscall[i].zName)==0 ) return aSyscall[i].pCurrent;
++ /* skip trailing spaces */
++ if( nDigits && eValid ){
++ while( z<zEnd && sqlite3Isspace(*z) ) z+=incr;
+ }
+- return 0;
+-}
+
+-/*
+-** 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 *unixNextSystemCall(sqlite3_vfs *p, const char *zName){
+- int i = -1;
++do_atof_calc:
++ /* adjust exponent by d, and update sign */
++ e = (e*esign) + d;
++ if( e<0 ) {
++ esign = -1;
++ e *= -1;
++ } else {
++ esign = 1;
++ }
+
+- UNUSED_PARAMETER(p);
+- if( zName ){
+- for(i=0; i<ArraySize(aSyscall)-1; i++){
+- if( strcmp(zName, aSyscall[i].zName)==0 ) break;
++ /* if 0 significand */
++ if( !s ) {
++ /* In the IEEE 754 standard, zero is signed.
++ ** Add the sign if we've seen at least one digit */
++ result = (sign<0 && nDigits) ? -(double)0 : (double)0;
++ } else {
++ /* attempt to reduce exponent */
++ if( esign>0 ){
++ while( s<(LARGEST_INT64/10) && e>0 ) e--,s*=10;
++ }else{
++ while( !(s%10) && e>0 ) e--,s/=10;
+ }
+- }
+- for(i++; i<ArraySize(aSyscall); i++){
+- if( aSyscall[i].pCurrent!=0 ) return aSyscall[i].zName;
+- }
+- return 0;
+-}
+
+-/*
+-** Invoke open(). Do so multiple times, until it either succeeds or
+-** fails for some reason other than EINTR.
+-**
+-** If the file creation mode "m" is 0 then set it to the default for
+-** SQLite. The default is SQLITE_DEFAULT_FILE_PERMISSIONS (normally
+-** 0644) as modified by the system umask. If m is not 0, then
+-** make the file creation mode be exactly m ignoring the umask.
+-**
+-** The m parameter will be non-zero only when creating -wal, -journal,
+-** and -shm files. We want those files to have *exactly* the same
+-** permissions as their original database, unadulterated by the umask.
+-** In that way, if a database file is -rw-rw-rw or -rw-rw-r-, and a
+-** transaction crashes and leaves behind hot journals, then any
+-** process that is able to write to the database will also be able to
+-** recover the hot journals.
+-*/
+-static int robust_open(const char *z, int f, mode_t m){
+- int fd;
+- mode_t m2 = m ? m : SQLITE_DEFAULT_FILE_PERMISSIONS;
+- do{
+-#if defined(O_CLOEXEC)
+- fd = osOpen(z,f|O_CLOEXEC,m2);
+-#else
+- fd = osOpen(z,f,m2);
+-#endif
+- }while( fd<0 && errno==EINTR );
+- if( fd>=0 ){
+- if( m!=0 ){
+- struct stat statbuf;
+- if( osFstat(fd, &statbuf)==0
+- && statbuf.st_size==0
+- && (statbuf.st_mode&0777)!=m
+- ){
+- osFchmod(fd, m);
++ /* adjust the sign of significand */
++ s = sign<0 ? -s : s;
++
++ /* if exponent, scale significand as appropriate
++ ** and store in result. */
++ if( e ){
++ LONGDOUBLE_TYPE scale = 1.0;
++ /* attempt to handle extremely small/large numbers better */
++ if( e>307 && e<342 ){
++ while( e%308 ) { scale *= 1.0e+1; e -= 1; }
++ if( esign<0 ){
++ result = s / scale;
++ result /= 1.0e+308;
++ }else{
++ result = s * scale;
++ result *= 1.0e+308;
++ }
++ }else if( e>=342 ){
++ if( esign<0 ){
++ result = 0.0*s;
++ }else{
++ result = 1e308*1e308*s; /* Infinity */
++ }
++ }else{
++ /* 1.0e+22 is the largest power of 10 than can be
++ ** represented exactly. */
++ while( e%22 ) { scale *= 1.0e+1; e -= 1; }
++ while( e>0 ) { scale *= 1.0e+22; e -= 22; }
++ if( esign<0 ){
++ result = s / scale;
++ }else{
++ result = s * scale;
++ }
+ }
++ } else {
++ result = (double)s;
+ }
+-#if defined(FD_CLOEXEC) && (!defined(O_CLOEXEC) || O_CLOEXEC==0)
+- osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
+-#endif
+ }
+- return fd;
++
++ /* store the result */
++ *pResult = result;
++
++ /* return true if number and no extra non-whitespace chracters after */
++ return z>=zEnd && nDigits>0 && eValid && nonNum==0;
++#else
++ return !sqlite3Atoi64(z, pResult, length, enc);
++#endif /* SQLITE_OMIT_FLOATING_POINT */
+ }
+
+ /*
+-** Helper functions to obtain and relinquish the global mutex. The
+-** global mutex is used to protect the unixInodeInfo and
+-** vxworksFileId objects used by this file, all of which may be
+-** shared by multiple threads.
++** Compare the 19-character string zNum against the text representation
++** value 2^63: 9223372036854775808. Return negative, zero, or positive
++** if zNum is less than, equal to, or greater than the string.
++** Note that zNum must contain exactly 19 characters.
+ **
+-** Function unixMutexHeld() is used to assert() that the global mutex
+-** is held when required. This function is only used as part of assert()
+-** statements. e.g.
++** Unlike memcmp() this routine is guaranteed to return the difference
++** in the values of the last digit if the only difference is in the
++** last digit. So, for example,
+ **
+-** unixEnterMutex()
+-** assert( unixMutexHeld() );
+-** unixEnterLeave()
++** compare2pow63("9223372036854775800", 1)
++**
++** will return -8.
+ */
+-static void unixEnterMutex(void){
+- sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+-}
+-static void unixLeaveMutex(void){
+- sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+-}
+-#ifdef SQLITE_DEBUG
+-static int unixMutexHeld(void) {
+- return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
++static int compare2pow63(const char *zNum, int incr){
++ int c = 0;
++ int i;
++ /* 012345678901234567 */
++ const char *pow63 = "922337203685477580";
++ for(i=0; c==0 && i<18; i++){
++ c = (zNum[i*incr]-pow63[i])*10;
++ }
++ if( c==0 ){
++ c = zNum[18*incr] - '8';
++ testcase( c==(-1) );
++ testcase( c==0 );
++ testcase( c==(+1) );
++ }
++ return c;
+ }
+-#endif
+
+
+-#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
+ /*
+-** Helper function for printing out trace information from debugging
+-** binaries. This returns the string represetation of the supplied
+-** integer lock-type.
++** Convert zNum to a 64-bit signed integer.
++**
++** If the zNum value is representable as a 64-bit twos-complement
++** integer, then write that value into *pNum and return 0.
++**
++** If zNum is exactly 9223372036854665808, return 2. This special
++** case is broken out because while 9223372036854665808 cannot be a
++** signed 64-bit integer, its negative -9223372036854665808 can be.
++**
++** If zNum is too big for a 64-bit integer and is not
++** 9223372036854665808 or if zNum contains any non-numeric text,
++** then return 1.
++**
++** length is the number of bytes in the string (bytes, not characters).
++** The string is not necessarily zero-terminated. The encoding is
++** given by enc.
+ */
+-static const char *azFileLock(int eFileLock){
+- switch( eFileLock ){
+- case NO_LOCK: return "NONE";
+- case SHARED_LOCK: return "SHARED";
+- case RESERVED_LOCK: return "RESERVED";
+- case PENDING_LOCK: return "PENDING";
+- case EXCLUSIVE_LOCK: return "EXCLUSIVE";
++SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
++ int incr;
++ u64 u = 0;
++ int neg = 0; /* assume positive */
++ int i;
++ int c = 0;
++ int nonNum = 0;
++ const char *zStart;
++ const char *zEnd = zNum + length;
++ assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
++ if( enc==SQLITE_UTF8 ){
++ incr = 1;
++ }else{
++ incr = 2;
++ assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
++ for(i=3-enc; i<length && zNum[i]==0; i+=2){}
++ nonNum = i<length;
++ zEnd = zNum+i+enc-3;
++ zNum += (enc&1);
++ }
++ while( zNum<zEnd && sqlite3Isspace(*zNum) ) zNum+=incr;
++ if( zNum<zEnd ){
++ if( *zNum=='-' ){
++ neg = 1;
++ zNum+=incr;
++ }else if( *zNum=='+' ){
++ zNum+=incr;
++ }
++ }
++ zStart = zNum;
++ while( zNum<zEnd && zNum[0]=='0' ){ zNum+=incr; } /* Skip leading zeros. */
++ for(i=0; &zNum[i]<zEnd && (c=zNum[i])>='0' && c<='9'; i+=incr){
++ u = u*10 + c - '0';
++ }
++ if( u>LARGEST_INT64 ){
++ *pNum = SMALLEST_INT64;
++ }else if( neg ){
++ *pNum = -(i64)u;
++ }else{
++ *pNum = (i64)u;
++ }
++ testcase( i==18 );
++ testcase( i==19 );
++ testcase( i==20 );
++ if( (c!=0 && &zNum[i]<zEnd) || (i==0 && zStart==zNum) || i>19*incr || nonNum ){
++ /* zNum is empty or contains non-numeric text or is longer
++ ** than 19 digits (thus guaranteeing that it is too large) */
++ return 1;
++ }else if( i<19*incr ){
++ /* Less than 19 digits, so we know that it fits in 64 bits */
++ assert( u<=LARGEST_INT64 );
++ return 0;
++ }else{
++ /* zNum is a 19-digit numbers. Compare it against 9223372036854775808. */
++ c = compare2pow63(zNum, incr);
++ if( c<0 ){
++ /* zNum is less than 9223372036854775808 so it fits */
++ assert( u<=LARGEST_INT64 );
++ return 0;
++ }else if( c>0 ){
++ /* zNum is greater than 9223372036854775808 so it overflows */
++ return 1;
++ }else{
++ /* zNum is exactly 9223372036854775808. Fits if negative. The
++ ** special case 2 overflow if positive */
++ assert( u-1==LARGEST_INT64 );
++ assert( (*pNum)==SMALLEST_INT64 );
++ return neg ? 0 : 2;
++ }
+ }
+- return "ERROR";
+ }
+-#endif
+
+-#ifdef SQLITE_LOCK_TRACE
+ /*
+-** Print out information about all locking operations.
++** If zNum represents an integer that will fit in 32-bits, then set
++** *pValue to that integer and return true. Otherwise return false.
+ **
+-** This routine is used for troubleshooting locks on multithreaded
+-** platforms. Enable by compiling with the -DSQLITE_LOCK_TRACE
+-** command-line option on the compiler. This code is normally
+-** turned off.
++** Any non-numeric characters that following zNum are ignored.
++** This is different from sqlite3Atoi64() which requires the
++** input number to be zero-terminated.
+ */
+-static int lockTrace(int fd, int op, struct flock *p){
+- char *zOpName, *zType;
+- int s;
+- int savedErrno;
+- if( op==F_GETLK ){
+- zOpName = "GETLK";
+- }else if( op==F_SETLK ){
+- zOpName = "SETLK";
+- }else{
+- s = osFcntl(fd, op, p);
+- sqlite3DebugPrintf("fcntl unknown %d %d %d\n", fd, op, s);
+- return s;
++SQLITE_PRIVATE int sqlite3GetInt32(const char *zNum, int *pValue){
++ sqlite_int64 v = 0;
++ int i, c;
++ int neg = 0;
++ if( zNum[0]=='-' ){
++ neg = 1;
++ zNum++;
++ }else if( zNum[0]=='+' ){
++ zNum++;
+ }
+- if( p->l_type==F_RDLCK ){
+- zType = "RDLCK";
+- }else if( p->l_type==F_WRLCK ){
+- zType = "WRLCK";
+- }else if( p->l_type==F_UNLCK ){
+- zType = "UNLCK";
+- }else{
+- assert( 0 );
++ while( zNum[0]=='0' ) zNum++;
++ for(i=0; i<11 && (c = zNum[i] - '0')>=0 && c<=9; i++){
++ v = v*10 + c;
+ }
+- assert( p->l_whence==SEEK_SET );
+- s = osFcntl(fd, op, p);
+- savedErrno = errno;
+- sqlite3DebugPrintf("fcntl %d %d %s %s %d %d %d %d\n",
+- threadid, fd, zOpName, zType, (int)p->l_start, (int)p->l_len,
+- (int)p->l_pid, s);
+- if( s==(-1) && op==F_SETLK && (p->l_type==F_RDLCK || p->l_type==F_WRLCK) ){
+- struct flock l2;
+- l2 = *p;
+- osFcntl(fd, F_GETLK, &l2);
+- if( l2.l_type==F_RDLCK ){
+- zType = "RDLCK";
+- }else if( l2.l_type==F_WRLCK ){
+- zType = "WRLCK";
+- }else if( l2.l_type==F_UNLCK ){
+- zType = "UNLCK";
+- }else{
+- assert( 0 );
+- }
+- sqlite3DebugPrintf("fcntl-failure-reason: %s %d %d %d\n",
+- zType, (int)l2.l_start, (int)l2.l_len, (int)l2.l_pid);
++
++ /* The longest decimal representation of a 32 bit integer is 10 digits:
++ **
++ ** 1234567890
++ ** 2^31 -> 2147483648
++ */
++ testcase( i==10 );
++ if( i>10 ){
++ return 0;
+ }
+- errno = savedErrno;
+- return s;
++ testcase( v-neg==2147483647 );
++ if( v-neg>2147483647 ){
++ return 0;
++ }
++ if( neg ){
++ v = -v;
++ }
++ *pValue = (int)v;
++ return 1;
+ }
+-#undef osFcntl
+-#define osFcntl lockTrace
+-#endif /* SQLITE_LOCK_TRACE */
+
+ /*
+-** Retry ftruncate() calls that fail due to EINTR
++** Return a 32-bit integer value extracted from a string. If the
++** string is not an integer, just return 0.
+ */
+-static int robust_ftruncate(int h, sqlite3_int64 sz){
+- int rc;
+- do{ rc = osFtruncate(h,sz); }while( rc<0 && errno==EINTR );
+- return rc;
++SQLITE_PRIVATE int sqlite3Atoi(const char *z){
++ int x = 0;
++ if( z ) sqlite3GetInt32(z, &x);
++ return x;
+ }
+
+ /*
+-** This routine translates a standard POSIX errno code into something
+-** useful to the clients of the sqlite3 functions. Specifically, it is
+-** intended to translate a variety of "try again" errors into SQLITE_BUSY
+-** and a variety of "please close the file descriptor NOW" errors into
+-** SQLITE_IOERR
+-**
+-** Errors during initialization of locks, or file system support for locks,
+-** should handle ENOLCK, ENOTSUP, EOPNOTSUPP separately.
++** The variable-length integer encoding is as follows:
++**
++** KEY:
++** A = 0xxxxxxx 7 bits of data and one flag bit
++** B = 1xxxxxxx 7 bits of data and one flag bit
++** C = xxxxxxxx 8 bits of data
++**
++** 7 bits - A
++** 14 bits - BA
++** 21 bits - BBA
++** 28 bits - BBBA
++** 35 bits - BBBBA
++** 42 bits - BBBBBA
++** 49 bits - BBBBBBA
++** 56 bits - BBBBBBBA
++** 64 bits - BBBBBBBBC
+ */
+-static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) {
+- switch (posixError) {
+-#if 0
+- /* At one point this code was not commented out. In theory, this branch
+- ** should never be hit, as this function should only be called after
+- ** a locking-related function (i.e. fcntl()) has returned non-zero with
+- ** the value of errno as the first argument. Since a system call has failed,
+- ** errno should be non-zero.
+- **
+- ** Despite this, if errno really is zero, we still don't want to return
+- ** SQLITE_OK. The system call failed, and *some* SQLite error should be
+- ** propagated back to the caller. Commenting this branch out means errno==0
+- ** will be handled by the "default:" case below.
+- */
+- case 0:
+- return SQLITE_OK;
+-#endif
+
+- case EAGAIN:
+- case ETIMEDOUT:
+- case EBUSY:
+- case EINTR:
+- case ENOLCK:
+- /* random NFS retry error, unless during file system support
+- * introspection, in which it actually means what it says */
+- return SQLITE_BUSY;
+-
+- case EACCES:
+- /* EACCES is like EAGAIN during locking operations, but not any other time*/
+- if( (sqliteIOErr == SQLITE_IOERR_LOCK) ||
+- (sqliteIOErr == SQLITE_IOERR_UNLOCK) ||
+- (sqliteIOErr == SQLITE_IOERR_RDLOCK) ||
+- (sqliteIOErr == SQLITE_IOERR_CHECKRESERVEDLOCK) ){
+- return SQLITE_BUSY;
++/*
++** Write a 64-bit variable-length integer to memory starting at p[0].
++** The length of data write will be between 1 and 9 bytes. The number
++** of bytes written is returned.
++**
++** A variable-length integer consists of the lower 7 bits of each byte
++** for all bytes that have the 8th bit set and one byte with the 8th
++** 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){
++ int i, j, n;
++ u8 buf[10];
++ if( v & (((u64)0xff000000)<<32) ){
++ p[8] = (u8)v;
++ v >>= 8;
++ for(i=7; i>=0; i--){
++ p[i] = (u8)((v & 0x7f) | 0x80);
++ v >>= 7;
+ }
+- /* else fall through */
+- case EPERM:
+- return SQLITE_PERM;
+-
+- /* EDEADLK is only possible if a call to fcntl(F_SETLKW) is made. And
+- ** this module never makes such a call. And the code in SQLite itself
+- ** asserts that SQLITE_IOERR_BLOCKED is never returned. For these reasons
+- ** this case is also commented out. If the system does set errno to EDEADLK,
+- ** the default SQLITE_IOERR_XXX code will be returned. */
+-#if 0
+- case EDEADLK:
+- return SQLITE_IOERR_BLOCKED;
+-#endif
+-
+-#if EOPNOTSUPP!=ENOTSUP
+- case EOPNOTSUPP:
+- /* something went terribly awry, unless during file system support
+- * introspection, in which it actually means what it says */
+-#endif
+-#ifdef ENOTSUP
+- case ENOTSUP:
+- /* invalid fd, unless during file system support introspection, in which
+- * it actually means what it says */
+-#endif
+- case EIO:
+- case EBADF:
+- case EINVAL:
+- case ENOTCONN:
+- case ENODEV:
+- case ENXIO:
+- case ENOENT:
+-#ifdef ESTALE /* ESTALE is not defined on Interix systems */
+- case ESTALE:
+-#endif
+- case ENOSYS:
+- /* these should force the client to close the file and reconnect */
+-
+- default:
+- return sqliteIOErr;
++ return 9;
++ }
++ n = 0;
++ do{
++ buf[n++] = (u8)((v & 0x7f) | 0x80);
++ v >>= 7;
++ }while( v!=0 );
++ buf[0] &= 0x7f;
++ assert( n<=9 );
++ for(i=0, j=n-1; j>=0; j--, i++){
++ p[i] = buf[j];
+ }
++ 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;
++ return 1;
++ }
++#endif
++ if( (v & ~0x3fff)==0 ){
++ p[0] = (u8)((v>>7) | 0x80);
++ p[1] = (u8)(v & 0x7f);
++ return 2;
++ }
++ return sqlite3PutVarint(p, v);
++}
+
+-/******************************************************************************
+-****************** Begin Unique File ID Utility Used By VxWorks ***************
+-**
+-** On most versions of unix, we can get a unique ID for a file by concatenating
+-** the device number and the inode number. But this does not work on VxWorks.
+-** On VxWorks, a unique file id must be based on the canonical filename.
++/*
++** Bitmasks used by sqlite3GetVarint(). These precomputed constants
++** are defined here rather than simply putting the constant expressions
++** inline in order to work around bugs in the RVT compiler.
+ **
+-** A pointer to an instance of the following structure can be used as a
+-** unique file ID in VxWorks. Each instance of this structure contains
+-** a copy of the canonical filename. There is also a reference count.
+-** The structure is reclaimed when the number of pointers to it drops to
+-** zero.
++** SLOT_2_0 A mask for (0x7f<<14) | 0x7f
+ **
+-** There are never very many files open at one time and lookups are not
+-** a performance-critical path, so it is sufficient to put these
+-** structures on a linked list.
++** SLOT_4_2_0 A mask for (0x7f<<28) | SLOT_2_0
+ */
+-struct vxworksFileId {
+- struct vxworksFileId *pNext; /* Next in a list of them all */
+- int nRef; /* Number of references to this one */
+- int nName; /* Length of the zCanonicalName[] string */
+- char *zCanonicalName; /* Canonical filename */
+-};
++#define SLOT_2_0 0x001fc07f
++#define SLOT_4_2_0 0xf01fc07f
+
+-#if OS_VXWORKS
+-/*
+-** All unique filenames are held on a linked list headed by this
+-** variable:
+-*/
+-static struct vxworksFileId *vxworksFileList = 0;
+
+ /*
+-** Simplify a filename into its canonical form
+-** by making the following changes:
+-**
+-** * removing any trailing and duplicate /
+-** * convert /./ into just /
+-** * convert /A/../ where A is any simple name into just /
+-**
+-** Changes are made in-place. Return the new name length.
+-**
+-** The original filename is in z[0..n-1]. Return the number of
+-** characters in the simplified name.
++** Read a 64-bit variable-length integer from memory starting at p[0].
++** Return the number of bytes read. The value is stored in *v.
+ */
+-static int vxworksSimplifyName(char *z, int n){
+- int i, j;
+- while( n>1 && z[n-1]=='/' ){ n--; }
+- for(i=j=0; i<n; i++){
+- if( z[i]=='/' ){
+- if( z[i+1]=='/' ) continue;
+- if( z[i+1]=='.' && i+2<n && z[i+2]=='/' ){
+- i += 1;
+- continue;
+- }
+- if( z[i+1]=='.' && i+3<n && z[i+2]=='.' && z[i+3]=='/' ){
+- while( j>0 && z[j-1]!='/' ){ j--; }
+- if( j>0 ){ j--; }
+- i += 2;
+- continue;
+- }
+- }
+- z[j++] = z[i];
++SQLITE_PRIVATE u8 sqlite3GetVarint(const unsigned char *p, u64 *v){
++ u32 a,b,s;
++
++ a = *p;
++ /* a: p0 (unmasked) */
++ if (!(a&0x80))
++ {
++ *v = a;
++ return 1;
+ }
+- z[j] = 0;
+- return j;
++
++ p++;
++ b = *p;
++ /* b: p1 (unmasked) */
++ if (!(b&0x80))
++ {
++ a &= 0x7f;
++ a = a<<7;
++ a |= b;
++ *v = a;
++ return 2;
++ }
++
++ /* Verify that constants are precomputed correctly */
++ assert( SLOT_2_0 == ((0x7f<<14) | (0x7f)) );
++ assert( SLOT_4_2_0 == ((0xfU<<28) | (0x7f<<14) | (0x7f)) );
++
++ p++;
++ a = a<<14;
++ a |= *p;
++ /* a: p0<<14 | p2 (unmasked) */
++ if (!(a&0x80))
++ {
++ a &= SLOT_2_0;
++ b &= 0x7f;
++ b = b<<7;
++ a |= b;
++ *v = a;
++ return 3;
++ }
++
++ /* CSE1 from below */
++ a &= SLOT_2_0;
++ p++;
++ b = b<<14;
++ b |= *p;
++ /* b: p1<<14 | p3 (unmasked) */
++ if (!(b&0x80))
++ {
++ b &= SLOT_2_0;
++ /* moved CSE1 up */
++ /* a &= (0x7f<<14)|(0x7f); */
++ a = a<<7;
++ a |= b;
++ *v = a;
++ return 4;
++ }
++
++ /* a: p0<<14 | p2 (masked) */
++ /* b: p1<<14 | p3 (unmasked) */
++ /* 1:save off p0<<21 | p1<<14 | p2<<7 | p3 (masked) */
++ /* moved CSE1 up */
++ /* a &= (0x7f<<14)|(0x7f); */
++ b &= SLOT_2_0;
++ s = a;
++ /* s: p0<<14 | p2 (masked) */
++
++ p++;
++ a = a<<14;
++ a |= *p;
++ /* a: p0<<28 | p2<<14 | p4 (unmasked) */
++ if (!(a&0x80))
++ {
++ /* we can skip these cause they were (effectively) done above in calc'ing s */
++ /* a &= (0x7f<<28)|(0x7f<<14)|(0x7f); */
++ /* b &= (0x7f<<14)|(0x7f); */
++ b = b<<7;
++ a |= b;
++ s = s>>18;
++ *v = ((u64)s)<<32 | a;
++ return 5;
++ }
++
++ /* 2:save off p0<<21 | p1<<14 | p2<<7 | p3 (masked) */
++ s = s<<7;
++ s |= b;
++ /* s: p0<<21 | p1<<14 | p2<<7 | p3 (masked) */
++
++ p++;
++ b = b<<14;
++ b |= *p;
++ /* b: p1<<28 | p3<<14 | p5 (unmasked) */
++ if (!(b&0x80))
++ {
++ /* we can skip this cause it was (effectively) done above in calc'ing s */
++ /* b &= (0x7f<<28)|(0x7f<<14)|(0x7f); */
++ a &= SLOT_2_0;
++ a = a<<7;
++ a |= b;
++ s = s>>18;
++ *v = ((u64)s)<<32 | a;
++ return 6;
++ }
++
++ p++;
++ a = a<<14;
++ a |= *p;
++ /* a: p2<<28 | p4<<14 | p6 (unmasked) */
++ if (!(a&0x80))
++ {
++ a &= SLOT_4_2_0;
++ b &= SLOT_2_0;
++ b = b<<7;
++ a |= b;
++ s = s>>11;
++ *v = ((u64)s)<<32 | a;
++ return 7;
++ }
++
++ /* CSE2 from below */
++ a &= SLOT_2_0;
++ p++;
++ b = b<<14;
++ b |= *p;
++ /* b: p3<<28 | p5<<14 | p7 (unmasked) */
++ if (!(b&0x80))
++ {
++ b &= SLOT_4_2_0;
++ /* moved CSE2 up */
++ /* a &= (0x7f<<14)|(0x7f); */
++ a = a<<7;
++ a |= b;
++ s = s>>4;
++ *v = ((u64)s)<<32 | a;
++ return 8;
++ }
++
++ p++;
++ a = a<<15;
++ a |= *p;
++ /* a: p4<<29 | p6<<15 | p8 (unmasked) */
++
++ /* moved CSE2 up */
++ /* a &= (0x7f<<29)|(0x7f<<15)|(0xff); */
++ b &= SLOT_2_0;
++ b = b<<8;
++ a |= b;
++
++ s = s<<4;
++ b = p[-4];
++ b &= 0x7f;
++ b = b>>3;
++ s |= b;
++
++ *v = ((u64)s)<<32 | a;
++
++ return 9;
+ }
+
+ /*
+-** Find a unique file ID for the given absolute pathname. Return
+-** a pointer to the vxworksFileId object. This pointer is the unique
+-** file ID.
++** Read a 32-bit variable-length integer from memory starting at p[0].
++** Return the number of bytes read. The value is stored in *v.
+ **
+-** The nRef field of the vxworksFileId object is incremented before
+-** the object is returned. A new vxworksFileId object is created
+-** and added to the global list if necessary.
++** If the varint stored in p[0] is larger than can fit in a 32-bit unsigned
++** integer, then set *v to 0xffffffff.
+ **
+-** If a memory allocation error occurs, return NULL.
++** A MACRO version, getVarint32, 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.
+ */
+-static struct vxworksFileId *vxworksFindFileId(const char *zAbsoluteName){
+- struct vxworksFileId *pNew; /* search key and new file ID */
+- struct vxworksFileId *pCandidate; /* For looping over existing file IDs */
+- int n; /* Length of zAbsoluteName string */
++SQLITE_PRIVATE u8 sqlite3GetVarint32(const unsigned char *p, u32 *v){
++ u32 a,b;
+
+- assert( zAbsoluteName[0]=='/' );
+- n = (int)strlen(zAbsoluteName);
+- pNew = sqlite3_malloc( sizeof(*pNew) + (n+1) );
+- if( pNew==0 ) return 0;
+- pNew->zCanonicalName = (char*)&pNew[1];
+- memcpy(pNew->zCanonicalName, zAbsoluteName, n+1);
+- n = vxworksSimplifyName(pNew->zCanonicalName, n);
++ /* The 1-byte case. Overwhelmingly the most common. Handled inline
++ ** by the getVarin32() macro */
++ a = *p;
++ /* a: p0 (unmasked) */
++#ifndef getVarint32
++ if (!(a&0x80))
++ {
++ /* Values between 0 and 127 */
++ *v = a;
++ return 1;
++ }
++#endif
+
+- /* Search for an existing entry that matching the canonical name.
+- ** If found, increment the reference count and return a pointer to
+- ** the existing file ID.
++ /* The 2-byte case */
++ p++;
++ b = *p;
++ /* b: p1 (unmasked) */
++ if (!(b&0x80))
++ {
++ /* Values between 128 and 16383 */
++ a &= 0x7f;
++ a = a<<7;
++ *v = a | b;
++ return 2;
++ }
++
++ /* The 3-byte case */
++ p++;
++ a = a<<14;
++ a |= *p;
++ /* a: p0<<14 | p2 (unmasked) */
++ if (!(a&0x80))
++ {
++ /* Values between 16384 and 2097151 */
++ a &= (0x7f<<14)|(0x7f);
++ b &= 0x7f;
++ b = b<<7;
++ *v = a | b;
++ return 3;
++ }
++
++ /* A 32-bit varint is used to store size information in btrees.
++ ** Objects are rarely larger than 2MiB limit of a 3-byte varint.
++ ** A 3-byte varint is sufficient, for example, to record the size
++ ** of a 1048569-byte BLOB or string.
++ **
++ ** We only unroll the first 1-, 2-, and 3- byte cases. The very
++ ** rare larger cases can be handled by the slower 64-bit varint
++ ** routine.
+ */
+- unixEnterMutex();
+- for(pCandidate=vxworksFileList; pCandidate; pCandidate=pCandidate->pNext){
+- if( pCandidate->nName==n
+- && memcmp(pCandidate->zCanonicalName, pNew->zCanonicalName, n)==0
+- ){
+- sqlite3_free(pNew);
+- pCandidate->nRef++;
+- unixLeaveMutex();
+- return pCandidate;
++#if 1
++ {
++ u64 v64;
++ u8 n;
++
++ p -= 2;
++ n = sqlite3GetVarint(p, &v64);
++ assert( n>3 && n<=9 );
++ if( (v64 & SQLITE_MAX_U32)!=v64 ){
++ *v = 0xffffffff;
++ }else{
++ *v = (u32)v64;
+ }
++ return n;
+ }
+
+- /* No match was found. We will make a new file ID */
+- pNew->nRef = 1;
+- pNew->nName = n;
+- pNew->pNext = vxworksFileList;
+- vxworksFileList = pNew;
+- unixLeaveMutex();
+- return pNew;
+-}
++#else
++ /* For following code (kept for historical record only) shows an
++ ** unrolling for the 3- and 4-byte varint cases. This code is
++ ** slightly faster, but it is also larger and much harder to test.
++ */
++ p++;
++ b = b<<14;
++ b |= *p;
++ /* b: p1<<14 | p3 (unmasked) */
++ if (!(b&0x80))
++ {
++ /* Values between 2097152 and 268435455 */
++ b &= (0x7f<<14)|(0x7f);
++ a &= (0x7f<<14)|(0x7f);
++ a = a<<7;
++ *v = a | b;
++ return 4;
++ }
+
+-/*
+-** Decrement the reference count on a vxworksFileId object. Free
+-** the object when the reference count reaches zero.
+-*/
+-static void vxworksReleaseFileId(struct vxworksFileId *pId){
+- unixEnterMutex();
+- assert( pId->nRef>0 );
+- pId->nRef--;
+- if( pId->nRef==0 ){
+- struct vxworksFileId **pp;
+- for(pp=&vxworksFileList; *pp && *pp!=pId; pp = &((*pp)->pNext)){}
+- assert( *pp==pId );
+- *pp = pId->pNext;
+- sqlite3_free(pId);
++ p++;
++ a = a<<14;
++ a |= *p;
++ /* a: p0<<28 | p2<<14 | p4 (unmasked) */
++ if (!(a&0x80))
++ {
++ /* Values between 268435456 and 34359738367 */
++ a &= SLOT_4_2_0;
++ b &= SLOT_4_2_0;
++ b = b<<7;
++ *v = a | b;
++ return 5;
+ }
+- unixLeaveMutex();
+-}
+-#endif /* OS_VXWORKS */
+-/*************** End of Unique File ID Utility Used By VxWorks ****************
+-******************************************************************************/
+
++ /* We can only reach this point when reading a corrupt database
++ ** file. In that case we are not in any hurry. Use the (relatively
++ ** slow) general-purpose sqlite3GetVarint() routine to extract the
++ ** value. */
++ {
++ u64 v64;
++ u8 n;
+
+-/******************************************************************************
+-*************************** Posix Advisory Locking ****************************
+-**
+-** POSIX advisory locks are broken by design. ANSI STD 1003.1 (1996)
+-** section 6.5.2.2 lines 483 through 490 specify that when a process
+-** sets or clears a lock, that operation overrides any prior locks set
+-** by the same process. It does not explicitly say so, but this implies
+-** that it overrides locks set by the same process using a different
+-** file descriptor. Consider this test case:
+-**
+-** int fd1 = open("./file1", O_RDWR|O_CREAT, 0644);
+-** int fd2 = open("./file2", O_RDWR|O_CREAT, 0644);
+-**
+-** Suppose ./file1 and ./file2 are really the same file (because
+-** one is a hard or symbolic link to the other) then if you set
+-** an exclusive lock on fd1, then try to get an exclusive lock
+-** on fd2, it works. I would have expected the second lock to
+-** fail since there was already a lock on the file due to fd1.
+-** But not so. Since both locks came from the same process, the
+-** second overrides the first, even though they were on different
+-** file descriptors opened on different file names.
+-**
+-** This means that we cannot use POSIX locks to synchronize file access
+-** among competing threads of the same process. POSIX locks will work fine
+-** to synchronize access for threads in separate processes, but not
+-** threads within the same process.
+-**
+-** To work around the problem, SQLite has to manage file locks internally
+-** on its own. Whenever a new database is opened, we have to find the
+-** specific inode of the database file (the inode is determined by the
+-** st_dev and st_ino fields of the stat structure that fstat() fills in)
+-** and check for locks already existing on that inode. When locks are
+-** created or removed, we have to look at our own internal record of the
+-** locks to see if another thread has previously set a lock on that same
+-** inode.
+-**
+-** (Aside: The use of inode numbers as unique IDs does not work on VxWorks.
+-** For VxWorks, we have to use the alternative unique ID system based on
+-** canonical filename and implemented in the previous division.)
+-**
+-** The sqlite3_file structure for POSIX is no longer just an integer file
+-** descriptor. It is now a structure that holds the integer file
+-** descriptor and a pointer to a structure that describes the internal
+-** locks on the corresponding inode. There is one locking structure
+-** per inode, so if the same inode is opened twice, both unixFile structures
+-** point to the same locking structure. The locking structure keeps
+-** a reference count (so we will know when to delete it) and a "cnt"
+-** field that tells us its internal lock status. cnt==0 means the
+-** file is unlocked. cnt==-1 means the file has an exclusive lock.
+-** cnt>0 means there are cnt shared locks on the file.
+-**
+-** Any attempt to lock or unlock a file first checks the locking
+-** structure. The fcntl() system call is only invoked to set a
+-** POSIX lock if the internal lock structure transitions between
+-** a locked and an unlocked state.
+-**
+-** But wait: there are yet more problems with POSIX advisory locks.
+-**
+-** If you close a file descriptor that points to a file that has locks,
+-** all locks on that file that are owned by the current process are
+-** released. To work around this problem, each unixInodeInfo object
+-** maintains a count of the number of pending locks on tha inode.
+-** When an attempt is made to close an unixFile, if there are
+-** other unixFile open on the same inode that are holding locks, the call
+-** to close() the file descriptor is deferred until all of the locks clear.
+-** The unixInodeInfo structure keeps a list of file descriptors that need to
+-** be closed and that list is walked (and cleared) when the last lock
+-** clears.
+-**
+-** Yet another problem: LinuxThreads do not play well with posix locks.
+-**
+-** Many older versions of linux use the LinuxThreads library which is
+-** not posix compliant. Under LinuxThreads, a lock created by thread
+-** A cannot be modified or overridden by a different thread B.
+-** Only thread A can modify the lock. Locking behavior is correct
+-** if the appliation uses the newer Native Posix Thread Library (NPTL)
+-** on linux - with NPTL a lock created by thread A can override locks
+-** in thread B. But there is no way to know at compile-time which
+-** threading library is being used. So there is no way to know at
+-** compile-time whether or not thread A can override locks on thread B.
+-** One has to do a run-time check to discover the behavior of the
+-** current process.
+-**
+-** SQLite used to support LinuxThreads. But support for LinuxThreads
+-** was dropped beginning with version 3.7.0. SQLite will still work with
+-** LinuxThreads provided that (1) there is no more than one connection
+-** per database file in the same process and (2) database connections
+-** do not move across threads.
++ p -= 4;
++ n = sqlite3GetVarint(p, &v64);
++ assert( n>5 && n<=9 );
++ *v = (u32)v64;
++ return n;
++ }
++#endif
++}
++
++/*
++** Return the number of bytes that will be needed to store the given
++** 64-bit integer.
+ */
++SQLITE_PRIVATE int sqlite3VarintLen(u64 v){
++ int i = 0;
++ do{
++ i++;
++ v >>= 7;
++ }while( v!=0 && ALWAYS(i<9) );
++ return i;
++}
++
+
+ /*
+-** An instance of the following structure serves as the key used
+-** to locate a particular unixInodeInfo object.
++** Read or write a four-byte big-endian integer value.
+ */
+-struct unixFileId {
+- dev_t dev; /* Device number */
+-#if OS_VXWORKS
+- struct vxworksFileId *pId; /* Unique file ID for vxworks. */
+-#else
+- ino_t ino; /* Inode number */
+-#endif
+-};
++SQLITE_PRIVATE u32 sqlite3Get4byte(const u8 *p){
++ return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
++}
++SQLITE_PRIVATE void sqlite3Put4byte(unsigned char *p, u32 v){
++ p[0] = (u8)(v>>24);
++ p[1] = (u8)(v>>16);
++ p[2] = (u8)(v>>8);
++ p[3] = (u8)v;
++}
++
++
+
+ /*
+-** An instance of the following structure is allocated for each open
+-** inode. Or, on LinuxThreads, there is one of these structures for
+-** each inode opened by each thread.
+-**
+-** A single inode can have multiple file descriptors, so each unixFile
+-** structure contains a pointer to an instance of this object and this
+-** object keeps a count of the number of unixFile pointing to it.
++** Translate a single byte of Hex into an integer.
++** This routine only works if h really is a valid hexadecimal
++** character: 0..9a..fA..F
+ */
+-struct unixInodeInfo {
+- struct unixFileId fileId; /* The lookup key */
+- int nShared; /* Number of SHARED locks held */
+- unsigned char eFileLock; /* One of SHARED_LOCK, RESERVED_LOCK etc. */
+- unsigned char bProcessLock; /* An exclusive process lock is held */
+- int nRef; /* Number of pointers to this structure */
+- unixShmNode *pShmNode; /* Shared memory associated with this inode */
+- int nLock; /* Number of outstanding file locks */
+- UnixUnusedFd *pUnused; /* Unused file descriptors to close */
+- unixInodeInfo *pNext; /* List of all unixInodeInfo objects */
+- unixInodeInfo *pPrev; /* .... doubly linked */
+-#if SQLITE_ENABLE_LOCKING_STYLE
+- unsigned long long sharedByte; /* for AFP simulated shared lock */
++SQLITE_PRIVATE u8 sqlite3HexToInt(int h){
++ assert( (h>='0' && h<='9') || (h>='a' && h<='f') || (h>='A' && h<='F') );
++#ifdef SQLITE_ASCII
++ h += 9*(1&(h>>6));
+ #endif
+-#if OS_VXWORKS
+- sem_t *pSem; /* Named POSIX semaphore */
+- char aSemName[MAX_PATHNAME+2]; /* Name of that semaphore */
++#ifdef SQLITE_EBCDIC
++ h += 9*(1&~(h>>4));
+ #endif
+-};
++ return (u8)(h & 0xf);
++}
+
++#if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC)
+ /*
+-** A lists of all unixInodeInfo objects.
++** Convert a BLOB literal of the form "x'hhhhhh'" into its binary
++** value. Return a pointer to its binary value. Space to hold the
++** binary value has been obtained from malloc and must be freed by
++** the calling routine.
+ */
+-static unixInodeInfo *inodeList = 0;
++SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){
++ char *zBlob;
++ int i;
++
++ zBlob = (char *)sqlite3DbMallocRaw(db, n/2 + 1);
++ n--;
++ if( zBlob ){
++ for(i=0; i<n; i+=2){
++ zBlob[i/2] = (sqlite3HexToInt(z[i])<<4) | sqlite3HexToInt(z[i+1]);
++ }
++ zBlob[i/2] = 0;
++ }
++ return zBlob;
++}
++#endif /* !SQLITE_OMIT_BLOB_LITERAL || SQLITE_HAS_CODEC */
+
+ /*
+-**
+-** This function - unixLogError_x(), is only ever called via the macro
+-** unixLogError().
+-**
+-** It is invoked after an error occurs in an OS function and errno has been
+-** set. It logs a message using sqlite3_log() containing the current value of
+-** errno and, if possible, the human-readable equivalent from strerror() or
+-** strerror_r().
+-**
+-** 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 (e.g. "unlink", "open") and the associated file-system path,
+-** if any.
++** Log an error that is an API call on a connection pointer that should
++** not have been used. The "type" of connection pointer is given as the
++** argument. The zType is a word like "NULL" or "closed" or "invalid".
+ */
+-#define unixLogError(a,b,c) unixLogErrorAtLine(a,b,c,__LINE__)
+-static int unixLogErrorAtLine(
+- int errcode, /* SQLite error code */
+- 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 *zErr; /* Message from strerror() or equivalent */
+- int iErrno = errno; /* Saved syscall error number */
+-
+- /* If this is not a threadsafe build (SQLITE_THREADSAFE==0), then use
+- ** the strerror() function to obtain the human-readable error message
+- ** equivalent to errno. Otherwise, use strerror_r().
+- */
+-#if SQLITE_THREADSAFE && defined(HAVE_STRERROR_R)
+- char aErr[80];
+- memset(aErr, 0, sizeof(aErr));
+- zErr = aErr;
+-
+- /* If STRERROR_R_CHAR_P (set by autoconf scripts) or __USE_GNU is defined,
+- ** assume that the system provides the GNU version of strerror_r() that
+- ** returns a pointer to a buffer containing the error message. That pointer
+- ** may point to aErr[], or it may point to some static storage somewhere.
+- ** Otherwise, assume that the system provides the POSIX version of
+- ** strerror_r(), which always writes an error message into aErr[].
+- **
+- ** If the code incorrectly assumes that it is the POSIX version that is
+- ** available, the error message will often be an empty string. Not a
+- ** huge problem. Incorrectly concluding that the GNU version is available
+- ** could lead to a segfault though.
+- */
+-#if defined(STRERROR_R_CHAR_P) || defined(__USE_GNU)
+- zErr =
+-# endif
+- strerror_r(iErrno, aErr, sizeof(aErr)-1);
+-
+-#elif SQLITE_THREADSAFE
+- /* This is a threadsafe build, but strerror_r() is not available. */
+- zErr = "";
+-#else
+- /* Non-threadsafe build, use strerror(). */
+- zErr = strerror(iErrno);
+-#endif
+-
+- if( zPath==0 ) zPath = "";
+- sqlite3_log(errcode,
+- "os_unix.c:%d: (%d) %s(%s) - %s",
+- iLine, iErrno, zFunc, zPath, zErr
++static void logBadConnection(const char *zType){
++ sqlite3_log(SQLITE_MISUSE,
++ "API call with %s database connection pointer",
++ zType
+ );
+-
+- return errcode;
+ }
+
+ /*
+-** Close a file descriptor.
+-**
+-** We assume that close() almost always works, since it is only in a
+-** very sick application or on a very sick platform that it might fail.
+-** If it does fail, simply leak the file descriptor, but do log the
+-** error.
++** Check to make sure we have a valid db pointer. This test is not
++** foolproof but it does provide some measure of protection against
++** misuse of the interface such as passing in db pointers that are
++** NULL or which have been previously closed. If this routine returns
++** 1 it means that the db pointer is valid and 0 if it should not be
++** dereferenced for any reason. The calling function should invoke
++** SQLITE_MISUSE immediately.
+ **
+-** Note that it is not safe to retry close() after EINTR since the
+-** file descriptor might have already been reused by another thread.
+-** So we don't even try to recover from an EINTR. Just log the error
+-** and move on.
++** sqlite3SafetyCheckOk() requires that the db pointer be valid for
++** use. sqlite3SafetyCheckSickOrOk() allows a db pointer that failed to
++** open properly and is not fit for general use but which can be
++** used as an argument to sqlite3_errmsg() or sqlite3_close().
+ */
+-static void robust_close(unixFile *pFile, int h, int lineno){
+- if( osClose(h) ){
+- unixLogErrorAtLine(SQLITE_IOERR_CLOSE, "close",
+- pFile ? pFile->zPath : 0, lineno);
++SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3 *db){
++ u32 magic;
++ if( db==0 ){
++ logBadConnection("NULL");
++ return 0;
++ }
++ magic = db->magic;
++ if( magic!=SQLITE_MAGIC_OPEN ){
++ if( sqlite3SafetyCheckSickOrOk(db) ){
++ testcase( sqlite3GlobalConfig.xLog!=0 );
++ logBadConnection("unopened");
++ }
++ return 0;
++ }else{
++ return 1;
++ }
++}
++SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3 *db){
++ u32 magic;
++ magic = db->magic;
++ if( magic!=SQLITE_MAGIC_SICK &&
++ magic!=SQLITE_MAGIC_OPEN &&
++ magic!=SQLITE_MAGIC_BUSY ){
++ testcase( sqlite3GlobalConfig.xLog!=0 );
++ logBadConnection("invalid");
++ return 0;
++ }else{
++ return 1;
+ }
+ }
+
+ /*
+-** Close all file descriptors accumuated in the unixInodeInfo->pUnused list.
+-*/
+-static void closePendingFds(unixFile *pFile){
+- unixInodeInfo *pInode = pFile->pInode;
+- UnixUnusedFd *p;
+- UnixUnusedFd *pNext;
+- for(p=pInode->pUnused; p; p=pNext){
+- pNext = p->pNext;
+- robust_close(pFile, p->fd, __LINE__);
+- sqlite3_free(p);
++** Attempt to add, substract, or multiply the 64-bit signed value iB against
++** the other 64-bit signed integer at *pA and store the result in *pA.
++** Return 0 on success. Or if the operation would have resulted in an
++** overflow, leave *pA unchanged and return 1.
++*/
++SQLITE_PRIVATE int sqlite3AddInt64(i64 *pA, i64 iB){
++ i64 iA = *pA;
++ testcase( iA==0 ); testcase( iA==1 );
++ testcase( iB==-1 ); testcase( iB==0 );
++ if( iB>=0 ){
++ testcase( iA>0 && LARGEST_INT64 - iA == iB );
++ testcase( iA>0 && LARGEST_INT64 - iA == iB - 1 );
++ if( iA>0 && LARGEST_INT64 - iA < iB ) return 1;
++ *pA += iB;
++ }else{
++ testcase( iA<0 && -(iA + LARGEST_INT64) == iB + 1 );
++ testcase( iA<0 && -(iA + LARGEST_INT64) == iB + 2 );
++ if( iA<0 && -(iA + LARGEST_INT64) > iB + 1 ) return 1;
++ *pA += iB;
+ }
+- pInode->pUnused = 0;
++ return 0;
++}
++SQLITE_PRIVATE int sqlite3SubInt64(i64 *pA, i64 iB){
++ testcase( iB==SMALLEST_INT64+1 );
++ if( iB==SMALLEST_INT64 ){
++ testcase( (*pA)==(-1) ); testcase( (*pA)==0 );
++ if( (*pA)>=0 ) return 1;
++ *pA -= iB;
++ return 0;
++ }else{
++ return sqlite3AddInt64(pA, -iB);
++ }
++}
++#define TWOPOWER32 (((i64)1)<<32)
++#define TWOPOWER31 (((i64)1)<<31)
++SQLITE_PRIVATE int sqlite3MulInt64(i64 *pA, i64 iB){
++ i64 iA = *pA;
++ i64 iA1, iA0, iB1, iB0, r;
++
++ iA1 = iA/TWOPOWER32;
++ iA0 = iA % TWOPOWER32;
++ iB1 = iB/TWOPOWER32;
++ iB0 = iB % TWOPOWER32;
++ if( iA1*iB1 != 0 ) return 1;
++ assert( iA1*iB0==0 || iA0*iB1==0 );
++ r = iA1*iB0 + iA0*iB1;
++ testcase( r==(-TWOPOWER31)-1 );
++ testcase( r==(-TWOPOWER31) );
++ testcase( r==TWOPOWER31 );
++ testcase( r==TWOPOWER31-1 );
++ if( r<(-TWOPOWER31) || r>=TWOPOWER31 ) return 1;
++ r *= TWOPOWER32;
++ if( sqlite3AddInt64(&r, iA0*iB0) ) return 1;
++ *pA = r;
++ return 0;
+ }
+
+ /*
+-** Release a unixInodeInfo structure previously allocated by findInodeInfo().
++** Compute the absolute value of a 32-bit signed integer, of possible. Or
++** if the integer has a value of -2147483648, return +2147483647
++*/
++SQLITE_PRIVATE int sqlite3AbsInt32(int x){
++ if( x>=0 ) return x;
++ if( x==(int)0x80000000 ) return 0x7fffffff;
++ return -x;
++}
++
++#ifdef SQLITE_ENABLE_8_3_NAMES
++/*
++** If SQLITE_ENABLE_8_3_NAMES is set at compile-time and if the database
++** filename in zBaseFilename is a URI with the "8_3_names=1" parameter and
++** if filename in z[] has a suffix (a.k.a. "extension") that is longer than
++** three characters, then shorten the suffix on z[] to be the last three
++** characters of the original suffix.
+ **
+-** The mutex entered using the unixEnterMutex() function must be held
+-** when this function is called.
++** If SQLITE_ENABLE_8_3_NAMES is set to 2 at compile-time, then always
++** do the suffix shortening regardless of URI parameter.
++**
++** Examples:
++**
++** test.db-journal => test.nal
++** test.db-wal => test.wal
++** test.db-shm => test.shm
++** test.db-mj7f3319fa => test.9fa
+ */
+-static void releaseInodeInfo(unixFile *pFile){
+- unixInodeInfo *pInode = pFile->pInode;
+- assert( unixMutexHeld() );
+- if( ALWAYS(pInode) ){
+- pInode->nRef--;
+- if( pInode->nRef==0 ){
+- assert( pInode->pShmNode==0 );
+- closePendingFds(pFile);
+- if( pInode->pPrev ){
+- assert( pInode->pPrev->pNext==pInode );
+- pInode->pPrev->pNext = pInode->pNext;
+- }else{
+- assert( inodeList==pInode );
+- inodeList = pInode->pNext;
+- }
+- if( pInode->pNext ){
+- assert( pInode->pNext->pPrev==pInode );
+- pInode->pNext->pPrev = pInode->pPrev;
+- }
+- sqlite3_free(pInode);
+- }
++SQLITE_PRIVATE void sqlite3FileSuffix3(const char *zBaseFilename, char *z){
++#if SQLITE_ENABLE_8_3_NAMES<2
++ if( sqlite3_uri_boolean(zBaseFilename, "8_3_names", 0) )
++#endif
++ {
++ int i, sz;
++ sz = sqlite3Strlen30(z);
++ for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){}
++ if( z[i]=='.' && ALWAYS(sz>i+4) ) memmove(&z[i+1], &z[sz-3], 4);
+ }
+ }
++#endif
+
++/************** End of util.c ************************************************/
++/************** Begin file hash.c ********************************************/
+ /*
+-** Given a file descriptor, locate the unixInodeInfo object that
+-** describes that file descriptor. Create a new one if necessary. The
+-** return value might be uninitialized if an error occurs.
++** 2001 September 22
+ **
+-** The mutex entered using the unixEnterMutex() function 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:
+ **
+-** Return an appropriate error code.
++** 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 generic hash-tables
++** used in SQLite.
+ */
+-static int findInodeInfo(
+- unixFile *pFile, /* Unix file with file desc used in the key */
+- unixInodeInfo **ppInode /* Return the unixInodeInfo object here */
+-){
+- int rc; /* System call return code */
+- int fd; /* The file descriptor for pFile */
+- struct unixFileId fileId; /* Lookup key for the unixInodeInfo */
+- struct stat statbuf; /* Low-level file information */
+- unixInodeInfo *pInode = 0; /* Candidate unixInodeInfo object */
++/* #include <assert.h> */
+
+- assert( unixMutexHeld() );
++/* Turn bulk memory into a hash table object by initializing the
++** fields of the Hash structure.
++**
++** "pNew" is a pointer to the hash table that is to be initialized.
++*/
++SQLITE_PRIVATE void sqlite3HashInit(Hash *pNew){
++ assert( pNew!=0 );
++ pNew->first = 0;
++ pNew->count = 0;
++ pNew->htsize = 0;
++ pNew->ht = 0;
++}
+
+- /* Get low-level information about the file that we can used to
+- ** create a unique name for the file.
+- */
+- fd = pFile->h;
+- rc = osFstat(fd, &statbuf);
+- if( rc!=0 ){
+- pFile->lastErrno = errno;
+-#ifdef EOVERFLOW
+- if( pFile->lastErrno==EOVERFLOW ) return SQLITE_NOLFS;
+-#endif
+- return SQLITE_IOERR;
+- }
++/* Remove all entries from a hash table. Reclaim all memory.
++** Call this routine to delete a hash table or to reset a hash table
++** to the empty state.
++*/
++SQLITE_PRIVATE void sqlite3HashClear(Hash *pH){
++ HashElem *elem; /* For looping over all elements of the table */
+
+-#ifdef __APPLE__
+- /* On OS X on an msdos filesystem, the inode number is reported
+- ** incorrectly for zero-size files. See ticket #3260. To work
+- ** around this problem (we consider it a bug in OS X, not SQLite)
+- ** we always increase the file size to 1 by writing a single byte
+- ** prior to accessing the inode number. The one byte written is
+- ** an ASCII 'S' character which also happens to be the first byte
+- ** in the header of every SQLite database. In this way, if there
+- ** is a race condition such that another thread has already populated
+- ** the first page of the database, no damage is done.
+- */
+- 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;
+- return SQLITE_IOERR;
+- }
+- rc = osFstat(fd, &statbuf);
+- if( rc!=0 ){
+- pFile->lastErrno = errno;
+- return SQLITE_IOERR;
+- }
++ assert( pH!=0 );
++ elem = pH->first;
++ pH->first = 0;
++ sqlite3_free(pH->ht);
++ pH->ht = 0;
++ pH->htsize = 0;
++ while( elem ){
++ HashElem *next_elem = elem->next;
++ sqlite3_free(elem);
++ elem = next_elem;
+ }
+-#endif
++ pH->count = 0;
++}
+
+- memset(&fileId, 0, sizeof(fileId));
+- fileId.dev = statbuf.st_dev;
+-#if OS_VXWORKS
+- fileId.pId = pFile->pId;
+-#else
+- fileId.ino = statbuf.st_ino;
+-#endif
+- pInode = inodeList;
+- while( pInode && memcmp(&fileId, &pInode->fileId, sizeof(fileId)) ){
+- pInode = pInode->pNext;
+- }
+- if( pInode==0 ){
+- pInode = sqlite3_malloc( sizeof(*pInode) );
+- if( pInode==0 ){
+- return SQLITE_NOMEM;
+- }
+- memset(pInode, 0, sizeof(*pInode));
+- memcpy(&pInode->fileId, &fileId, sizeof(fileId));
+- pInode->nRef = 1;
+- pInode->pNext = inodeList;
+- pInode->pPrev = 0;
+- if( inodeList ) inodeList->pPrev = pInode;
+- inodeList = pInode;
+- }else{
+- pInode->nRef++;
++/*
++** The hashing function.
++*/
++static unsigned int strHash(const char *z, int nKey){
++ int h = 0;
++ assert( nKey>=0 );
++ while( nKey > 0 ){
++ h = (h<<3) ^ h ^ sqlite3UpperToLower[(unsigned char)*z++];
++ nKey--;
+ }
+- *ppInode = pInode;
+- return SQLITE_OK;
++ return h;
+ }
+
+
+-/*
+-** Check a unixFile that is a database. Verify the following:
+-**
+-** (1) There is exactly one hard link on the file
+-** (2) The file is not a symbolic link
+-** (3) The file has not been renamed or unlinked
+-**
+-** Issue sqlite3_log(SQLITE_WARNING,...) messages if anything is not right.
++/* Link pNew element into the hash table pH. If pEntry!=0 then also
++** insert pNew into the pEntry hash bucket.
+ */
+-static void verifyDbFile(unixFile *pFile){
+- struct stat buf;
+- int rc;
+- if( pFile->ctrlFlags & UNIXFILE_WARNED ){
+- /* One or more of the following warnings have already been issued. Do not
+- ** repeat them so as not to clutter the error log */
+- return;
+- }
+- rc = osFstat(pFile->h, &buf);
+- if( rc!=0 ){
+- sqlite3_log(SQLITE_WARNING, "cannot fstat db file %s", pFile->zPath);
+- pFile->ctrlFlags |= UNIXFILE_WARNED;
+- return;
+- }
+- if( buf.st_nlink==0 && (pFile->ctrlFlags & UNIXFILE_DELETE)==0 ){
+- sqlite3_log(SQLITE_WARNING, "file unlinked while open: %s", pFile->zPath);
+- pFile->ctrlFlags |= UNIXFILE_WARNED;
+- return;
+- }
+- if( buf.st_nlink>1 ){
+- sqlite3_log(SQLITE_WARNING, "multiple links to file: %s", pFile->zPath);
+- pFile->ctrlFlags |= UNIXFILE_WARNED;
+- return;
++static void insertElement(
++ Hash *pH, /* The complete hash table */
++ struct _ht *pEntry, /* The entry into which pNew is inserted */
++ HashElem *pNew /* The element to be inserted */
++){
++ HashElem *pHead; /* First element already in pEntry */
++ if( pEntry ){
++ pHead = pEntry->count ? pEntry->chain : 0;
++ pEntry->count++;
++ pEntry->chain = pNew;
++ }else{
++ pHead = 0;
+ }
+- if( pFile->pInode!=0
+- && ((rc = osStat(pFile->zPath, &buf))!=0
+- || buf.st_ino!=pFile->pInode->fileId.ino)
+- ){
+- sqlite3_log(SQLITE_WARNING, "file renamed while open: %s", pFile->zPath);
+- pFile->ctrlFlags |= UNIXFILE_WARNED;
+- return;
++ if( pHead ){
++ pNew->next = pHead;
++ pNew->prev = pHead->prev;
++ if( pHead->prev ){ pHead->prev->next = pNew; }
++ else { pH->first = pNew; }
++ pHead->prev = pNew;
++ }else{
++ pNew->next = pH->first;
++ if( pH->first ){ pH->first->prev = pNew; }
++ pNew->prev = 0;
++ pH->first = pNew;
+ }
+ }
+
+
+-/*
+-** 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, set *pResOut
+-** 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.
++/* Resize the hash table so that it cantains "new_size" buckets.
++**
++** The hash table might fail to resize if sqlite3_malloc() fails or
++** if the new size is the same as the prior size.
++** Return TRUE if the resize occurs and false if not.
+ */
+-static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){
+- int rc = SQLITE_OK;
+- int reserved = 0;
+- unixFile *pFile = (unixFile*)id;
++static int rehash(Hash *pH, unsigned int new_size){
++ struct _ht *new_ht; /* The new hash table */
++ HashElem *elem, *next_elem; /* For looping over existing elements */
+
+- SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
++#if SQLITE_MALLOC_SOFT_LIMIT>0
++ if( new_size*sizeof(struct _ht)>SQLITE_MALLOC_SOFT_LIMIT ){
++ new_size = SQLITE_MALLOC_SOFT_LIMIT/sizeof(struct _ht);
++ }
++ if( new_size==pH->htsize ) return 0;
++#endif
+
+- assert( pFile );
+- unixEnterMutex(); /* Because pFile->pInode is shared across threads */
++ /* The inability to allocates space for a larger hash table is
++ ** a performance hit but it is not a fatal error. So mark the
++ ** allocation as a benign. Use sqlite3Malloc()/memset(0) instead of
++ ** sqlite3MallocZero() to make the allocation, as sqlite3MallocZero()
++ ** only zeroes the requested number of bytes whereas this module will
++ ** use the actual amount of space allocated for the hash table (which
++ ** may be larger than the requested amount).
++ */
++ sqlite3BeginBenignMalloc();
++ new_ht = (struct _ht *)sqlite3Malloc( new_size*sizeof(struct _ht) );
++ sqlite3EndBenignMalloc();
+
+- /* Check if a thread in this process holds such a lock */
+- if( pFile->pInode->eFileLock>SHARED_LOCK ){
+- reserved = 1;
++ if( new_ht==0 ) return 0;
++ sqlite3_free(pH->ht);
++ pH->ht = new_ht;
++ 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;
++ next_elem = elem->next;
++ insertElement(pH, &new_ht[h], elem);
+ }
++ return 1;
++}
+
+- /* Otherwise see if some other process holds it.
+- */
+-#ifndef __DJGPP__
+- if( !reserved && !pFile->pInode->bProcessLock ){
+- struct flock lock;
+- lock.l_whence = SEEK_SET;
+- lock.l_start = RESERVED_BYTE;
+- lock.l_len = 1;
+- lock.l_type = F_WRLCK;
+- if( osFcntl(pFile->h, F_GETLK, &lock) ){
+- rc = SQLITE_IOERR_CHECKRESERVEDLOCK;
+- pFile->lastErrno = errno;
+- } else if( lock.l_type!=F_UNLCK ){
+- reserved = 1;
++/* 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.
++*/
++static HashElem *findElementGivenHash(
++ 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. */
++){
++ HashElem *elem; /* Used to loop thru the element list */
++ int count; /* Number of elements left to test */
++
++ if( pH->ht ){
++ struct _ht *pEntry = &pH->ht[h];
++ elem = pEntry->chain;
++ count = pEntry->count;
++ }else{
++ elem = pH->first;
++ count = pH->count;
++ }
++ while( count-- && ALWAYS(elem) ){
++ if( elem->nKey==nKey && sqlite3StrNICmp(elem->pKey,pKey,nKey)==0 ){
++ return elem;
+ }
++ elem = elem->next;
+ }
+-#endif
+-
+- unixLeaveMutex();
+- OSTRACE(("TEST WR-LOCK %d %d %d (unix)\n", pFile->h, rc, reserved));
+-
+- *pResOut = reserved;
+- return rc;
++ return 0;
+ }
+
+-/*
+-** Attempt to set a system-lock on the file pFile. The lock is
+-** described by pLock.
+-**
+-** If the pFile was opened read/write from unix-excl, then the only lock
+-** ever obtained is an exclusive lock, and it is obtained exactly once
+-** the first time any lock is attempted. All subsequent system locking
+-** operations become no-ops. Locking operations still happen internally,
+-** in order to coordinate access between separate database connections
+-** within this process, but all of that is handled in memory and the
+-** operating system does not participate.
+-**
+-** This function is a pass-through to fcntl(F_SETLK) if pFile is using
+-** any VFS other than "unix-excl" or if pFile is opened on "unix-excl"
+-** and is read-only.
+-**
+-** Zero is returned if the call completes successfully, or -1 if a call
+-** to fcntl() fails. In this case, errno is set appropriately (by fcntl()).
++/* Remove a single entry from the hash table given a pointer to that
++** element and a hash on the element's key.
+ */
+-static int unixFileLock(unixFile *pFile, struct flock *pLock){
+- int rc;
+- unixInodeInfo *pInode = pFile->pInode;
+- assert( unixMutexHeld() );
+- assert( pInode!=0 );
+- if( ((pFile->ctrlFlags & UNIXFILE_EXCL)!=0 || pInode->bProcessLock)
+- && ((pFile->ctrlFlags & UNIXFILE_RDONLY)==0)
+- ){
+- if( pInode->bProcessLock==0 ){
+- struct flock lock;
+- assert( pInode->nLock==0 );
+- lock.l_whence = SEEK_SET;
+- lock.l_start = SHARED_FIRST;
+- lock.l_len = SHARED_SIZE;
+- lock.l_type = F_WRLCK;
+- rc = osFcntl(pFile->h, F_SETLK, &lock);
+- if( rc<0 ) return rc;
+- pInode->bProcessLock = 1;
+- pInode->nLock++;
+- }else{
+- rc = 0;
++static void removeElementGivenHash(
++ Hash *pH, /* The pH containing "elem" */
++ HashElem* elem, /* The element to be removed from the pH */
++ unsigned int h /* Hash value for the element */
++){
++ struct _ht *pEntry;
++ if( elem->prev ){
++ elem->prev->next = elem->next;
++ }else{
++ pH->first = elem->next;
++ }
++ if( elem->next ){
++ elem->next->prev = elem->prev;
++ }
++ if( pH->ht ){
++ pEntry = &pH->ht[h];
++ if( pEntry->chain==elem ){
++ pEntry->chain = elem->next;
+ }
++ pEntry->count--;
++ assert( pEntry->count>=0 );
++ }
++ sqlite3_free( elem );
++ pH->count--;
++ if( pH->count==0 ){
++ assert( pH->first==0 );
++ assert( pH->count==0 );
++ sqlite3HashClear(pH);
++ }
++}
++
++/* 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
++** found, or NULL if there is no match.
++*/
++SQLITE_PRIVATE void *sqlite3HashFind(const Hash *pH, const char *pKey, int nKey){
++ 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{
+- rc = osFcntl(pFile->h, F_SETLK, pLock);
++ h = 0;
+ }
+- return rc;
++ elem = findElementGivenHash(pH, pKey, nKey, h);
++ return elem ? elem->data : 0;
+ }
+
+-/*
+-** Lock the file with the lock specified by parameter eFileLock - one
+-** of the following:
+-**
+-** (1) SHARED_LOCK
+-** (2) RESERVED_LOCK
+-** (3) PENDING_LOCK
+-** (4) EXCLUSIVE_LOCK
++/* Insert an element into the hash table pH. The key is pKey,nKey
++** and the data is "data".
+ **
+-** 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:
++** If no element exists with a matching key, then a new
++** element is created and NULL is returned.
+ **
+-** UNLOCKED -> SHARED
+-** SHARED -> RESERVED
+-** SHARED -> (PENDING) -> EXCLUSIVE
+-** RESERVED -> (PENDING) -> EXCLUSIVE
+-** PENDING -> EXCLUSIVE
++** If another element already exists with the same key, then the
++** new data replaces the old data and the old data is returned.
++** The key is not copied in this instance. If a malloc fails, then
++** the new data is returned and the hash table is unchanged.
+ **
+-** This routine will only increase a lock. Use the sqlite3OsUnlock()
+-** routine to lower a locking level.
++** If the "data" parameter to this function is NULL, then the
++** element corresponding to "key" is removed from the hash table.
+ */
+-static int unixLock(sqlite3_file *id, int eFileLock){
+- /* The following describes the implementation of the various locks and
+- ** lock transitions in terms of the POSIX advisory shared and exclusive
+- ** lock primitives (called read-locks and write-locks below, to avoid
+- ** confusion with SQLite lock names). The algorithms are complicated
+- ** slightly in order to be compatible with windows systems simultaneously
+- ** accessing the same database file, in case that is ever required.
+- **
+- ** Symbols defined in os.h indentify the 'pending byte' and the 'reserved
+- ** byte', each single bytes at well known offsets, and the 'shared byte
+- ** range', a range of 510 bytes at a well known offset.
+- **
+- ** To obtain a SHARED lock, a read-lock is obtained on the 'pending
+- ** byte'. If this is successful, a random byte from the 'shared byte
+- ** range' is read-locked and the lock on the 'pending byte' released.
+- **
+- ** A process may only obtain a RESERVED lock after it has a SHARED lock.
+- ** A RESERVED lock is implemented by grabbing a write-lock on the
+- ** 'reserved byte'.
+- **
+- ** A process may only obtain a PENDING lock after it has obtained a
+- ** SHARED lock. A PENDING lock is implemented by obtaining a write-lock
+- ** on the 'pending byte'. This ensures that no new SHARED locks can be
+- ** obtained, but existing SHARED locks are allowed to persist. A process
+- ** does not have to obtain a RESERVED lock on the way to a PENDING lock.
+- ** This property is used by the algorithm for rolling back a journal file
+- ** after a crash.
+- **
+- ** An EXCLUSIVE lock, obtained after a PENDING lock is held, is
+- ** implemented by obtaining a write-lock on the entire 'shared byte
+- ** range'. Since all other locks require a read-lock on one of the bytes
+- ** within this range, this ensures that no other locks are held on the
+- ** database.
+- **
+- ** The reason a single byte cannot be used instead of the 'shared byte
+- ** range' is that some versions of windows do not support read-locks. By
+- ** locking a random byte from a range, concurrent SHARED locks may exist
+- ** even if the locking primitive used is always a write-lock.
+- */
+- int rc = SQLITE_OK;
+- unixFile *pFile = (unixFile*)id;
+- unixInodeInfo *pInode;
+- struct flock lock;
+- int tErrno = 0;
+-
+- 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()));
++SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, int nKey, 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 */
+
+- /* 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
+- ** unixEnterMutex() hasn't been called yet.
+- */
+- if( pFile->eFileLock>=eFileLock ){
+- OSTRACE(("LOCK %d %s ok (already held) (unix)\n", pFile->h,
+- azFileLock(eFileLock)));
+- return SQLITE_OK;
++ assert( pH!=0 );
++ assert( pKey!=0 );
++ assert( nKey>=0 );
++ if( pH->htsize ){
++ h = strHash(pKey, nKey) % pH->htsize;
++ }else{
++ h = 0;
+ }
+-
+- /* Make sure the locking sequence is correct.
+- ** (1) We never move from unlocked to anything higher than shared lock.
+- ** (2) SQLite never explicitly requests a pendig lock.
+- ** (3) A shared lock is always held when a reserve lock is requested.
+- */
+- assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK );
+- assert( eFileLock!=PENDING_LOCK );
+- assert( eFileLock!=RESERVED_LOCK || pFile->eFileLock==SHARED_LOCK );
+-
+- /* This mutex is needed because pFile->pInode is shared across threads
+- */
+- unixEnterMutex();
+- pInode = pFile->pInode;
+-
+- /* If some thread using this PID has a lock via a different unixFile*
+- ** handle that precludes the requested lock, return BUSY.
+- */
+- if( (pFile->eFileLock!=pInode->eFileLock &&
+- (pInode->eFileLock>=PENDING_LOCK || eFileLock>SHARED_LOCK))
+- ){
+- rc = SQLITE_BUSY;
+- goto end_lock;
++ elem = findElementGivenHash(pH,pKey,nKey,h);
++ if( elem ){
++ void *old_data = elem->data;
++ if( data==0 ){
++ removeElementGivenHash(pH,elem,h);
++ }else{
++ elem->data = data;
++ elem->pKey = pKey;
++ assert(nKey==elem->nKey);
++ }
++ return old_data;
+ }
+-
+- /* If a SHARED lock is requested, and some thread using this PID already
+- ** has a SHARED or RESERVED lock, then increment reference counts and
+- ** return SQLITE_OK.
+- */
+- if( eFileLock==SHARED_LOCK &&
+- (pInode->eFileLock==SHARED_LOCK || pInode->eFileLock==RESERVED_LOCK) ){
+- assert( eFileLock==SHARED_LOCK );
+- assert( pFile->eFileLock==0 );
+- assert( pInode->nShared>0 );
+- pFile->eFileLock = SHARED_LOCK;
+- pInode->nShared++;
+- pInode->nLock++;
+- goto end_lock;
++ if( data==0 ) return 0;
++ 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;
++ }
++ }
++ if( pH->ht ){
++ insertElement(pH, &pH->ht[h], new_elem);
++ }else{
++ insertElement(pH, 0, new_elem);
+ }
++ return 0;
++}
+
++/************** End of hash.c ************************************************/
++/************** Begin file opcodes.c *****************************************/
++/* Automatically generated. Do not edit */
++/* See the mkopcodec.awk script for details. */
++#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
++SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
++ static const char *const azName[] = { "?",
++ /* 1 */ "Goto",
++ /* 2 */ "Gosub",
++ /* 3 */ "Return",
++ /* 4 */ "Yield",
++ /* 5 */ "HaltIfNull",
++ /* 6 */ "Halt",
++ /* 7 */ "Integer",
++ /* 8 */ "Int64",
++ /* 9 */ "String",
++ /* 10 */ "Null",
++ /* 11 */ "Blob",
++ /* 12 */ "Variable",
++ /* 13 */ "Move",
++ /* 14 */ "Copy",
++ /* 15 */ "SCopy",
++ /* 16 */ "ResultRow",
++ /* 17 */ "CollSeq",
++ /* 18 */ "Function",
++ /* 19 */ "Not",
++ /* 20 */ "AddImm",
++ /* 21 */ "MustBeInt",
++ /* 22 */ "RealAffinity",
++ /* 23 */ "Permutation",
++ /* 24 */ "Compare",
++ /* 25 */ "Jump",
++ /* 26 */ "Once",
++ /* 27 */ "If",
++ /* 28 */ "IfNot",
++ /* 29 */ "Column",
++ /* 30 */ "Affinity",
++ /* 31 */ "MakeRecord",
++ /* 32 */ "Count",
++ /* 33 */ "Savepoint",
++ /* 34 */ "AutoCommit",
++ /* 35 */ "Transaction",
++ /* 36 */ "ReadCookie",
++ /* 37 */ "SetCookie",
++ /* 38 */ "VerifyCookie",
++ /* 39 */ "OpenRead",
++ /* 40 */ "OpenWrite",
++ /* 41 */ "OpenAutoindex",
++ /* 42 */ "OpenEphemeral",
++ /* 43 */ "SorterOpen",
++ /* 44 */ "OpenPseudo",
++ /* 45 */ "Close",
++ /* 46 */ "SeekLt",
++ /* 47 */ "SeekLe",
++ /* 48 */ "SeekGe",
++ /* 49 */ "SeekGt",
++ /* 50 */ "Seek",
++ /* 51 */ "NotFound",
++ /* 52 */ "Found",
++ /* 53 */ "IsUnique",
++ /* 54 */ "NotExists",
++ /* 55 */ "Sequence",
++ /* 56 */ "NewRowid",
++ /* 57 */ "Insert",
++ /* 58 */ "InsertInt",
++ /* 59 */ "Delete",
++ /* 60 */ "ResetCount",
++ /* 61 */ "SorterCompare",
++ /* 62 */ "SorterData",
++ /* 63 */ "RowKey",
++ /* 64 */ "RowData",
++ /* 65 */ "Rowid",
++ /* 66 */ "NullRow",
++ /* 67 */ "Last",
++ /* 68 */ "Or",
++ /* 69 */ "And",
++ /* 70 */ "SorterSort",
++ /* 71 */ "Sort",
++ /* 72 */ "Rewind",
++ /* 73 */ "IsNull",
++ /* 74 */ "NotNull",
++ /* 75 */ "Ne",
++ /* 76 */ "Eq",
++ /* 77 */ "Gt",
++ /* 78 */ "Le",
++ /* 79 */ "Lt",
++ /* 80 */ "Ge",
++ /* 81 */ "SorterNext",
++ /* 82 */ "BitAnd",
++ /* 83 */ "BitOr",
++ /* 84 */ "ShiftLeft",
++ /* 85 */ "ShiftRight",
++ /* 86 */ "Add",
++ /* 87 */ "Subtract",
++ /* 88 */ "Multiply",
++ /* 89 */ "Divide",
++ /* 90 */ "Remainder",
++ /* 91 */ "Concat",
++ /* 92 */ "Prev",
++ /* 93 */ "BitNot",
++ /* 94 */ "String8",
++ /* 95 */ "Next",
++ /* 96 */ "SorterInsert",
++ /* 97 */ "IdxInsert",
++ /* 98 */ "IdxDelete",
++ /* 99 */ "IdxRowid",
++ /* 100 */ "IdxLT",
++ /* 101 */ "IdxGE",
++ /* 102 */ "Destroy",
++ /* 103 */ "Clear",
++ /* 104 */ "CreateIndex",
++ /* 105 */ "CreateTable",
++ /* 106 */ "ParseSchema",
++ /* 107 */ "LoadAnalysis",
++ /* 108 */ "DropTable",
++ /* 109 */ "DropIndex",
++ /* 110 */ "DropTrigger",
++ /* 111 */ "IntegrityCk",
++ /* 112 */ "RowSetAdd",
++ /* 113 */ "RowSetRead",
++ /* 114 */ "RowSetTest",
++ /* 115 */ "Program",
++ /* 116 */ "Param",
++ /* 117 */ "FkCounter",
++ /* 118 */ "FkIfZero",
++ /* 119 */ "MemMax",
++ /* 120 */ "IfPos",
++ /* 121 */ "IfNeg",
++ /* 122 */ "IfZero",
++ /* 123 */ "AggStep",
++ /* 124 */ "AggFinal",
++ /* 125 */ "Checkpoint",
++ /* 126 */ "JournalMode",
++ /* 127 */ "Vacuum",
++ /* 128 */ "IncrVacuum",
++ /* 129 */ "Expire",
++ /* 130 */ "Real",
++ /* 131 */ "TableLock",
++ /* 132 */ "VBegin",
++ /* 133 */ "VCreate",
++ /* 134 */ "VDestroy",
++ /* 135 */ "VOpen",
++ /* 136 */ "VFilter",
++ /* 137 */ "VColumn",
++ /* 138 */ "VNext",
++ /* 139 */ "VRename",
++ /* 140 */ "VUpdate",
++ /* 141 */ "ToText",
++ /* 142 */ "ToBlob",
++ /* 143 */ "ToNumeric",
++ /* 144 */ "ToInt",
++ /* 145 */ "ToReal",
++ /* 146 */ "Pagecount",
++ /* 147 */ "MaxPgcnt",
++ /* 148 */ "Trace",
++ /* 149 */ "Noop",
++ /* 150 */ "Explain",
++ };
++ return azName[i];
++}
++#endif
+
+- /* A PENDING lock is needed before acquiring a SHARED lock and before
+- ** acquiring an EXCLUSIVE lock. For the SHARED lock, the PENDING will
+- ** be released.
+- */
+- lock.l_len = 1L;
+- lock.l_whence = SEEK_SET;
+- if( eFileLock==SHARED_LOCK
+- || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock<PENDING_LOCK)
+- ){
+- lock.l_type = (eFileLock==SHARED_LOCK?F_RDLCK:F_WRLCK);
+- lock.l_start = PENDING_BYTE;
+- if( unixFileLock(pFile, &lock) ){
+- tErrno = errno;
+- rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
+- if( rc!=SQLITE_BUSY ){
+- pFile->lastErrno = tErrno;
+- }
+- goto end_lock;
+- }
+- }
++/************** End of opcodes.c *********************************************/
++/************** Begin file os_unix.c *****************************************/
++/*
++** 2004 May 22
++**
++** 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 VFS implementation for unix-like operating systems
++** include Linux, MacOSX, *BSD, QNX, VxWorks, AIX, HPUX, and others.
++**
++** There are actually several different VFS implementations in this file.
++** The differences are in the way that file locking is done. The default
++** implementation uses Posix Advisory Locks. Alternative implementations
++** use flock(), dot-files, various proprietary locking schemas, or simply
++** skip locking all together.
++**
++** This source file is organized into divisions where the logic for various
++** subfunctions is contained within the appropriate division. PLEASE
++** KEEP THE STRUCTURE OF THIS FILE INTACT. New code should be placed
++** in the correct division and should be clearly labeled.
++**
++** The layout of divisions is as follows:
++**
++** * General-purpose declarations and utility functions.
++** * Unique file ID logic used by VxWorks.
++** * Various locking primitive implementations (all except proxy locking):
++** + for Posix Advisory Locks
++** + for no-op locks
++** + for dot-file locks
++** + for flock() locking
++** + for named semaphore locks (VxWorks only)
++** + for AFP filesystem locks (MacOSX only)
++** * sqlite3_file methods not associated with locking.
++** * Definitions of sqlite3_io_methods objects for all locking
++** methods plus "finder" functions for each locking method.
++** * sqlite3_vfs method implementations.
++** * Locking primitives for the proxy uber-locking-method. (MacOSX only)
++** * Definitions of sqlite3_vfs objects for all locking methods
++** plus implementations of sqlite3_os_init() and sqlite3_os_end().
++*/
++#if SQLITE_OS_UNIX /* This file is used on unix only */
+
++/* Use posix_fallocate() if it is available
++*/
++#if !defined(HAVE_POSIX_FALLOCATE) \
++ && (_XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L)
++# define HAVE_POSIX_FALLOCATE 1
++#endif
+
+- /* If control gets to this point, then actually go ahead and make
+- ** operating system calls for the specified lock.
+- */
+- if( eFileLock==SHARED_LOCK ){
+- assert( pInode->nShared==0 );
+- assert( pInode->eFileLock==0 );
+- assert( rc==SQLITE_OK );
++/*
++** There are various methods for file locking used for concurrency
++** control:
++**
++** 1. POSIX locking (the default),
++** 2. No locking,
++** 3. Dot-file locking,
++** 4. flock() locking,
++** 5. AFP locking (OSX only),
++** 6. Named POSIX semaphores (VXWorks only),
++** 7. proxy locking. (OSX only)
++**
++** Styles 4, 5, and 7 are only available of SQLITE_ENABLE_LOCKING_STYLE
++** is defined to 1. The SQLITE_ENABLE_LOCKING_STYLE also enables automatic
++** selection of the appropriate locking style based on the filesystem
++** where the database is located.
++*/
++#if !defined(SQLITE_ENABLE_LOCKING_STYLE)
++# if defined(__APPLE__)
++# define SQLITE_ENABLE_LOCKING_STYLE 1
++# else
++# define SQLITE_ENABLE_LOCKING_STYLE 0
++# endif
++#endif
+
+- /* Now get the read-lock */
+- lock.l_start = SHARED_FIRST;
+- lock.l_len = SHARED_SIZE;
+- if( unixFileLock(pFile, &lock) ){
+- tErrno = errno;
+- rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
+- }
++/*
++** 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
+
+- /* Drop the temporary PENDING lock */
+- lock.l_start = PENDING_BYTE;
+- lock.l_len = 1L;
+- lock.l_type = F_UNLCK;
+- if( unixFileLock(pFile, &lock) && rc==SQLITE_OK ){
+- /* This could happen with a network mount */
+- tErrno = errno;
+- rc = SQLITE_IOERR_UNLOCK;
+- }
++/*
++** These #defines should enable >2GB file support on Posix if the
++** underlying operating system supports it. If the OS lacks
++** large file support, these should be no-ops.
++**
++** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch
++** on the compiler command line. This is necessary if you are compiling
++** on a recent machine (ex: RedHat 7.2) but you want your code to work
++** on an older machine (ex: RedHat 6.0). If you compile on RedHat 7.2
++** without this option, LFS is enable. But LFS does not exist in the kernel
++** in RedHat 6.0, so the code won't work. Hence, for maximum binary
++** portability you should omit LFS.
++**
++** The previous paragraph was written in 2005. (This paragraph is written
++** on 2008-11-28.) These days, all Linux kernels support large files, so
++** you should probably leave LFS enabled. But some embedded platforms might
++** lack LFS in which case the SQLITE_DISABLE_LFS macro might still be useful.
++*/
++#ifndef SQLITE_DISABLE_LFS
++# define _LARGE_FILE 1
++# ifndef _FILE_OFFSET_BITS
++# define _FILE_OFFSET_BITS 64
++# endif
++# define _LARGEFILE_SOURCE 1
++#endif
+
+- if( rc ){
+- if( rc!=SQLITE_BUSY ){
+- pFile->lastErrno = tErrno;
+- }
+- goto end_lock;
+- }else{
+- pFile->eFileLock = SHARED_LOCK;
+- pInode->nLock++;
+- pInode->nShared = 1;
+- }
+- }else if( eFileLock==EXCLUSIVE_LOCK && pInode->nShared>1 ){
+- /* We are trying for an exclusive lock but another thread in this
+- ** same process is still holding a shared lock. */
+- rc = SQLITE_BUSY;
+- }else{
+- /* The request was for a RESERVED or EXCLUSIVE lock. It is
+- ** assumed that there is a SHARED or greater lock on the file
+- ** already.
+- */
+- assert( 0!=pFile->eFileLock );
+- lock.l_type = F_WRLCK;
++/*
++** standard include files.
++*/
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++#include <unistd.h>
++/* #include <time.h> */
++#include <sys/time.h>
++#include <errno.h>
++#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
+/* #include <sys/mman.h> */
++#endif
+
+- assert( eFileLock==RESERVED_LOCK || eFileLock==EXCLUSIVE_LOCK );
+- if( eFileLock==RESERVED_LOCK ){
+- lock.l_start = RESERVED_BYTE;
+- lock.l_len = 1L;
+- }else{
+- lock.l_start = SHARED_FIRST;
+- lock.l_len = SHARED_SIZE;
+- }
+
+- if( unixFileLock(pFile, &lock) ){
+- tErrno = errno;
+- rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
+- if( rc!=SQLITE_BUSY ){
+- pFile->lastErrno = tErrno;
+- }
+- }
+- }
+-
++#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
++#endif /* SQLITE_ENABLE_LOCKING_STYLE */
+
+-#ifdef SQLITE_DEBUG
+- /* Set up the transaction-counter change checking flags when
+- ** transitioning from a SHARED to a RESERVED lock. The change
+- ** from SHARED to RESERVED marks the beginning of a normal
+- ** write operation (not a hot journal rollback).
+- */
+- if( rc==SQLITE_OK
+- && pFile->eFileLock<=SHARED_LOCK
+- && eFileLock==RESERVED_LOCK
+- ){
+- pFile->transCntrChng = 0;
+- pFile->dbUpdate = 0;
+- pFile->inNormalWrite = 1;
+- }
++#if defined(__APPLE__) || (SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS)
++# include <sys/mount.h>
+ #endif
+
+-
+- if( rc==SQLITE_OK ){
+- pFile->eFileLock = eFileLock;
+- pInode->eFileLock = eFileLock;
+- }else if( eFileLock==EXCLUSIVE_LOCK ){
+- pFile->eFileLock = PENDING_LOCK;
+- pInode->eFileLock = PENDING_LOCK;
+- }
+-
+-end_lock:
+- unixLeaveMutex();
+- OSTRACE(("LOCK %d %s %s (unix)\n", pFile->h, azFileLock(eFileLock),
+- rc==SQLITE_OK ? "ok" : "failed"));
+- return rc;
+-}
++#ifdef HAVE_UTIME
++# include <utime.h>
++#endif
+
+ /*
+-** Add the file descriptor used by file handle pFile to the corresponding
+-** pUnused list.
++** Allowed values of unixFile.fsFlags
+ */
+-static void setPendingFd(unixFile *pFile){
+- unixInodeInfo *pInode = pFile->pInode;
+- UnixUnusedFd *p = pFile->pUnused;
+- p->pNext = pInode->pUnused;
+- pInode->pUnused = p;
+- pFile->h = -1;
+- pFile->pUnused = 0;
+-}
++#define SQLITE_FSFLAGS_IS_MSDOS 0x1
+
+ /*
+-** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
+-** 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.
+-**
+-** If handleNFSUnlock is true, then on downgrading an EXCLUSIVE_LOCK to SHARED
+-** the byte range is divided into 2 parts and the first part is unlocked then
+-** set to a read lock, then the other part is simply unlocked. This works
+-** around a bug in BSD NFS lockd (also seen on MacOSX 10.3+) that fails to
+-** remove the write lock on a region when a read lock is set.
++** If we are to be thread-safe, include the pthreads header and define
++** the SQLITE_UNIX_THREADS macro.
+ */
+-static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
+- unixFile *pFile = (unixFile*)id;
+- unixInodeInfo *pInode;
+- struct flock lock;
+- int rc = SQLITE_OK;
+-
+- 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()));
+-
+- assert( eFileLock<=SHARED_LOCK );
+- if( pFile->eFileLock<=eFileLock ){
+- return SQLITE_OK;
+- }
+- unixEnterMutex();
+- pInode = pFile->pInode;
+- assert( pInode->nShared!=0 );
+- if( pFile->eFileLock>SHARED_LOCK ){
+- assert( pInode->eFileLock==pFile->eFileLock );
+-
+-#ifdef SQLITE_DEBUG
+- /* When reducing a lock such that other processes can start
+- ** reading the database file again, make sure that the
+- ** transaction counter was updated if any part of the database
+- ** file changed. If the transaction counter is not updated,
+- ** other connections to the same file might not realize that
+- ** the file has changed and hence might not know to flush their
+- ** cache. The use of a stale cache can lead to database corruption.
+- */
+- pFile->inNormalWrite = 0;
++#if SQLITE_THREADSAFE
++/* # include <pthread.h> */
++# define SQLITE_UNIX_THREADS 1
+ #endif
+
+- /* downgrading to a shared lock on NFS involves clearing the write lock
+- ** before establishing the readlock - to avoid a race condition we downgrade
+- ** the lock in 2 blocks, so that part of the range will be covered by a
+- ** write lock until the rest is covered by a read lock:
+- ** 1: [WWWWW]
+- ** 2: [....W]
+- ** 3: [RRRRW]
+- ** 4: [RRRR.]
+- */
+- if( eFileLock==SHARED_LOCK ){
+-
+-#if !defined(__APPLE__) || !SQLITE_ENABLE_LOCKING_STYLE
+- (void)handleNFSUnlock;
+- assert( handleNFSUnlock==0 );
++/*
++** Default permissions when creating a new file
++*/
++#ifndef SQLITE_DEFAULT_FILE_PERMISSIONS
++# define SQLITE_DEFAULT_FILE_PERMISSIONS 0644
+ #endif
+-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
+- if( handleNFSUnlock ){
+- int tErrno; /* Error code from system call errors */
+- off_t divSize = SHARED_SIZE - 1;
+-
+- lock.l_type = F_UNLCK;
+- lock.l_whence = SEEK_SET;
+- lock.l_start = SHARED_FIRST;
+- lock.l_len = divSize;
+- if( unixFileLock(pFile, &lock)==(-1) ){
+- tErrno = errno;
+- rc = SQLITE_IOERR_UNLOCK;
+- if( IS_LOCK_ERROR(rc) ){
+- pFile->lastErrno = tErrno;
+- }
+- goto end_unlock;
+- }
+- lock.l_type = F_RDLCK;
+- lock.l_whence = SEEK_SET;
+- lock.l_start = SHARED_FIRST;
+- lock.l_len = divSize;
+- if( unixFileLock(pFile, &lock)==(-1) ){
+- tErrno = errno;
+- rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);
+- if( IS_LOCK_ERROR(rc) ){
+- pFile->lastErrno = tErrno;
+- }
+- goto end_unlock;
+- }
+- lock.l_type = F_UNLCK;
+- lock.l_whence = SEEK_SET;
+- lock.l_start = SHARED_FIRST+divSize;
+- lock.l_len = SHARED_SIZE-divSize;
+- if( unixFileLock(pFile, &lock)==(-1) ){
+- tErrno = errno;
+- rc = SQLITE_IOERR_UNLOCK;
+- if( IS_LOCK_ERROR(rc) ){
+- pFile->lastErrno = tErrno;
+- }
+- goto end_unlock;
+- }
+- }else
+-#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
+- {
+- lock.l_type = F_RDLCK;
+- lock.l_whence = SEEK_SET;
+- lock.l_start = SHARED_FIRST;
+- lock.l_len = SHARED_SIZE;
+- if( unixFileLock(pFile, &lock) ){
+- /* In theory, the call to unixFileLock() cannot fail because another
+- ** process is holding an incompatible lock. If it does, this
+- ** indicates that the other process is not following the locking
+- ** protocol. If this happens, return SQLITE_IOERR_RDLOCK. Returning
+- ** SQLITE_BUSY would confuse the upper layer (in practice it causes
+- ** an assert to fail). */
+- rc = SQLITE_IOERR_RDLOCK;
+- pFile->lastErrno = errno;
+- goto end_unlock;
+- }
+- }
+- }
+- lock.l_type = F_UNLCK;
+- lock.l_whence = SEEK_SET;
+- lock.l_start = PENDING_BYTE;
+- lock.l_len = 2L; assert( PENDING_BYTE+1==RESERVED_BYTE );
+- if( unixFileLock(pFile, &lock)==0 ){
+- pInode->eFileLock = SHARED_LOCK;
+- }else{
+- rc = SQLITE_IOERR_UNLOCK;
+- pFile->lastErrno = errno;
+- goto end_unlock;
+- }
+- }
+- if( eFileLock==NO_LOCK ){
+- /* Decrement the shared lock counter. Release the lock using an
+- ** OS call only when all threads in this same process have released
+- ** the lock.
+- */
+- pInode->nShared--;
+- if( pInode->nShared==0 ){
+- lock.l_type = F_UNLCK;
+- lock.l_whence = SEEK_SET;
+- lock.l_start = lock.l_len = 0L;
+- if( unixFileLock(pFile, &lock)==0 ){
+- pInode->eFileLock = NO_LOCK;
+- }else{
+- rc = SQLITE_IOERR_UNLOCK;
+- pFile->lastErrno = errno;
+- pInode->eFileLock = NO_LOCK;
+- pFile->eFileLock = NO_LOCK;
+- }
+- }
+-
+- /* Decrement the count of locks against this same file. When the
+- ** count reaches zero, close any other file descriptors whose close
+- ** was deferred because of outstanding locks.
+- */
+- pInode->nLock--;
+- assert( pInode->nLock>=0 );
+- if( pInode->nLock==0 ){
+- closePendingFds(pFile);
+- }
+- }
+-
+-end_unlock:
+- unixLeaveMutex();
+- if( rc==SQLITE_OK ) pFile->eFileLock = eFileLock;
+- return rc;
+-}
+
+ /*
+-** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
+-** 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.
++** Default permissions when creating auto proxy dir
+ */
+-static int unixUnlock(sqlite3_file *id, int eFileLock){
+- assert( eFileLock==SHARED_LOCK || ((unixFile *)id)->nFetchOut==0 );
+- return posixUnlock(id, eFileLock, 0);
+-}
++#ifndef SQLITE_DEFAULT_PROXYDIR_PERMISSIONS
++# define SQLITE_DEFAULT_PROXYDIR_PERMISSIONS 0755
++#endif
+
+-static int unixMapfile(unixFile *pFd, i64 nByte);
+-static void unixUnmapfile(unixFile *pFd);
++/*
++** Maximum supported path-length.
++*/
++#define MAX_PATHNAME 512
+
+ /*
+-** This function performs the parts of the "close file" operation
+-** common to all locking schemes. It closes the directory and file
+-** handles, if they are valid, and sets all fields of the unixFile
+-** structure to 0.
+-**
+-** It is *not* necessary to hold the mutex when this routine is called,
+-** even on VxWorks. A mutex will be acquired on VxWorks by the
+-** vxworksReleaseFileId() routine.
++** 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
+ */
+-static int closeUnixFile(sqlite3_file *id){
+- unixFile *pFile = (unixFile*)id;
+- unixUnmapfile(pFile);
+- if( pFile->h>=0 ){
+- robust_close(pFile, pFile->h, __LINE__);
+- pFile->h = -1;
+- }
+-#if OS_VXWORKS
+- if( pFile->pId ){
+- if( pFile->ctrlFlags & UNIXFILE_DELETE ){
+- osUnlink(pFile->pId->zCanonicalName);
+- }
+- vxworksReleaseFileId(pFile->pId);
+- pFile->pId = 0;
+- }
+-#endif
+- OSTRACE(("CLOSE %-3d\n", pFile->h));
+- OpenCounter(-1);
+- sqlite3_free(pFile->pUnused);
+- memset(pFile, 0, sizeof(unixFile));
+- return SQLITE_OK;
+-}
++#define IS_LOCK_ERROR(x) ((x != SQLITE_OK) && (x != SQLITE_BUSY))
++
++/* Forward references */
++typedef struct unixShm unixShm; /* Connection shared memory */
++typedef struct unixShmNode unixShmNode; /* Shared memory instance */
++typedef struct unixInodeInfo unixInodeInfo; /* An i-node */
++typedef struct UnixUnusedFd UnixUnusedFd; /* An unused file descriptor */
+
+ /*
+-** Close a file.
++** Sometimes, after a file handle is closed by SQLite, the file descriptor
++** cannot be closed immediately. In these cases, instances of the following
++** structure are used to store the file descriptor while waiting for an
++** opportunity to either close or reuse it.
+ */
+-static int unixClose(sqlite3_file *id){
+- int rc = SQLITE_OK;
+- unixFile *pFile = (unixFile *)id;
+- verifyDbFile(pFile);
+- unixUnlock(id, NO_LOCK);
+- unixEnterMutex();
++struct UnixUnusedFd {
++ int fd; /* File descriptor to close */
++ int flags; /* Flags this file descriptor was opened with */
++ UnixUnusedFd *pNext; /* Next unused file descriptor on same file */
++};
+
+- /* unixFile.pInode is always valid here. Otherwise, a different close
+- ** routine (e.g. nolockClose()) would be called instead.
++/*
++** The unixFile structure is subclass of sqlite3_file specific to the unix
++** VFS implementations.
++*/
++typedef struct unixFile unixFile;
++struct unixFile {
++ sqlite3_io_methods const *pMethod; /* Always the first entry */
++ sqlite3_vfs *pVfs; /* The VFS that created this unixFile */
++ unixInodeInfo *pInode; /* Info about locks on this inode */
++ int h; /* The file descriptor */
++ unsigned char eFileLock; /* The type of lock held on this fd */
++ unsigned short int ctrlFlags; /* Behavioral bits. UNIXFILE_* flags */
++ int lastErrno; /* The unix errno from last I/O error */
++ void *lockingContext; /* Locking style specific state */
++ UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */
++ const char *zPath; /* Name of the file */
++ unixShm *pShm; /* Shared memory segment information */
++ int szChunk; /* Configured by FCNTL_CHUNK_SIZE */
++ int nFetchOut; /* Number of outstanding xFetch refs */
++ sqlite3_int64 mmapSize; /* Usable size of mapping at pMapRegion */
++ sqlite3_int64 mmapSizeActual; /* Actual size of mapping at pMapRegion */
++ sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */
++ void *pMapRegion; /* Memory mapped region */
++#ifdef __QNXNTO__
++ int sectorSize; /* Device sector size */
++ int deviceCharacteristics; /* Precomputed device characteristics */
++#endif
++#if SQLITE_ENABLE_LOCKING_STYLE
++ int openFlags; /* The flags specified at open() */
++#endif
++#if SQLITE_ENABLE_LOCKING_STYLE || defined(__APPLE__)
++ unsigned fsFlags; /* cached details from statfs() */
++#endif
++#if OS_VXWORKS
++ struct vxworksFileId *pId; /* Unique file ID */
++#endif
++#ifdef SQLITE_DEBUG
++ /* The next group of variables are used to track whether or not the
++ ** transaction counter in bytes 24-27 of database files are updated
++ ** whenever any part of the database changes. An assertion fault will
++ ** occur if a file is updated without also updating the transaction
++ ** counter. This test is made to avoid new problems similar to the
++ ** one described by ticket #3584.
+ */
+- assert( pFile->pInode->nLock>0 || pFile->pInode->bProcessLock==0 );
+- if( ALWAYS(pFile->pInode) && pFile->pInode->nLock ){
+- /* If there are outstanding locks, do not actually close the file just
+- ** yet because that would clear those locks. Instead, add the file
+- ** descriptor to pInode->pUnused list. It will be automatically closed
+- ** when the last lock is cleared.
+- */
+- setPendingFd(pFile);
+- }
+- releaseInodeInfo(pFile);
+- rc = closeUnixFile(id);
+- unixLeaveMutex();
+- return rc;
+-}
+-
+-/************** End of the posix advisory lock implementation *****************
+-******************************************************************************/
++ unsigned char transCntrChng; /* True if the transaction counter changed */
++ unsigned char dbUpdate; /* True if any part of database file changed */
++ unsigned char inNormalWrite; /* True if in a normal write operation */
+
+-/******************************************************************************
+-****************************** No-op Locking **********************************
+-**
+-** Of the various locking implementations available, this is by far the
+-** simplest: locking is ignored. No attempt is made to lock the database
+-** file for reading or writing.
+-**
+-** This locking mode is appropriate for use on read-only databases
+-** (ex: databases that are burned into CD-ROM, for example.) It can
+-** also be used if the application employs some external mechanism to
+-** prevent simultaneous access of the same database by two or more
+-** database connections. But there is a serious risk of database
+-** corruption if this locking mode is used in situations where multiple
+-** database connections are accessing the same database file at the same
+-** time and one or more of those connections are writing.
+-*/
++#endif
+
+-static int nolockCheckReservedLock(sqlite3_file *NotUsed, int *pResOut){
+- UNUSED_PARAMETER(NotUsed);
+- *pResOut = 0;
+- return SQLITE_OK;
+-}
+-static int nolockLock(sqlite3_file *NotUsed, int NotUsed2){
+- UNUSED_PARAMETER2(NotUsed, NotUsed2);
+- return SQLITE_OK;
+-}
+-static int nolockUnlock(sqlite3_file *NotUsed, int NotUsed2){
+- UNUSED_PARAMETER2(NotUsed, NotUsed2);
+- return SQLITE_OK;
+-}
++#ifdef SQLITE_TEST
++ /* In test mode, increase the size of this structure a bit so that
++ ** it is larger than the struct CrashFile defined in test6.c.
++ */
++ char aPadding[32];
++#endif
++};
+
+ /*
+-** Close the file.
++** Allowed values for the unixFile.ctrlFlags bitmask:
+ */
+-static int nolockClose(sqlite3_file *id) {
+- return closeUnixFile(id);
+-}
+-
+-/******************* End of the no-op lock implementation *********************
+-******************************************************************************/
++#define UNIXFILE_EXCL 0x01 /* Connections from one process only */
++#define UNIXFILE_RDONLY 0x02 /* Connection is read only */
++#define UNIXFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */
++#ifndef SQLITE_DISABLE_DIRSYNC
++# define UNIXFILE_DIRSYNC 0x08 /* Directory sync needed */
++#else
++# define UNIXFILE_DIRSYNC 0x00
++#endif
++#define UNIXFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */
++#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 */
+
+-/******************************************************************************
+-************************* Begin dot-file Locking ******************************
++/*
++** Include code that is common to all os_*.c files
++*/
++/************** Include os_common.h in the middle of os_unix.c ***************/
++/************** Begin file os_common.h ***************************************/
++/*
++** 2004 May 22
+ **
+-** The dotfile locking implementation uses the existence of separate lock
+-** files (really a directory) to control access to the database. This works
+-** on just about every filesystem imaginable. But there are serious downsides:
++** The author disclaims copyright to this source code. In place of
++** a legal notice, here is a blessing:
+ **
+-** (1) There is zero concurrency. A single reader blocks all other
+-** connections from reading or writing the database.
++** 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.
+ **
+-** (2) An application crash or power loss can leave stale lock files
+-** sitting around that need to be cleared manually.
++******************************************************************************
+ **
+-** Nevertheless, a dotlock is an appropriate locking mode for use if no
+-** other locking strategy is available.
++** This file contains macros and a little bit of code that is common to
++** all of the platform-specific files (os_*.c) and is #included into those
++** files.
+ **
+-** Dotfile locking works by creating a subdirectory in the same directory as
+-** the database and with the same name but with a ".lock" extension added.
+-** The existence of a lock directory implies an EXCLUSIVE lock. All other
+-** lock types (SHARED, RESERVED, PENDING) are mapped into EXCLUSIVE.
++** This file should be #included by the os_*.c files only. It is not a
++** general purpose header file.
+ */
++#ifndef _OS_COMMON_H_
++#define _OS_COMMON_H_
+
+ /*
+-** The file suffix added to the data base filename in order to create the
+-** lock directory.
++** At least two bugs have slipped in because we changed the MEMORY_DEBUG
++** macro to SQLITE_DEBUG and some older makefiles have not yet made the
++** switch. The following code should catch this problem at compile-time.
+ */
+-#define DOTLOCK_SUFFIX ".lock"
++#ifdef MEMORY_DEBUG
++# 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
+
+ /*
+-** 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, set *pResOut
+-** 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.
+-**
+-** In dotfile locking, either a lock exists or it does not. So in this
+-** variation of CheckReservedLock(), *pResOut is set to true if any lock
+-** is held on the file and false if the file is unlocked.
++** Macros for performance tracing. Normally turned off. Only works
++** on i486 hardware.
+ */
+-static int dotlockCheckReservedLock(sqlite3_file *id, int *pResOut) {
+- int rc = SQLITE_OK;
+- int reserved = 0;
+- unixFile *pFile = (unixFile*)id;
+-
+- SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
+-
+- assert( pFile );
+-
+- /* Check if a thread in this process holds such a lock */
+- if( pFile->eFileLock>SHARED_LOCK ){
+- /* Either this connection or some other connection in the same process
+- ** holds a lock on the file. No need to check further. */
+- reserved = 1;
+- }else{
+- /* The lock is held if and only if the lockfile exists */
+- const char *zLockFile = (const char*)pFile->lockingContext;
+- reserved = osAccess(zLockFile, 0)==0;
+- }
+- OSTRACE(("TEST WR-LOCK %d %d %d (dotlock)\n", pFile->h, rc, reserved));
+- *pResOut = reserved;
+- return rc;
+-}
++#ifdef SQLITE_PERFORMANCE_TRACE
+
++/*
++** hwtime.h contains inline assembler code for implementing
++** high-performance timing routines.
++*/
++/************** Include hwtime.h in the middle of os_common.h ****************/
++/************** Begin file hwtime.h ******************************************/
+ /*
+-** Lock the file with the lock specified by parameter eFileLock - one
+-** of the following:
+-**
+-** (1) SHARED_LOCK
+-** (2) RESERVED_LOCK
+-** (3) PENDING_LOCK
+-** (4) EXCLUSIVE_LOCK
++** 2008 May 27
+ **
+-** 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:
++** The author disclaims copyright to this source code. In place of
++** a legal notice, here is a blessing:
+ **
+-** UNLOCKED -> SHARED
+-** SHARED -> RESERVED
+-** SHARED -> (PENDING) -> EXCLUSIVE
+-** RESERVED -> (PENDING) -> EXCLUSIVE
+-** PENDING -> EXCLUSIVE
++** 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 routine will only increase a lock. Use the sqlite3OsUnlock()
+-** routine to lower a locking level.
++******************************************************************************
+ **
+-** With dotfile locking, we really only support state (4): EXCLUSIVE.
+-** But we track the other locking levels internally.
++** This file contains inline asm code for retrieving "high-performance"
++** counters for x86 class CPUs.
+ */
+-static int dotlockLock(sqlite3_file *id, int eFileLock) {
+- unixFile *pFile = (unixFile*)id;
+- char *zLockFile = (char *)pFile->lockingContext;
+- int rc = SQLITE_OK;
++#ifndef _HWTIME_H_
++#define _HWTIME_H_
+
++/*
++** The following routine only works on pentium-class (or newer) processors.
++** It uses the RDTSC opcode to read the cycle count value out of the
++** processor and returns that value. This can be used for high-res
++** profiling.
++*/
++#if (defined(__GNUC__) || defined(_MSC_VER)) && \
++ (defined(i386) || defined(__i386__) || defined(_M_IX86))
+
+- /* If we have any lock, then the lock file already exists. All we have
+- ** to do is adjust our internal record of the lock level.
+- */
+- if( pFile->eFileLock > NO_LOCK ){
+- pFile->eFileLock = eFileLock;
+- /* Always update the timestamp on the old file */
+-#ifdef HAVE_UTIME
+- utime(zLockFile, NULL);
+-#else
+- utimes(zLockFile, NULL);
+-#endif
+- return SQLITE_OK;
++ #if defined(__GNUC__)
++
++ __inline__ sqlite_uint64 sqlite3Hwtime(void){
++ unsigned int lo, hi;
++ __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
++ return (sqlite_uint64)hi << 32 | lo;
+ }
+-
+- /* grab an exclusive lock */
+- rc = osMkdir(zLockFile, 0777);
+- if( rc<0 ){
+- /* failed to open/create the lock directory */
+- int tErrno = errno;
+- if( EEXIST == tErrno ){
+- rc = SQLITE_BUSY;
+- } else {
+- rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
+- if( IS_LOCK_ERROR(rc) ){
+- pFile->lastErrno = tErrno;
+- }
+- }
+- return rc;
+- }
+-
+- /* got it, set the type and return ok */
+- pFile->eFileLock = eFileLock;
+- return rc;
+-}
+
+-/*
+-** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
+-** 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.
+-**
+-** When the locking level reaches NO_LOCK, delete the lock file.
+-*/
+-static int dotlockUnlock(sqlite3_file *id, int eFileLock) {
+- unixFile *pFile = (unixFile*)id;
+- char *zLockFile = (char *)pFile->lockingContext;
+- int rc;
++ #elif defined(_MSC_VER)
+
+- assert( pFile );
+- OSTRACE(("UNLOCK %d %d was %d pid=%d (dotlock)\n", pFile->h, eFileLock,
+- pFile->eFileLock, getpid()));
+- assert( eFileLock<=SHARED_LOCK );
+-
+- /* no-op if possible */
+- if( pFile->eFileLock==eFileLock ){
+- return SQLITE_OK;
++ __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){
++ __asm {
++ rdtsc
++ ret ; return value at EDX:EAX
++ }
+ }
+
+- /* To downgrade to shared, simply update our internal notion of the
+- ** lock state. No need to mess with the file on disk.
+- */
+- if( eFileLock==SHARED_LOCK ){
+- pFile->eFileLock = SHARED_LOCK;
+- return SQLITE_OK;
++ #endif
++
++#elif (defined(__GNUC__) && defined(__x86_64__))
++
++ __inline__ sqlite_uint64 sqlite3Hwtime(void){
++ unsigned long val;
++ __asm__ __volatile__ ("rdtsc" : "=A" (val));
++ return val;
+ }
+-
+- /* To fully unlock the database, delete the lock file */
+- assert( eFileLock==NO_LOCK );
+- rc = osRmdir(zLockFile);
+- if( rc<0 && errno==ENOTDIR ) rc = osUnlink(zLockFile);
+- if( rc<0 ){
+- int tErrno = errno;
+- rc = 0;
+- if( ENOENT != tErrno ){
+- rc = SQLITE_IOERR_UNLOCK;
+- }
+- if( IS_LOCK_ERROR(rc) ){
+- pFile->lastErrno = tErrno;
+- }
+- return rc;
++
++#elif (defined(__GNUC__) && defined(__ppc__))
++
++ __inline__ sqlite_uint64 sqlite3Hwtime(void){
++ unsigned long long retval;
++ unsigned long junk;
++ __asm__ __volatile__ ("\n\
++ 1: mftbu %1\n\
++ mftb %L0\n\
++ mftbu %0\n\
++ cmpw %0,%1\n\
++ bne 1b"
++ : "=r" (retval), "=r" (junk));
++ return retval;
+ }
+- pFile->eFileLock = NO_LOCK;
+- return SQLITE_OK;
+-}
++
++#else
++
++ #error Need implementation of sqlite3Hwtime() for your platform.
++
++ /*
++ ** To compile without implementing sqlite3Hwtime() for your platform,
++ ** you can remove the above #error and use the following
++ ** stub function. You will lose timing support for many
++ ** of the debugging and testing utilities, but it should at
++ ** least compile and run.
++ */
++SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
++
++#endif
++
++#endif /* !defined(_HWTIME_H_) */
++
++/************** End of hwtime.h **********************************************/
++/************** Continuing where we left off in os_common.h ******************/
++
++static sqlite_uint64 g_start;
++static sqlite_uint64 g_elapsed;
++#define TIMER_START g_start=sqlite3Hwtime()
++#define TIMER_END g_elapsed=sqlite3Hwtime()-g_start
++#define TIMER_ELAPSED g_elapsed
++#else
++#define TIMER_START
++#define TIMER_END
++#define TIMER_ELAPSED ((sqlite_uint64)0)
++#endif
+
+ /*
+-** Close a file. Make sure the lock has been released before closing.
++** If we compile with the SQLITE_TEST macro set, then the following block
++** of code will give us the ability to simulate a disk I/O error. This
++** is used for testing the I/O recovery logic.
+ */
+-static int dotlockClose(sqlite3_file *id) {
+- int rc = SQLITE_OK;
+- if( id ){
+- unixFile *pFile = (unixFile*)id;
+- dotlockUnlock(id, NO_LOCK);
+- sqlite3_free(pFile->lockingContext);
+- rc = closeUnixFile(id);
+- }
+- return rc;
++#ifdef SQLITE_TEST
++SQLITE_API int sqlite3_io_error_hit = 0; /* Total number of I/O Errors */
++SQLITE_API int sqlite3_io_error_hardhit = 0; /* Number of non-benign errors */
++SQLITE_API int sqlite3_io_error_pending = 0; /* Count down to first I/O error */
++SQLITE_API int sqlite3_io_error_persist = 0; /* True if I/O errors persist */
++SQLITE_API int sqlite3_io_error_benign = 0; /* True if errors are benign */
++SQLITE_API int sqlite3_diskfull_pending = 0;
++SQLITE_API int sqlite3_diskfull = 0;
++#define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X)
++#define SimulateIOError(CODE) \
++ if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \
++ || sqlite3_io_error_pending-- == 1 ) \
++ { local_ioerr(); CODE; }
++static void local_ioerr(){
++ IOTRACE(("IOERR\n"));
++ sqlite3_io_error_hit++;
++ if( !sqlite3_io_error_benign ) sqlite3_io_error_hardhit++;
+ }
+-/****************** End of the dot-file lock implementation *******************
+-******************************************************************************/
++#define SimulateDiskfullError(CODE) \
++ if( sqlite3_diskfull_pending ){ \
++ if( sqlite3_diskfull_pending == 1 ){ \
++ local_ioerr(); \
++ sqlite3_diskfull = 1; \
++ sqlite3_io_error_hit = 1; \
++ CODE; \
++ }else{ \
++ sqlite3_diskfull_pending--; \
++ } \
++ }
++#else
++#define SimulateIOErrorBenign(X)
++#define SimulateIOError(A)
++#define SimulateDiskfullError(A)
++#endif
+
+-/******************************************************************************
+-************************** Begin flock Locking ********************************
+-**
+-** Use the flock() system call to do file locking.
+-**
+-** flock() locking is like dot-file locking in that the various
+-** fine-grain locking levels supported by SQLite are collapsed into
+-** a single exclusive lock. In other words, SHARED, RESERVED, and
+-** PENDING locks are the same thing as an EXCLUSIVE lock. SQLite
+-** 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.
++/*
++** When testing, keep a count of the number of open files.
+ */
+-#if SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS
++#ifdef SQLITE_TEST
++SQLITE_API int sqlite3_open_file_count = 0;
++#define OpenCounter(X) sqlite3_open_file_count+=(X)
++#else
++#define OpenCounter(X)
++#endif
++
++#endif /* !defined(_OS_COMMON_H_) */
++
++/************** End of os_common.h *******************************************/
++/************** Continuing where we left off in os_unix.c ********************/
++
++/*
++** Define various macros that are missing from some systems.
++*/
++#ifndef O_LARGEFILE
++# define O_LARGEFILE 0
++#endif
++#ifdef SQLITE_DISABLE_LFS
++# undef O_LARGEFILE
++# define O_LARGEFILE 0
++#endif
++#ifndef O_NOFOLLOW
++# define O_NOFOLLOW 0
++#endif
++#ifndef O_BINARY
++# define O_BINARY 0
++#endif
+
+ /*
+-** Retry flock() calls that fail with EINTR
++** The threadid macro resolves to the thread-id or to 0. Used for
++** testing and debugging only.
+ */
+-#ifdef EINTR
+-static int robust_flock(int fd, int op){
+- int rc;
+- do{ rc = flock(fd,op); }while( rc<0 && errno==EINTR );
+- return rc;
+-}
++#if SQLITE_THREADSAFE
++#define threadid pthread_self()
+ #else
+-# define robust_flock(a,b) flock(a,b)
++#define threadid 0
+ #endif
+-
+
+ /*
+-** 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, set *pResOut
+-** 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.
++** HAVE_MREMAP defaults to true on Linux and false everywhere else.
+ */
+-static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){
+- int rc = SQLITE_OK;
+- int reserved = 0;
+- unixFile *pFile = (unixFile*)id;
+-
+- SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
+-
+- assert( pFile );
+-
+- /* Check if a thread in this process holds such a lock */
+- if( pFile->eFileLock>SHARED_LOCK ){
+- reserved = 1;
+- }
+-
+- /* Otherwise see if some other process holds it. */
+- if( !reserved ){
+- /* attempt to get the lock */
+- int lrc = robust_flock(pFile->h, LOCK_EX | LOCK_NB);
+- if( !lrc ){
+- /* got the lock, unlock it */
+- lrc = robust_flock(pFile->h, LOCK_UN);
+- if ( lrc ) {
+- int tErrno = errno;
+- /* unlock failed with an error */
+- lrc = SQLITE_IOERR_UNLOCK;
+- if( IS_LOCK_ERROR(lrc) ){
+- pFile->lastErrno = tErrno;
+- rc = lrc;
+- }
+- }
+- } else {
+- int tErrno = errno;
+- reserved = 1;
+- /* someone else might have it reserved */
+- lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
+- if( IS_LOCK_ERROR(lrc) ){
+- pFile->lastErrno = tErrno;
+- rc = lrc;
+- }
+- }
+- }
+- OSTRACE(("TEST WR-LOCK %d %d %d (flock)\n", pFile->h, rc, reserved));
+-
+-#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
+- if( (rc & SQLITE_IOERR) == SQLITE_IOERR ){
+- rc = SQLITE_OK;
+- reserved=1;
+- }
+-#endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */
+- *pResOut = reserved;
+- return rc;
+-}
++#if !defined(HAVE_MREMAP)
++# if defined(__linux__) && defined(_GNU_SOURCE)
++# define HAVE_MREMAP 1
++# else
++# define HAVE_MREMAP 0
++# endif
++#endif
+
+ /*
+-** Lock the file with the lock specified by parameter eFileLock - 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
+-**
+-** flock() only really support EXCLUSIVE locks. We track intermediate
+-** lock states in the sqlite3_file structure, but all locks SHARED or
+-** above are really EXCLUSIVE locks and exclude all other processes from
+-** access the file.
++** 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.
+ **
+-** This routine will only increase a lock. Use the sqlite3OsUnlock()
+-** routine to lower a locking level.
++** The safest way to deal with the problem is to always use this wrapper
++** which always has the same well-defined interface.
+ */
+-static int flockLock(sqlite3_file *id, int eFileLock) {
+- int rc = SQLITE_OK;
+- unixFile *pFile = (unixFile*)id;
+-
+- assert( pFile );
+-
+- /* if we already have a lock, it is exclusive.
+- ** Just adjust level and punt on outta here. */
+- if (pFile->eFileLock > NO_LOCK) {
+- pFile->eFileLock = eFileLock;
+- return SQLITE_OK;
+- }
+-
+- /* grab an exclusive lock */
+-
+- if (robust_flock(pFile->h, LOCK_EX | LOCK_NB)) {
+- int tErrno = errno;
+- /* didn't get, must be busy */
+- rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
+- if( IS_LOCK_ERROR(rc) ){
+- pFile->lastErrno = tErrno;
+- }
+- } else {
+- /* got it, set the type and return ok */
+- pFile->eFileLock = eFileLock;
+- }
+- OSTRACE(("LOCK %d %s %s (flock)\n", pFile->h, azFileLock(eFileLock),
+- rc==SQLITE_OK ? "ok" : "failed"));
+-#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
+- if( (rc & SQLITE_IOERR) == SQLITE_IOERR ){
+- rc = SQLITE_BUSY;
+- }
+-#endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */
+- return rc;
++static int posixOpen(const char *zFile, int flags, int mode){
++ return open(zFile, flags, mode);
+ }
+
+-
+ /*
+-** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
+-** 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.
++** On some systems, calls to fchown() will trigger a message in a security
++** log if they come from non-root processes. So avoid calling fchown() if
++** we are not running as root.
+ */
+-static int flockUnlock(sqlite3_file *id, int eFileLock) {
+- unixFile *pFile = (unixFile*)id;
+-
+- assert( pFile );
+- OSTRACE(("UNLOCK %d %d was %d pid=%d (flock)\n", pFile->h, eFileLock,
+- pFile->eFileLock, getpid()));
+- assert( eFileLock<=SHARED_LOCK );
+-
+- /* no-op if possible */
+- if( pFile->eFileLock==eFileLock ){
+- return SQLITE_OK;
+- }
+-
+- /* shared can just be set because we always have an exclusive */
+- if (eFileLock==SHARED_LOCK) {
+- pFile->eFileLock = eFileLock;
+- return SQLITE_OK;
+- }
+-
+- /* no, really, unlock. */
+- if( robust_flock(pFile->h, LOCK_UN) ){
+-#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
+- return SQLITE_OK;
+-#endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */
+- return SQLITE_IOERR_UNLOCK;
+- }else{
+- pFile->eFileLock = NO_LOCK;
+- return SQLITE_OK;
+- }
++static int posixFchown(int fd, uid_t uid, gid_t gid){
++ return geteuid() ? 0 : fchown(fd,uid,gid);
+ }
+
++/* Forward reference */
++static int openDirectory(const char*, int*);
++
+ /*
+-** Close a file.
++** Many system calls are accessed through pointer-to-functions so that
++** they may be overridden at runtime to facilitate fault injection during
++** testing and sandboxing. The following array holds the names and pointers
++** to all overrideable system calls.
+ */
+-static int flockClose(sqlite3_file *id) {
+- int rc = SQLITE_OK;
+- if( id ){
+- flockUnlock(id, NO_LOCK);
+- rc = closeUnixFile(id);
+- }
+- return rc;
+-}
++static struct unix_syscall {
++ const char *zName; /* Name of the system call */
++ sqlite3_syscall_ptr pCurrent; /* Current value of the system call */
++ sqlite3_syscall_ptr pDefault; /* Default value */
++} aSyscall[] = {
++ { "open", (sqlite3_syscall_ptr)posixOpen, 0 },
++#define osOpen ((int(*)(const char*,int,int))aSyscall[0].pCurrent)
+
+-#endif /* SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORK */
++ { "close", (sqlite3_syscall_ptr)close, 0 },
++#define osClose ((int(*)(int))aSyscall[1].pCurrent)
+
+-/******************* End of the flock lock implementation *********************
+-******************************************************************************/
++ { "access", (sqlite3_syscall_ptr)access, 0 },
++#define osAccess ((int(*)(const char*,int))aSyscall[2].pCurrent)
+
+-/******************************************************************************
+-************************ Begin Named Semaphore Locking ************************
+-**
+-** Named semaphore locking is only supported on VxWorks.
+-**
+-** Semaphore locking is like dot-lock and flock in that it really only
+-** supports EXCLUSIVE locking. Only a single process can read or write
+-** the database file at a time. This reduces potential concurrency, but
+-** makes the lock implementation much easier.
+-*/
+-#if OS_VXWORKS
++ { "getcwd", (sqlite3_syscall_ptr)getcwd, 0 },
++#define osGetcwd ((char*(*)(char*,size_t))aSyscall[3].pCurrent)
++
++ { "stat", (sqlite3_syscall_ptr)stat, 0 },
++#define osStat ((int(*)(const char*,struct stat*))aSyscall[4].pCurrent)
+
+ /*
+-** 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, set *pResOut
+-** 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.
++** The DJGPP compiler environment looks mostly like Unix, but it
++** lacks the fcntl() system call. So redefine fcntl() to be something
++** that always succeeds. This means that locking does not occur under
++** DJGPP. But it is DOS - what did you expect?
+ */
+-static int semCheckReservedLock(sqlite3_file *id, int *pResOut) {
+- int rc = SQLITE_OK;
+- int reserved = 0;
+- unixFile *pFile = (unixFile*)id;
++#ifdef __DJGPP__
++ { "fstat", 0, 0 },
++#define osFstat(a,b,c) 0
++#else
++ { "fstat", (sqlite3_syscall_ptr)fstat, 0 },
++#define osFstat ((int(*)(int,struct stat*))aSyscall[5].pCurrent)
++#endif
+
+- SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
+-
+- assert( pFile );
++ { "ftruncate", (sqlite3_syscall_ptr)ftruncate, 0 },
++#define osFtruncate ((int(*)(int,off_t))aSyscall[6].pCurrent)
+
+- /* Check if a thread in this process holds such a lock */
+- if( pFile->eFileLock>SHARED_LOCK ){
+- reserved = 1;
+- }
+-
+- /* Otherwise see if some other process holds it. */
+- if( !reserved ){
+- sem_t *pSem = pFile->pInode->pSem;
+- struct stat statBuf;
++ { "fcntl", (sqlite3_syscall_ptr)fcntl, 0 },
++#define osFcntl ((int(*)(int,int,...))aSyscall[7].pCurrent)
+
+- if( sem_trywait(pSem)==-1 ){
+- int tErrno = errno;
+- if( EAGAIN != tErrno ){
+- rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_CHECKRESERVEDLOCK);
+- pFile->lastErrno = tErrno;
+- } else {
+- /* someone else has the lock when we are in NO_LOCK */
+- reserved = (pFile->eFileLock < SHARED_LOCK);
+- }
+- }else{
+- /* we could have it if we want it */
+- sem_post(pSem);
+- }
+- }
+- OSTRACE(("TEST WR-LOCK %d %d %d (sem)\n", pFile->h, rc, reserved));
++ { "read", (sqlite3_syscall_ptr)read, 0 },
++#define osRead ((ssize_t(*)(int,void*,size_t))aSyscall[8].pCurrent)
+
+- *pResOut = reserved;
+- return rc;
+-}
++#if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE
++ { "pread", (sqlite3_syscall_ptr)pread, 0 },
++#else
++ { "pread", (sqlite3_syscall_ptr)0, 0 },
++#endif
++#define osPread ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[9].pCurrent)
++
++#if defined(USE_PREAD64)
++ { "pread64", (sqlite3_syscall_ptr)pread64, 0 },
++#else
++ { "pread64", (sqlite3_syscall_ptr)0, 0 },
++#endif
++#define osPread64 ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].pCurrent)
++
++ { "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
++ { "pwrite", (sqlite3_syscall_ptr)pwrite, 0 },
++#else
++ { "pwrite", (sqlite3_syscall_ptr)0, 0 },
++#endif
++#define osPwrite ((ssize_t(*)(int,const void*,size_t,off_t))\
++ aSyscall[12].pCurrent)
++
++#if defined(USE_PREAD64)
++ { "pwrite64", (sqlite3_syscall_ptr)pwrite64, 0 },
++#else
++ { "pwrite64", (sqlite3_syscall_ptr)0, 0 },
++#endif
++#define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\
++ aSyscall[13].pCurrent)
++
++ { "fchmod", (sqlite3_syscall_ptr)fchmod, 0 },
++#define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent)
++
++#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
++ { "fallocate", (sqlite3_syscall_ptr)posix_fallocate, 0 },
++#else
++ { "fallocate", (sqlite3_syscall_ptr)0, 0 },
++#endif
++#define osFallocate ((int(*)(int,off_t,off_t))aSyscall[15].pCurrent)
++
++ { "unlink", (sqlite3_syscall_ptr)unlink, 0 },
++#define osUnlink ((int(*)(const char*))aSyscall[16].pCurrent)
++
++ { "openDirectory", (sqlite3_syscall_ptr)openDirectory, 0 },
++#define osOpenDirectory ((int(*)(const char*,int*))aSyscall[17].pCurrent)
++
++ { "mkdir", (sqlite3_syscall_ptr)mkdir, 0 },
++#define osMkdir ((int(*)(const char*,mode_t))aSyscall[18].pCurrent)
++
++ { "rmdir", (sqlite3_syscall_ptr)rmdir, 0 },
++#define osRmdir ((int(*)(const char*))aSyscall[19].pCurrent)
++
++ { "fchown", (sqlite3_syscall_ptr)posixFchown, 0 },
++#define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent)
++
++ { "mmap", (sqlite3_syscall_ptr)mmap, 0 },
++#define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[21].pCurrent)
++
++ { "munmap", (sqlite3_syscall_ptr)munmap, 0 },
++#define osMunmap ((void*(*)(void*,size_t))aSyscall[22].pCurrent)
++
++#if HAVE_MREMAP
++ { "mremap", (sqlite3_syscall_ptr)mremap, 0 },
++#else
++ { "mremap", (sqlite3_syscall_ptr)0, 0 },
++#endif
++#define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[23].pCurrent)
++
++}; /* End of the overrideable system calls */
+
+ /*
+-** Lock the file with the lock specified by parameter eFileLock - 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
+-**
+-** Semaphore locks only really support EXCLUSIVE locks. We track intermediate
+-** lock states in the sqlite3_file structure, but all locks SHARED or
+-** above are really EXCLUSIVE locks and exclude all other processes from
+-** access the file.
+-**
+-** This routine will only increase a lock. Use the sqlite3OsUnlock()
+-** routine to lower a locking level.
++** This is the xSetSystemCall() method of sqlite3_vfs for all of the
++** "unix" 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 semLock(sqlite3_file *id, int eFileLock) {
+- unixFile *pFile = (unixFile*)id;
+- int fd;
+- sem_t *pSem = pFile->pInode->pSem;
+- int rc = SQLITE_OK;
++static int unixSetSystemCall(
++ 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;
+
+- /* if we already have a lock, it is exclusive.
+- ** Just adjust level and punt on outta here. */
+- if (pFile->eFileLock > NO_LOCK) {
+- pFile->eFileLock = eFileLock;
++ 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;
+- goto sem_end_lock;
+- }
+-
+- /* lock semaphore now but bail out when already locked. */
+- if( sem_trywait(pSem)==-1 ){
+- rc = SQLITE_BUSY;
+- goto sem_end_lock;
++ 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;
++ }
++ }
+ }
+-
+- /* got it, set the type and return ok */
+- pFile->eFileLock = eFileLock;
+-
+- sem_end_lock:
+ return rc;
+ }
+
+ /*
+-** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
+-** 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.
++** 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 int semUnlock(sqlite3_file *id, int eFileLock) {
+- unixFile *pFile = (unixFile*)id;
+- sem_t *pSem = pFile->pInode->pSem;
++static sqlite3_syscall_ptr unixGetSystemCall(
++ sqlite3_vfs *pNotUsed,
++ const char *zName
++){
++ unsigned int i;
+
+- assert( pFile );
+- assert( pSem );
+- OSTRACE(("UNLOCK %d %d was %d pid=%d (sem)\n", pFile->h, eFileLock,
+- pFile->eFileLock, getpid()));
+- assert( eFileLock<=SHARED_LOCK );
+-
+- /* no-op if possible */
+- if( pFile->eFileLock==eFileLock ){
+- return SQLITE_OK;
+- }
+-
+- /* shared can just be set because we always have an exclusive */
+- if (eFileLock==SHARED_LOCK) {
+- pFile->eFileLock = eFileLock;
+- return SQLITE_OK;
+- }
+-
+- /* no, really unlock. */
+- if ( sem_post(pSem)==-1 ) {
+- int rc, tErrno = errno;
+- rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
+- if( IS_LOCK_ERROR(rc) ){
+- pFile->lastErrno = tErrno;
+- }
+- return rc;
++ UNUSED_PARAMETER(pNotUsed);
++ for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
++ if( strcmp(zName, aSyscall[i].zName)==0 ) return aSyscall[i].pCurrent;
+ }
+- pFile->eFileLock = NO_LOCK;
+- return SQLITE_OK;
++ return 0;
+ }
+
+ /*
+- ** Close a file.
+- */
+-static int semClose(sqlite3_file *id) {
+- if( id ){
+- unixFile *pFile = (unixFile*)id;
+- semUnlock(id, NO_LOCK);
+- assert( pFile );
+- unixEnterMutex();
+- releaseInodeInfo(pFile);
+- unixLeaveMutex();
+- closeUnixFile(id);
++** 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 *unixNextSystemCall(sqlite3_vfs *p, const char *zName){
++ int i = -1;
++
++ UNUSED_PARAMETER(p);
++ if( zName ){
++ for(i=0; i<ArraySize(aSyscall)-1; i++){
++ if( strcmp(zName, aSyscall[i].zName)==0 ) break;
++ }
+ }
+- return SQLITE_OK;
++ for(i++; i<ArraySize(aSyscall); i++){
++ if( aSyscall[i].pCurrent!=0 ) return aSyscall[i].zName;
++ }
++ return 0;
+ }
+
+-#endif /* OS_VXWORKS */
+ /*
+-** Named semaphore locking is only available on VxWorks.
+-**
+-*************** End of the named semaphore lock implementation ****************
+-******************************************************************************/
+-
+-
+-/******************************************************************************
+-*************************** Begin AFP Locking *********************************
++** Invoke open(). Do so multiple times, until it either succeeds or
++** fails for some reason other than EINTR.
+ **
+-** AFP is the Apple Filing Protocol. AFP is a network filesystem found
+-** on Apple Macintosh computers - both OS9 and OSX.
++** If the file creation mode "m" is 0 then set it to the default for
++** SQLite. The default is SQLITE_DEFAULT_FILE_PERMISSIONS (normally
++** 0644) as modified by the system umask. If m is not 0, then
++** make the file creation mode be exactly m ignoring the umask.
+ **
+-** Third-party implementations of AFP are available. But this code here
+-** only works on OSX.
++** The m parameter will be non-zero only when creating -wal, -journal,
++** and -shm files. We want those files to have *exactly* the same
++** permissions as their original database, unadulterated by the umask.
++** In that way, if a database file is -rw-rw-rw or -rw-rw-r-, and a
++** transaction crashes and leaves behind hot journals, then any
++** process that is able to write to the database will also be able to
++** recover the hot journals.
+ */
++static int robust_open(const char *z, int f, mode_t m){
++ int fd;
++ mode_t m2 = m ? m : SQLITE_DEFAULT_FILE_PERMISSIONS;
++ do{
++#if defined(O_CLOEXEC)
++ fd = osOpen(z,f|O_CLOEXEC,m2);
++#else
++ fd = osOpen(z,f,m2);
++#endif
++ }while( fd<0 && errno==EINTR );
++ if( fd>=0 ){
++ if( m!=0 ){
++ struct stat statbuf;
++ if( osFstat(fd, &statbuf)==0
++ && statbuf.st_size==0
++ && (statbuf.st_mode&0777)!=m
++ ){
++ osFchmod(fd, m);
++ }
++ }
++#if defined(FD_CLOEXEC) && (!defined(O_CLOEXEC) || O_CLOEXEC==0)
++ osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
++#endif
++ }
++ return fd;
++}
+
+-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
+ /*
+-** The afpLockingContext structure contains all afp lock specific state
++** Helper functions to obtain and relinquish the global mutex. The
++** global mutex is used to protect the unixInodeInfo and
++** vxworksFileId objects used by this file, all of which may be
++** shared by multiple threads.
++**
++** Function unixMutexHeld() is used to assert() that the global mutex
++** is held when required. This function is only used as part of assert()
++** statements. e.g.
++**
++** unixEnterMutex()
++** assert( unixMutexHeld() );
++** unixEnterLeave()
+ */
+-typedef struct afpLockingContext afpLockingContext;
+-struct afpLockingContext {
+- int reserved;
+- const char *dbPath; /* Name of the open file */
+-};
+-
+-struct ByteRangeLockPB2
+-{
+- unsigned long long offset; /* offset to first byte to lock */
+- unsigned long long length; /* nbr of bytes to lock */
+- unsigned long long retRangeStart; /* nbr of 1st byte locked if successful */
+- unsigned char unLockFlag; /* 1 = unlock, 0 = lock */
+- unsigned char startEndFlag; /* 1=rel to end of fork, 0=rel to start */
+- int fd; /* file desc to assoc this lock with */
+-};
++static void unixEnterMutex(void){
++ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
++}
++static void unixLeaveMutex(void){
++ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
++}
++#ifdef SQLITE_DEBUG
++static int unixMutexHeld(void) {
++ return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
++}
++#endif
+
+-#define afpfsByteRangeLock2FSCTL _IOWR('z', 23, struct ByteRangeLockPB2)
+
++#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
+ /*
+-** This is a utility for setting or clearing a bit-range lock on an
+-** AFP filesystem.
+-**
+-** Return SQLITE_OK on success, SQLITE_BUSY on failure.
++** Helper function for printing out trace information from debugging
++** binaries. This returns the string represetation of the supplied
++** integer lock-type.
+ */
+-static int afpSetLock(
+- const char *path, /* Name of the file to be locked or unlocked */
+- unixFile *pFile, /* Open file descriptor on path */
+- unsigned long long offset, /* First byte to be locked */
+- unsigned long long length, /* Number of bytes to lock */
+- int setLockFlag /* True to set lock. False to clear lock */
+-){
+- struct ByteRangeLockPB2 pb;
+- int err;
+-
+- pb.unLockFlag = setLockFlag ? 0 : 1;
+- pb.startEndFlag = 0;
+- pb.offset = offset;
+- pb.length = length;
+- pb.fd = pFile->h;
+-
+- OSTRACE(("AFPSETLOCK [%s] for %d%s in range %llx:%llx\n",
+- (setLockFlag?"ON":"OFF"), pFile->h, (pb.fd==-1?"[testval-1]":""),
+- offset, length));
+- err = fsctl(path, afpfsByteRangeLock2FSCTL, &pb, 0);
+- if ( err==-1 ) {
+- int rc;
+- int tErrno = errno;
+- OSTRACE(("AFPSETLOCK failed to fsctl() '%s' %d %s\n",
+- path, tErrno, strerror(tErrno)));
+-#ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS
+- rc = SQLITE_BUSY;
+-#else
+- rc = sqliteErrorFromPosixError(tErrno,
+- setLockFlag ? SQLITE_IOERR_LOCK : SQLITE_IOERR_UNLOCK);
+-#endif /* SQLITE_IGNORE_AFP_LOCK_ERRORS */
+- if( IS_LOCK_ERROR(rc) ){
+- pFile->lastErrno = tErrno;
+- }
+- return rc;
+- } else {
+- return SQLITE_OK;
++static const char *azFileLock(int eFileLock){
++ switch( eFileLock ){
++ case NO_LOCK: return "NONE";
++ case SHARED_LOCK: return "SHARED";
++ case RESERVED_LOCK: return "RESERVED";
++ case PENDING_LOCK: return "PENDING";
++ case EXCLUSIVE_LOCK: return "EXCLUSIVE";
+ }
++ return "ERROR";
+ }
++#endif
+
++#ifdef SQLITE_LOCK_TRACE
+ /*
+-** 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, set *pResOut
+-** 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.
++** Print out information about all locking operations.
++**
++** This routine is used for troubleshooting locks on multithreaded
++** platforms. Enable by compiling with the -DSQLITE_LOCK_TRACE
++** command-line option on the compiler. This code is normally
++** turned off.
+ */
+-static int afpCheckReservedLock(sqlite3_file *id, int *pResOut){
+- int rc = SQLITE_OK;
+- int reserved = 0;
+- unixFile *pFile = (unixFile*)id;
+- afpLockingContext *context;
+-
+- SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
+-
+- assert( pFile );
+- context = (afpLockingContext *) pFile->lockingContext;
+- if( context->reserved ){
+- *pResOut = 1;
+- return SQLITE_OK;
++static int lockTrace(int fd, int op, struct flock *p){
++ char *zOpName, *zType;
++ int s;
++ int savedErrno;
++ if( op==F_GETLK ){
++ zOpName = "GETLK";
++ }else if( op==F_SETLK ){
++ zOpName = "SETLK";
++ }else{
++ s = osFcntl(fd, op, p);
++ sqlite3DebugPrintf("fcntl unknown %d %d %d\n", fd, op, s);
++ return s;
+ }
+- unixEnterMutex(); /* Because pFile->pInode is shared across threads */
+-
+- /* Check if a thread in this process holds such a lock */
+- if( pFile->pInode->eFileLock>SHARED_LOCK ){
+- reserved = 1;
++ if( p->l_type==F_RDLCK ){
++ zType = "RDLCK";
++ }else if( p->l_type==F_WRLCK ){
++ zType = "WRLCK";
++ }else if( p->l_type==F_UNLCK ){
++ zType = "UNLCK";
++ }else{
++ assert( 0 );
+ }
+-
+- /* Otherwise see if some other process holds it.
+- */
+- if( !reserved ){
+- /* lock the RESERVED byte */
+- int lrc = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1,1);
+- if( SQLITE_OK==lrc ){
+- /* if we succeeded in taking the reserved lock, unlock it to restore
+- ** the original state */
+- lrc = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1, 0);
+- } else {
+- /* if we failed to get the lock then someone else must have it */
+- reserved = 1;
+- }
+- if( IS_LOCK_ERROR(lrc) ){
+- rc=lrc;
++ assert( p->l_whence==SEEK_SET );
++ s = osFcntl(fd, op, p);
++ savedErrno = errno;
++ sqlite3DebugPrintf("fcntl %d %d %s %s %d %d %d %d\n",
++ threadid, fd, zOpName, zType, (int)p->l_start, (int)p->l_len,
++ (int)p->l_pid, s);
++ if( s==(-1) && op==F_SETLK && (p->l_type==F_RDLCK || p->l_type==F_WRLCK) ){
++ struct flock l2;
++ l2 = *p;
++ osFcntl(fd, F_GETLK, &l2);
++ if( l2.l_type==F_RDLCK ){
++ zType = "RDLCK";
++ }else if( l2.l_type==F_WRLCK ){
++ zType = "WRLCK";
++ }else if( l2.l_type==F_UNLCK ){
++ zType = "UNLCK";
++ }else{
++ assert( 0 );
+ }
++ sqlite3DebugPrintf("fcntl-failure-reason: %s %d %d %d\n",
++ zType, (int)l2.l_start, (int)l2.l_len, (int)l2.l_pid);
+ }
+-
+- unixLeaveMutex();
+- OSTRACE(("TEST WR-LOCK %d %d %d (afp)\n", pFile->h, rc, reserved));
+-
+- *pResOut = reserved;
+- return rc;
++ errno = savedErrno;
++ return s;
+ }
++#undef osFcntl
++#define osFcntl lockTrace
++#endif /* SQLITE_LOCK_TRACE */
+
+ /*
+-** Lock the file with the lock specified by parameter eFileLock - 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. Use the sqlite3OsUnlock()
+-** routine to lower a locking level.
++** Retry ftruncate() calls that fail due to EINTR
+ */
+-static int afpLock(sqlite3_file *id, int eFileLock){
+- int rc = SQLITE_OK;
+- unixFile *pFile = (unixFile*)id;
+- unixInodeInfo *pInode = pFile->pInode;
+- afpLockingContext *context = (afpLockingContext *) pFile->lockingContext;
+-
+- 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()));
++static int robust_ftruncate(int h, sqlite3_int64 sz){
++ int rc;
++ do{ rc = osFtruncate(h,sz); }while( rc<0 && errno==EINTR );
++ return rc;
++}
+
+- /* 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
+- ** unixEnterMutex() hasn't been called yet.
++/*
++** This routine translates a standard POSIX errno code into something
++** useful to the clients of the sqlite3 functions. Specifically, it is
++** intended to translate a variety of "try again" errors into SQLITE_BUSY
++** and a variety of "please close the file descriptor NOW" errors into
++** SQLITE_IOERR
++**
++** Errors during initialization of locks, or file system support for locks,
++** should handle ENOLCK, ENOTSUP, EOPNOTSUPP separately.
++*/
++static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) {
++ switch (posixError) {
++#if 0
++ /* At one point this code was not commented out. In theory, this branch
++ ** should never be hit, as this function should only be called after
++ ** a locking-related function (i.e. fcntl()) has returned non-zero with
++ ** the value of errno as the first argument. Since a system call has failed,
++ ** errno should be non-zero.
++ **
++ ** Despite this, if errno really is zero, we still don't want to return
++ ** SQLITE_OK. The system call failed, and *some* SQLite error should be
++ ** propagated back to the caller. Commenting this branch out means errno==0
++ ** will be handled by the "default:" case below.
+ */
+- if( pFile->eFileLock>=eFileLock ){
+- OSTRACE(("LOCK %d %s ok (already held) (afp)\n", pFile->h,
+- azFileLock(eFileLock)));
++ case 0:
+ return SQLITE_OK;
+- }
+-
+- /* Make sure the locking sequence is correct
+- ** (1) We never move from unlocked to anything higher than shared lock.
+- ** (2) SQLite never explicitly requests a pendig lock.
+- ** (3) A shared lock is always held when a reserve lock is requested.
+- */
+- assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK );
+- assert( eFileLock!=PENDING_LOCK );
+- assert( eFileLock!=RESERVED_LOCK || pFile->eFileLock==SHARED_LOCK );
+-
+- /* This mutex is needed because pFile->pInode is shared across threads
+- */
+- unixEnterMutex();
+- pInode = pFile->pInode;
++#endif
+
+- /* If some thread using this PID has a lock via a different unixFile*
+- ** handle that precludes the requested lock, return BUSY.
+- */
+- if( (pFile->eFileLock!=pInode->eFileLock &&
+- (pInode->eFileLock>=PENDING_LOCK || eFileLock>SHARED_LOCK))
+- ){
+- rc = SQLITE_BUSY;
+- goto afp_end_lock;
+- }
+-
+- /* If a SHARED lock is requested, and some thread using this PID already
+- ** has a SHARED or RESERVED lock, then increment reference counts and
+- ** return SQLITE_OK.
+- */
+- if( eFileLock==SHARED_LOCK &&
+- (pInode->eFileLock==SHARED_LOCK || pInode->eFileLock==RESERVED_LOCK) ){
+- assert( eFileLock==SHARED_LOCK );
+- assert( pFile->eFileLock==0 );
+- assert( pInode->nShared>0 );
+- pFile->eFileLock = SHARED_LOCK;
+- pInode->nShared++;
+- pInode->nLock++;
+- goto afp_end_lock;
+- }
++ case EAGAIN:
++ case ETIMEDOUT:
++ case EBUSY:
++ case EINTR:
++ case ENOLCK:
++ /* random NFS retry error, unless during file system support
++ * introspection, in which it actually means what it says */
++ return SQLITE_BUSY;
+
+- /* A PENDING lock is needed before acquiring a SHARED lock and before
+- ** acquiring an EXCLUSIVE lock. For the SHARED lock, the PENDING will
+- ** be released.
+- */
+- if( eFileLock==SHARED_LOCK
+- || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock<PENDING_LOCK)
+- ){
+- int failed;
+- failed = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 1);
+- if (failed) {
+- rc = failed;
+- goto afp_end_lock;
++ case EACCES:
++ /* EACCES is like EAGAIN during locking operations, but not any other time*/
++ if( (sqliteIOErr == SQLITE_IOERR_LOCK) ||
++ (sqliteIOErr == SQLITE_IOERR_UNLOCK) ||
++ (sqliteIOErr == SQLITE_IOERR_RDLOCK) ||
++ (sqliteIOErr == SQLITE_IOERR_CHECKRESERVEDLOCK) ){
++ return SQLITE_BUSY;
+ }
+- }
+-
+- /* If control gets to this point, then actually go ahead and make
+- ** operating system calls for the specified lock.
+- */
+- if( eFileLock==SHARED_LOCK ){
+- int lrc1, lrc2, lrc1Errno = 0;
+- long lk, mask;
++ /* else fall through */
++ case EPERM:
++ return SQLITE_PERM;
+
+- assert( pInode->nShared==0 );
+- assert( pInode->eFileLock==0 );
+-
+- mask = (sizeof(long)==8) ? LARGEST_INT64 : 0x7fffffff;
+- /* Now get the read-lock SHARED_LOCK */
+- /* note that the quality of the randomness doesn't matter that much */
+- lk = random();
+- pInode->sharedByte = (lk & mask)%(SHARED_SIZE - 1);
+- lrc1 = afpSetLock(context->dbPath, pFile,
+- SHARED_FIRST+pInode->sharedByte, 1, 1);
+- if( IS_LOCK_ERROR(lrc1) ){
+- lrc1Errno = pFile->lastErrno;
+- }
+- /* Drop the temporary PENDING lock */
+- lrc2 = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 0);
++ /* EDEADLK is only possible if a call to fcntl(F_SETLKW) is made. And
++ ** this module never makes such a call. And the code in SQLite itself
++ ** asserts that SQLITE_IOERR_BLOCKED is never returned. For these reasons
++ ** this case is also commented out. If the system does set errno to EDEADLK,
++ ** the default SQLITE_IOERR_XXX code will be returned. */
++#if 0
++ case EDEADLK:
++ return SQLITE_IOERR_BLOCKED;
++#endif
+
+- if( IS_LOCK_ERROR(lrc1) ) {
+- pFile->lastErrno = lrc1Errno;
+- rc = lrc1;
+- goto afp_end_lock;
+- } else if( IS_LOCK_ERROR(lrc2) ){
+- rc = lrc2;
+- goto afp_end_lock;
+- } else if( lrc1 != SQLITE_OK ) {
+- rc = lrc1;
+- } else {
+- pFile->eFileLock = SHARED_LOCK;
+- pInode->nLock++;
+- pInode->nShared = 1;
+- }
+- }else if( eFileLock==EXCLUSIVE_LOCK && pInode->nShared>1 ){
+- /* We are trying for an exclusive lock but another thread in this
+- ** same process is still holding a shared lock. */
+- rc = SQLITE_BUSY;
+- }else{
+- /* The request was for a RESERVED or EXCLUSIVE lock. It is
+- ** assumed that there is a SHARED or greater lock on the file
+- ** already.
+- */
+- int failed = 0;
+- assert( 0!=pFile->eFileLock );
+- if (eFileLock >= RESERVED_LOCK && pFile->eFileLock < RESERVED_LOCK) {
+- /* Acquire a RESERVED lock */
+- failed = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1,1);
+- if( !failed ){
+- context->reserved = 1;
++#if EOPNOTSUPP!=ENOTSUP
++ case EOPNOTSUPP:
++ /* something went terribly awry, unless during file system support
++ * introspection, in which it actually means what it says */
++#endif
++#ifdef ENOTSUP
++ case ENOTSUP:
++ /* invalid fd, unless during file system support introspection, in which
++ * it actually means what it says */
++#endif
++ case EIO:
++ case EBADF:
++ case EINVAL:
++ case ENOTCONN:
++ case ENODEV:
++ case ENXIO:
++ case ENOENT:
++#ifdef ESTALE /* ESTALE is not defined on Interix systems */
++ case ESTALE:
++#endif
++ case ENOSYS:
++ /* these should force the client to close the file and reconnect */
++
++ default:
++ return sqliteIOErr;
++ }
++}
++
++
++/******************************************************************************
++****************** Begin Unique File ID Utility Used By VxWorks ***************
++**
++** On most versions of unix, we can get a unique ID for a file by concatenating
++** the device number and the inode number. But this does not work on VxWorks.
++** On VxWorks, a unique file id must be based on the canonical filename.
++**
++** A pointer to an instance of the following structure can be used as a
++** unique file ID in VxWorks. Each instance of this structure contains
++** a copy of the canonical filename. There is also a reference count.
++** The structure is reclaimed when the number of pointers to it drops to
++** zero.
++**
++** There are never very many files open at one time and lookups are not
++** a performance-critical path, so it is sufficient to put these
++** structures on a linked list.
++*/
++struct vxworksFileId {
++ struct vxworksFileId *pNext; /* Next in a list of them all */
++ int nRef; /* Number of references to this one */
++ int nName; /* Length of the zCanonicalName[] string */
++ char *zCanonicalName; /* Canonical filename */
++};
++
++#if OS_VXWORKS
++/*
++** All unique filenames are held on a linked list headed by this
++** variable:
++*/
++static struct vxworksFileId *vxworksFileList = 0;
++
++/*
++** Simplify a filename into its canonical form
++** by making the following changes:
++**
++** * removing any trailing and duplicate /
++** * convert /./ into just /
++** * convert /A/../ where A is any simple name into just /
++**
++** Changes are made in-place. Return the new name length.
++**
++** The original filename is in z[0..n-1]. Return the number of
++** characters in the simplified name.
++*/
++static int vxworksSimplifyName(char *z, int n){
++ int i, j;
++ while( n>1 && z[n-1]=='/' ){ n--; }
++ for(i=j=0; i<n; i++){
++ if( z[i]=='/' ){
++ if( z[i+1]=='/' ) continue;
++ if( z[i+1]=='.' && i+2<n && z[i+2]=='/' ){
++ i += 1;
++ continue;
+ }
+- }
+- if (!failed && eFileLock == EXCLUSIVE_LOCK) {
+- /* Acquire an EXCLUSIVE lock */
+-
+- /* Remove the shared lock before trying the range. we'll need to
+- ** reestablish the shared lock if we can't get the afpUnlock
+- */
+- if( !(failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST +
+- pInode->sharedByte, 1, 0)) ){
+- int failed2 = SQLITE_OK;
+- /* now attemmpt to get the exclusive lock range */
+- failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST,
+- SHARED_SIZE, 1);
+- if( failed && (failed2 = afpSetLock(context->dbPath, pFile,
+- SHARED_FIRST + pInode->sharedByte, 1, 1)) ){
+- /* Can't reestablish the shared lock. Sqlite can't deal, this is
+- ** a critical I/O error
+- */
+- rc = ((failed & SQLITE_IOERR) == SQLITE_IOERR) ? failed2 :
+- SQLITE_IOERR_LOCK;
+- goto afp_end_lock;
+- }
+- }else{
+- rc = failed;
++ if( z[i+1]=='.' && i+3<n && z[i+2]=='.' && z[i+3]=='/' ){
++ while( j>0 && z[j-1]!='/' ){ j--; }
++ if( j>0 ){ j--; }
++ i += 2;
++ continue;
+ }
+ }
+- if( failed ){
+- rc = failed;
+- }
+- }
+-
+- if( rc==SQLITE_OK ){
+- pFile->eFileLock = eFileLock;
+- pInode->eFileLock = eFileLock;
+- }else if( eFileLock==EXCLUSIVE_LOCK ){
+- pFile->eFileLock = PENDING_LOCK;
+- pInode->eFileLock = PENDING_LOCK;
++ z[j++] = z[i];
+ }
+-
+-afp_end_lock:
+- unixLeaveMutex();
+- OSTRACE(("LOCK %d %s %s (afp)\n", pFile->h, azFileLock(eFileLock),
+- rc==SQLITE_OK ? "ok" : "failed"));
+- return rc;
++ z[j] = 0;
++ return j;
+ }
+
+ /*
+-** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
+-** must be either NO_LOCK or SHARED_LOCK.
++** Find a unique file ID for the given absolute pathname. Return
++** a pointer to the vxworksFileId object. This pointer is the unique
++** file ID.
+ **
+-** If the locking level of the file descriptor is already at or below
+-** the requested locking level, this routine is a no-op.
++** The nRef field of the vxworksFileId object is incremented before
++** the object is returned. A new vxworksFileId object is created
++** and added to the global list if necessary.
++**
++** If a memory allocation error occurs, return NULL.
+ */
+-static int afpUnlock(sqlite3_file *id, int eFileLock) {
+- int rc = SQLITE_OK;
+- unixFile *pFile = (unixFile*)id;
+- unixInodeInfo *pInode;
+- afpLockingContext *context = (afpLockingContext *) pFile->lockingContext;
+- int skipShared = 0;
+-#ifdef SQLITE_TEST
+- int h = pFile->h;
+-#endif
++static struct vxworksFileId *vxworksFindFileId(const char *zAbsoluteName){
++ struct vxworksFileId *pNew; /* search key and new file ID */
++ struct vxworksFileId *pCandidate; /* For looping over existing file IDs */
++ int n; /* Length of zAbsoluteName string */
+
+- 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()));
++ assert( zAbsoluteName[0]=='/' );
++ n = (int)strlen(zAbsoluteName);
++ pNew = sqlite3_malloc( sizeof(*pNew) + (n+1) );
++ if( pNew==0 ) return 0;
++ pNew->zCanonicalName = (char*)&pNew[1];
++ memcpy(pNew->zCanonicalName, zAbsoluteName, n+1);
++ n = vxworksSimplifyName(pNew->zCanonicalName, n);
+
+- assert( eFileLock<=SHARED_LOCK );
+- if( pFile->eFileLock<=eFileLock ){
+- return SQLITE_OK;
+- }
++ /* Search for an existing entry that matching the canonical name.
++ ** If found, increment the reference count and return a pointer to
++ ** the existing file ID.
++ */
+ unixEnterMutex();
+- pInode = pFile->pInode;
+- assert( pInode->nShared!=0 );
+- if( pFile->eFileLock>SHARED_LOCK ){
+- assert( pInode->eFileLock==pFile->eFileLock );
+- SimulateIOErrorBenign(1);
+- SimulateIOError( h=(-1) )
+- SimulateIOErrorBenign(0);
+-
+-#ifdef SQLITE_DEBUG
+- /* When reducing a lock such that other processes can start
+- ** reading the database file again, make sure that the
+- ** transaction counter was updated if any part of the database
+- ** file changed. If the transaction counter is not updated,
+- ** other connections to the same file might not realize that
+- ** the file has changed and hence might not know to flush their
+- ** cache. The use of a stale cache can lead to database corruption.
+- */
+- assert( pFile->inNormalWrite==0
+- || pFile->dbUpdate==0
+- || pFile->transCntrChng==1 );
+- pFile->inNormalWrite = 0;
+-#endif
+-
+- if( pFile->eFileLock==EXCLUSIVE_LOCK ){
+- rc = afpSetLock(context->dbPath, pFile, SHARED_FIRST, SHARED_SIZE, 0);
+- if( rc==SQLITE_OK && (eFileLock==SHARED_LOCK || pInode->nShared>1) ){
+- /* only re-establish the shared lock if necessary */
+- int sharedLockByte = SHARED_FIRST+pInode->sharedByte;
+- rc = afpSetLock(context->dbPath, pFile, sharedLockByte, 1, 1);
+- } else {
+- skipShared = 1;
+- }
+- }
+- if( rc==SQLITE_OK && pFile->eFileLock>=PENDING_LOCK ){
+- rc = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 0);
+- }
+- if( rc==SQLITE_OK && pFile->eFileLock>=RESERVED_LOCK && context->reserved ){
+- rc = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1, 0);
+- if( !rc ){
+- context->reserved = 0;
+- }
+- }
+- if( rc==SQLITE_OK && (eFileLock==SHARED_LOCK || pInode->nShared>1)){
+- pInode->eFileLock = SHARED_LOCK;
++ for(pCandidate=vxworksFileList; pCandidate; pCandidate=pCandidate->pNext){
++ if( pCandidate->nName==n
++ && memcmp(pCandidate->zCanonicalName, pNew->zCanonicalName, n)==0
++ ){
++ sqlite3_free(pNew);
++ pCandidate->nRef++;
++ unixLeaveMutex();
++ return pCandidate;
+ }
+ }
+- if( rc==SQLITE_OK && eFileLock==NO_LOCK ){
+
+- /* Decrement the shared lock counter. Release the lock using an
+- ** OS call only when all threads in this same process have released
+- ** the lock.
+- */
+- unsigned long long sharedLockByte = SHARED_FIRST+pInode->sharedByte;
+- pInode->nShared--;
+- if( pInode->nShared==0 ){
+- SimulateIOErrorBenign(1);
+- SimulateIOError( h=(-1) )
+- SimulateIOErrorBenign(0);
+- if( !skipShared ){
+- rc = afpSetLock(context->dbPath, pFile, sharedLockByte, 1, 0);
+- }
+- if( !rc ){
+- pInode->eFileLock = NO_LOCK;
+- pFile->eFileLock = NO_LOCK;
+- }
+- }
+- if( rc==SQLITE_OK ){
+- pInode->nLock--;
+- assert( pInode->nLock>=0 );
+- if( pInode->nLock==0 ){
+- closePendingFds(pFile);
+- }
+- }
+- }
+-
++ /* No match was found. We will make a new file ID */
++ pNew->nRef = 1;
++ pNew->nName = n;
++ pNew->pNext = vxworksFileList;
++ vxworksFileList = pNew;
+ unixLeaveMutex();
+- if( rc==SQLITE_OK ) pFile->eFileLock = eFileLock;
+- return rc;
++ return pNew;
+ }
+
+ /*
+-** Close a file & cleanup AFP specific locking context
++** Decrement the reference count on a vxworksFileId object. Free
++** the object when the reference count reaches zero.
+ */
+-static int afpClose(sqlite3_file *id) {
+- int rc = SQLITE_OK;
+- if( id ){
+- unixFile *pFile = (unixFile*)id;
+- afpUnlock(id, NO_LOCK);
+- unixEnterMutex();
+- if( pFile->pInode && pFile->pInode->nLock ){
+- /* If there are outstanding locks, do not actually close the file just
+- ** yet because that would clear those locks. Instead, add the file
+- ** descriptor to pInode->aPending. It will be automatically closed when
+- ** the last lock is cleared.
+- */
+- setPendingFd(pFile);
+- }
+- releaseInodeInfo(pFile);
+- sqlite3_free(pFile->lockingContext);
+- rc = closeUnixFile(id);
+- unixLeaveMutex();
++static void vxworksReleaseFileId(struct vxworksFileId *pId){
++ unixEnterMutex();
++ assert( pId->nRef>0 );
++ pId->nRef--;
++ if( pId->nRef==0 ){
++ struct vxworksFileId **pp;
++ for(pp=&vxworksFileList; *pp && *pp!=pId; pp = &((*pp)->pNext)){}
++ assert( *pp==pId );
++ *pp = pId->pNext;
++ sqlite3_free(pId);
+ }
+- return rc;
++ unixLeaveMutex();
+ }
+-
+-#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
+-/*
+-** The code above is the AFP lock implementation. The code is specific
+-** to MacOSX and does not work on other unix platforms. No alternative
+-** is available. If you don't compile for a mac, then the "unix-afp"
+-** VFS is not available.
+-**
+-********************* End of the AFP lock implementation **********************
++#endif /* OS_VXWORKS */
++/*************** End of Unique File ID Utility Used By VxWorks ****************
+ ******************************************************************************/
+
+-/******************************************************************************
+-*************************** Begin NFS Locking ********************************/
+-
+-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
+-/*
+- ** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
+- ** 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.
+- */
+-static int nfsUnlock(sqlite3_file *id, int eFileLock){
+- return posixUnlock(id, eFileLock, 1);
+-}
+-
+-#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
+-/*
+-** The code above is the NFS lock implementation. The code is specific
+-** to MacOSX and does not work on other unix platforms. No alternative
+-** is available.
+-**
+-********************* End of the NFS lock implementation **********************
+-******************************************************************************/
+
+ /******************************************************************************
+-**************** Non-locking sqlite3_file methods *****************************
++*************************** Posix Advisory Locking ****************************
+ **
+-** The next division contains implementations for all methods of the
+-** sqlite3_file object other than the locking methods. The locking
+-** methods were defined in divisions above (one locking method per
+-** division). Those methods that are common to all locking modes
+-** are gather together into this division.
++** POSIX advisory locks are broken by design. ANSI STD 1003.1 (1996)
++** section 6.5.2.2 lines 483 through 490 specify that when a process
++** sets or clears a lock, that operation overrides any prior locks set
++** by the same process. It does not explicitly say so, but this implies
++** that it overrides locks set by the same process using a different
++** file descriptor. Consider this test case:
++**
++** int fd1 = open("./file1", O_RDWR|O_CREAT, 0644);
++** int fd2 = open("./file2", O_RDWR|O_CREAT, 0644);
++**
++** Suppose ./file1 and ./file2 are really the same file (because
++** one is a hard or symbolic link to the other) then if you set
++** an exclusive lock on fd1, then try to get an exclusive lock
++** on fd2, it works. I would have expected the second lock to
++** fail since there was already a lock on the file due to fd1.
++** But not so. Since both locks came from the same process, the
++** second overrides the first, even though they were on different
++** file descriptors opened on different file names.
++**
++** This means that we cannot use POSIX locks to synchronize file access
++** among competing threads of the same process. POSIX locks will work fine
++** to synchronize access for threads in separate processes, but not
++** threads within the same process.
++**
++** To work around the problem, SQLite has to manage file locks internally
++** on its own. Whenever a new database is opened, we have to find the
++** specific inode of the database file (the inode is determined by the
++** st_dev and st_ino fields of the stat structure that fstat() fills in)
++** and check for locks already existing on that inode. When locks are
++** created or removed, we have to look at our own internal record of the
++** locks to see if another thread has previously set a lock on that same
++** inode.
++**
++** (Aside: The use of inode numbers as unique IDs does not work on VxWorks.
++** For VxWorks, we have to use the alternative unique ID system based on
++** canonical filename and implemented in the previous division.)
++**
++** The sqlite3_file structure for POSIX is no longer just an integer file
++** descriptor. It is now a structure that holds the integer file
++** descriptor and a pointer to a structure that describes the internal
++** locks on the corresponding inode. There is one locking structure
++** per inode, so if the same inode is opened twice, both unixFile structures
++** point to the same locking structure. The locking structure keeps
++** a reference count (so we will know when to delete it) and a "cnt"
++** field that tells us its internal lock status. cnt==0 means the
++** file is unlocked. cnt==-1 means the file has an exclusive lock.
++** cnt>0 means there are cnt shared locks on the file.
++**
++** Any attempt to lock or unlock a file first checks the locking
++** structure. The fcntl() system call is only invoked to set a
++** POSIX lock if the internal lock structure transitions between
++** a locked and an unlocked state.
++**
++** But wait: there are yet more problems with POSIX advisory locks.
++**
++** If you close a file descriptor that points to a file that has locks,
++** all locks on that file that are owned by the current process are
++** released. To work around this problem, each unixInodeInfo object
++** maintains a count of the number of pending locks on tha inode.
++** When an attempt is made to close an unixFile, if there are
++** other unixFile open on the same inode that are holding locks, the call
++** to close() the file descriptor is deferred until all of the locks clear.
++** The unixInodeInfo structure keeps a list of file descriptors that need to
++** be closed and that list is walked (and cleared) when the last lock
++** clears.
++**
++** Yet another problem: LinuxThreads do not play well with posix locks.
++**
++** Many older versions of linux use the LinuxThreads library which is
++** not posix compliant. Under LinuxThreads, a lock created by thread
++** A cannot be modified or overridden by a different thread B.
++** Only thread A can modify the lock. Locking behavior is correct
++** if the appliation uses the newer Native Posix Thread Library (NPTL)
++** on linux - with NPTL a lock created by thread A can override locks
++** in thread B. But there is no way to know at compile-time which
++** threading library is being used. So there is no way to know at
++** compile-time whether or not thread A can override locks on thread B.
++** One has to do a run-time check to discover the behavior of the
++** current process.
++**
++** SQLite used to support LinuxThreads. But support for LinuxThreads
++** was dropped beginning with version 3.7.0. SQLite will still work with
++** LinuxThreads provided that (1) there is no more than one connection
++** per database file in the same process and (2) database connections
++** do not move across threads.
+ */
+
+ /*
+-** Seek to the offset passed as the second argument, then read cnt
+-** bytes into pBuf. Return the number of bytes actually read.
+-**
+-** 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.
+-** See tickets #2741 and #2681.
+-**
+-** To avoid stomping the errno value on a failed read the lastErrno value
+-** is set before returning.
++** An instance of the following structure serves as the key used
++** to locate a particular unixInodeInfo object.
+ */
+-static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){
+- int got;
+- int prior = 0;
+-#if (!defined(USE_PREAD) && !defined(USE_PREAD64))
+- i64 newOffset;
+-#endif
+- TIMER_START;
+- assert( cnt==(cnt&0x1ffff) );
+- cnt &= 0x1ffff;
+- do{
+-#if defined(USE_PREAD)
+- got = osPread(id->h, pBuf, cnt, offset);
+- SimulateIOError( got = -1 );
+-#elif defined(USE_PREAD64)
+- got = osPread64(id->h, pBuf, cnt, offset);
+- SimulateIOError( got = -1 );
++struct unixFileId {
++ dev_t dev; /* Device number */
++#if OS_VXWORKS
++ struct vxworksFileId *pId; /* Unique file ID for vxworks. */
+ #else
+- newOffset = lseek(id->h, offset, SEEK_SET);
+- SimulateIOError( newOffset-- );
+- if( newOffset!=offset ){
+- if( newOffset == -1 ){
+- ((unixFile*)id)->lastErrno = errno;
+- }else{
+- ((unixFile*)id)->lastErrno = 0;
+- }
+- return -1;
+- }
+- got = osRead(id->h, pBuf, cnt);
++ ino_t ino; /* Inode number */
+ #endif
+- if( got==cnt ) break;
+- if( got<0 ){
+- if( errno==EINTR ){ got = 1; continue; }
+- prior = 0;
+- ((unixFile*)id)->lastErrno = errno;
+- break;
+- }else if( got>0 ){
+- cnt -= got;
+- offset += got;
+- prior += got;
+- pBuf = (void*)(got + (char*)pBuf);
+- }
+- }while( got>0 );
+- TIMER_END;
+- OSTRACE(("READ %-3d %5d %7lld %llu\n",
+- id->h, got+prior, offset-prior, TIMER_ELAPSED));
+- return got+prior;
+-}
++};
+
+ /*
+-** Read data from a file into a buffer. Return SQLITE_OK if all
+-** bytes were read successfully and SQLITE_IOERR if anything goes
+-** wrong.
++** An instance of the following structure is allocated for each open
++** inode. Or, on LinuxThreads, there is one of these structures for
++** each inode opened by each thread.
++**
++** A single inode can have multiple file descriptors, so each unixFile
++** structure contains a pointer to an instance of this object and this
++** object keeps a count of the number of unixFile pointing to it.
+ */
+-static int unixRead(
+- sqlite3_file *id,
+- void *pBuf,
+- int amt,
+- sqlite3_int64 offset
+-){
+- unixFile *pFile = (unixFile *)id;
+- int got;
+- assert( id );
+- assert( offset>=0 );
+- assert( amt>0 );
+-
+- /* If this is a database file (not a journal, master-journal or temp
+- ** file), the bytes in the locking range should never be read or written. */
+-#if 0
+- assert( pFile->pUnused==0
+- || offset>=PENDING_BYTE+512
+- || offset+amt<=PENDING_BYTE
+- );
++struct unixInodeInfo {
++ struct unixFileId fileId; /* The lookup key */
++ int nShared; /* Number of SHARED locks held */
++ unsigned char eFileLock; /* One of SHARED_LOCK, RESERVED_LOCK etc. */
++ unsigned char bProcessLock; /* An exclusive process lock is held */
++ int nRef; /* Number of pointers to this structure */
++ unixShmNode *pShmNode; /* Shared memory associated with this inode */
++ int nLock; /* Number of outstanding file locks */
++ UnixUnusedFd *pUnused; /* Unused file descriptors to close */
++ unixInodeInfo *pNext; /* List of all unixInodeInfo objects */
++ unixInodeInfo *pPrev; /* .... doubly linked */
++#if SQLITE_ENABLE_LOCKING_STYLE
++ unsigned long long sharedByte; /* for AFP simulated shared lock */
+ #endif
+-
+-#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);
+- return SQLITE_OK;
+- }else{
+- int nCopy = pFile->mmapSize - offset;
+- memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], nCopy);
+- pBuf = &((u8 *)pBuf)[nCopy];
+- amt -= nCopy;
+- offset += nCopy;
+- }
+- }
++#if OS_VXWORKS
++ sem_t *pSem; /* Named POSIX semaphore */
++ char aSemName[MAX_PATHNAME+2]; /* Name of that semaphore */
+ #endif
++};
+
+- got = seekAndRead(pFile, offset, pBuf, amt);
+- if( got==amt ){
+- return SQLITE_OK;
+- }else if( got<0 ){
+- /* lastErrno set by seekAndRead */
+- return SQLITE_IOERR_READ;
+- }else{
+- pFile->lastErrno = 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;
+- }
+-}
++/*
++** A lists of all unixInodeInfo objects.
++*/
++static unixInodeInfo *inodeList = 0;
+
+ /*
+-** Attempt to seek the file-descriptor passed as the first argument to
+-** absolute offset iOff, then attempt to write nBuf bytes of data from
+-** pBuf to it. If an error occurs, return -1 and set *piErrno. Otherwise,
+-** return the actual number of bytes written (which may be less than
+-** nBuf).
++**
++** This function - unixLogError_x(), is only ever called via the macro
++** unixLogError().
++**
++** It is invoked after an error occurs in an OS function and errno has been
++** set. It logs a message using sqlite3_log() containing the current value of
++** errno and, if possible, the human-readable equivalent from strerror() or
++** strerror_r().
++**
++** 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 (e.g. "unlink", "open") and the associated file-system path,
++** if any.
+ */
+-static int seekAndWriteFd(
+- int fd, /* File descriptor to write to */
+- i64 iOff, /* File offset to begin writing at */
+- const void *pBuf, /* Copy data from this buffer to the file */
+- int nBuf, /* Size of buffer pBuf in bytes */
+- int *piErrno /* OUT: Error number if error occurs */
++#define unixLogError(a,b,c) unixLogErrorAtLine(a,b,c,__LINE__)
++static int unixLogErrorAtLine(
++ int errcode, /* SQLite error code */
++ 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 */
+ ){
+- int rc = 0; /* Value returned by system call */
++ char *zErr; /* Message from strerror() or equivalent */
++ int iErrno = errno; /* Saved syscall error number */
+
+- assert( nBuf==(nBuf&0x1ffff) );
+- nBuf &= 0x1ffff;
+- TIMER_START;
++ /* If this is not a threadsafe build (SQLITE_THREADSAFE==0), then use
++ ** the strerror() function to obtain the human-readable error message
++ ** equivalent to errno. Otherwise, use strerror_r().
++ */
++#if SQLITE_THREADSAFE && defined(HAVE_STRERROR_R)
++ char aErr[80];
++ memset(aErr, 0, sizeof(aErr));
++ zErr = aErr;
+
+-#if defined(USE_PREAD)
+- do{ rc = 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);
+-#else
+- do{
+- i64 iSeek = lseek(fd, iOff, SEEK_SET);
+- SimulateIOError( iSeek-- );
++ /* If STRERROR_R_CHAR_P (set by autoconf scripts) or __USE_GNU is defined,
++ ** assume that the system provides the GNU version of strerror_r() that
++ ** returns a pointer to a buffer containing the error message. That pointer
++ ** may point to aErr[], or it may point to some static storage somewhere.
++ ** Otherwise, assume that the system provides the POSIX version of
++ ** strerror_r(), which always writes an error message into aErr[].
++ **
++ ** If the code incorrectly assumes that it is the POSIX version that is
++ ** available, the error message will often be an empty string. Not a
++ ** huge problem. Incorrectly concluding that the GNU version is available
++ ** could lead to a segfault though.
++ */
++#if defined(STRERROR_R_CHAR_P) || defined(__USE_GNU)
++ zErr =
++# endif
++ strerror_r(iErrno, aErr, sizeof(aErr)-1);
+
+- if( iSeek!=iOff ){
+- if( piErrno ) *piErrno = (iSeek==-1 ? errno : 0);
+- return -1;
+- }
+- rc = osWrite(fd, pBuf, nBuf);
+- }while( rc<0 && errno==EINTR );
++#elif SQLITE_THREADSAFE
++ /* This is a threadsafe build, but strerror_r() is not available. */
++ zErr = "";
++#else
++ /* Non-threadsafe build, use strerror(). */
++ zErr = strerror(iErrno);
+ #endif
+
+- TIMER_END;
+- OSTRACE(("WRITE %-3d %5d %7lld %llu\n", fd, rc, iOff, TIMER_ELAPSED));
++ if( zPath==0 ) zPath = "";
++ sqlite3_log(errcode,
++ "os_unix.c:%d: (%d) %s(%s) - %s",
++ iLine, iErrno, zFunc, zPath, zErr
++ );
+
+- if( rc<0 && piErrno ) *piErrno = errno;
+- return rc;
++ return errcode;
+ }
+
+-
+ /*
+-** Seek to the offset in id->offset then read cnt bytes into pBuf.
+-** Return the number of bytes actually read. Update the offset.
++** Close a file descriptor.
+ **
+-** To avoid stomping the errno value on a failed write the lastErrno value
+-** is set before returning.
++** We assume that close() almost always works, since it is only in a
++** very sick application or on a very sick platform that it might fail.
++** If it does fail, simply leak the file descriptor, but do log the
++** error.
++**
++** Note that it is not safe to retry close() after EINTR since the
++** file descriptor might have already been reused by another thread.
++** So we don't even try to recover from an EINTR. Just log the error
++** and move on.
+ */
+-static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){
+- return seekAndWriteFd(id->h, offset, pBuf, cnt, &id->lastErrno);
++static void robust_close(unixFile *pFile, int h, int lineno){
++ if( osClose(h) ){
++ unixLogErrorAtLine(SQLITE_IOERR_CLOSE, "close",
++ pFile ? pFile->zPath : 0, lineno);
++ }
+ }
+
++/*
++** Close all file descriptors accumuated in the unixInodeInfo->pUnused list.
++*/
++static void closePendingFds(unixFile *pFile){
++ unixInodeInfo *pInode = pFile->pInode;
++ UnixUnusedFd *p;
++ UnixUnusedFd *pNext;
++ for(p=pInode->pUnused; p; p=pNext){
++ pNext = p->pNext;
++ robust_close(pFile, p->fd, __LINE__);
++ sqlite3_free(p);
++ }
++ pInode->pUnused = 0;
++}
+
+ /*
+-** Write data from a buffer into a file. Return SQLITE_OK on success
+-** or some other error code on failure.
++** Release a unixInodeInfo structure previously allocated by findInodeInfo().
++**
++** The mutex entered using the unixEnterMutex() function must be held
++** when this function is called.
+ */
+-static int unixWrite(
+- sqlite3_file *id,
+- const void *pBuf,
+- int amt,
+- sqlite3_int64 offset
++static void releaseInodeInfo(unixFile *pFile){
++ unixInodeInfo *pInode = pFile->pInode;
++ assert( unixMutexHeld() );
++ if( ALWAYS(pInode) ){
++ pInode->nRef--;
++ if( pInode->nRef==0 ){
++ assert( pInode->pShmNode==0 );
++ closePendingFds(pFile);
++ if( pInode->pPrev ){
++ assert( pInode->pPrev->pNext==pInode );
++ pInode->pPrev->pNext = pInode->pNext;
++ }else{
++ assert( inodeList==pInode );
++ inodeList = pInode->pNext;
++ }
++ if( pInode->pNext ){
++ assert( pInode->pNext->pPrev==pInode );
++ pInode->pNext->pPrev = pInode->pPrev;
++ }
++ sqlite3_free(pInode);
++ }
++ }
++}
++
++/*
++** Given a file descriptor, locate the unixInodeInfo object that
++** describes that file descriptor. Create a new one if necessary. The
++** return value might be uninitialized if an error occurs.
++**
++** The mutex entered using the unixEnterMutex() function must be held
++** when this function is called.
++**
++** Return an appropriate error code.
++*/
++static int findInodeInfo(
++ unixFile *pFile, /* Unix file with file desc used in the key */
++ unixInodeInfo **ppInode /* Return the unixInodeInfo object here */
+ ){
+- unixFile *pFile = (unixFile*)id;
+- int wrote = 0;
+- assert( id );
+- assert( amt>0 );
++ int rc; /* System call return code */
++ int fd; /* The file descriptor for pFile */
++ struct unixFileId fileId; /* Lookup key for the unixInodeInfo */
++ struct stat statbuf; /* Low-level file information */
++ unixInodeInfo *pInode = 0; /* Candidate unixInodeInfo object */
+
+- /* If this is a database file (not a journal, master-journal or temp
+- ** file), the bytes in the locking range should never be read or written. */
+-#if 0
+- assert( pFile->pUnused==0
+- || offset>=PENDING_BYTE+512
+- || offset+amt<=PENDING_BYTE
+- );
+-#endif
++ assert( unixMutexHeld() );
+
+-#ifdef SQLITE_DEBUG
+- /* If we are doing a normal write to a database file (as opposed to
+- ** doing a hot-journal rollback or a write to some file other than a
+- ** normal database file) then record the fact that the database
+- ** has changed. If the transaction counter is modified, record that
+- ** fact too.
++ /* Get low-level information about the file that we can used to
++ ** create a unique name for the file.
+ */
+- if( pFile->inNormalWrite ){
+- pFile->dbUpdate = 1; /* The database has been modified */
+- if( offset<=24 && offset+amt>=27 ){
+- int rc;
+- char oldCntr[4];
+- SimulateIOErrorBenign(1);
+- rc = seekAndRead(pFile, 24, oldCntr, 4);
+- SimulateIOErrorBenign(0);
+- if( rc!=4 || memcmp(oldCntr, &((char*)pBuf)[24-offset], 4)!=0 ){
+- pFile->transCntrChng = 1; /* The transaction counter has changed */
+- }
+- }
+- }
++ fd = pFile->h;
++ rc = osFstat(fd, &statbuf);
++ if( rc!=0 ){
++ pFile->lastErrno = errno;
++#ifdef EOVERFLOW
++ if( pFile->lastErrno==EOVERFLOW ) return SQLITE_NOLFS;
+ #endif
++ return SQLITE_IOERR;
++ }
+
+-#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);
+- return SQLITE_OK;
+- }else{
+- int nCopy = pFile->mmapSize - offset;
+- memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, nCopy);
+- pBuf = &((u8 *)pBuf)[nCopy];
+- amt -= nCopy;
+- offset += nCopy;
++#ifdef __APPLE__
++ /* On OS X on an msdos filesystem, the inode number is reported
++ ** incorrectly for zero-size files. See ticket #3260. To work
++ ** around this problem (we consider it a bug in OS X, not SQLite)
++ ** we always increase the file size to 1 by writing a single byte
++ ** prior to accessing the inode number. The one byte written is
++ ** an ASCII 'S' character which also happens to be the first byte
++ ** in the header of every SQLite database. In this way, if there
++ ** is a race condition such that another thread has already populated
++ ** the first page of the database, no damage is done.
++ */
++ 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;
++ return SQLITE_IOERR;
++ }
++ rc = osFstat(fd, &statbuf);
++ if( rc!=0 ){
++ pFile->lastErrno = errno;
++ return SQLITE_IOERR;
+ }
+ }
+ #endif
+
+- while( amt>0 && (wrote = seekAndWrite(pFile, offset, pBuf, amt))>0 ){
+- amt -= wrote;
+- offset += wrote;
+- pBuf = &((char*)pBuf)[wrote];
++ memset(&fileId, 0, sizeof(fileId));
++ fileId.dev = statbuf.st_dev;
++#if OS_VXWORKS
++ fileId.pId = pFile->pId;
++#else
++ fileId.ino = statbuf.st_ino;
++#endif
++ pInode = inodeList;
++ while( pInode && memcmp(&fileId, &pInode->fileId, sizeof(fileId)) ){
++ pInode = pInode->pNext;
+ }
+- SimulateIOError(( wrote=(-1), amt=1 ));
+- SimulateDiskfullError(( wrote=0, amt=1 ));
+-
+- if( amt>0 ){
+- if( wrote<0 && pFile->lastErrno!=ENOSPC ){
+- /* lastErrno set by seekAndWrite */
+- return SQLITE_IOERR_WRITE;
+- }else{
+- pFile->lastErrno = 0; /* not a system error */
+- return SQLITE_FULL;
++ if( pInode==0 ){
++ pInode = sqlite3_malloc( sizeof(*pInode) );
++ if( pInode==0 ){
++ return SQLITE_NOMEM;
+ }
++ memset(pInode, 0, sizeof(*pInode));
++ memcpy(&pInode->fileId, &fileId, sizeof(fileId));
++ pInode->nRef = 1;
++ pInode->pNext = inodeList;
++ pInode->pPrev = 0;
++ if( inodeList ) inodeList->pPrev = pInode;
++ inodeList = pInode;
++ }else{
++ pInode->nRef++;
+ }
+-
++ *ppInode = pInode;
+ return SQLITE_OK;
+ }
+
+-#ifdef SQLITE_TEST
+-/*
+-** Count the number of fullsyncs and normal syncs. This is used to test
+-** that syncs and fullsyncs are occurring at the right times.
+-*/
+-SQLITE_API int sqlite3_sync_count = 0;
+-SQLITE_API int sqlite3_fullsync_count = 0;
+-#endif
+-
+-/*
+-** 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
+-*/
+-#if !defined(fdatasync)
+-# define fdatasync fsync
+-#endif
+
+ /*
+-** Define HAVE_FULLFSYNC to 0 or 1 depending on whether or not
+-** the F_FULLFSYNC macro is defined. F_FULLFSYNC is currently
+-** only available on Mac OS X. But that could change.
++** Check a unixFile that is a database. Verify the following:
++**
++** (1) There is exactly one hard link on the file
++** (2) The file is not a symbolic link
++** (3) The file has not been renamed or unlinked
++**
++** Issue sqlite3_log(SQLITE_WARNING,...) messages if anything is not right.
+ */
+-#ifdef F_FULLFSYNC
+-# define HAVE_FULLFSYNC 1
+-#else
+-# define HAVE_FULLFSYNC 0
+-#endif
++static void verifyDbFile(unixFile *pFile){
++ struct stat buf;
++ int rc;
++ if( pFile->ctrlFlags & UNIXFILE_WARNED ){
++ /* One or more of the following warnings have already been issued. Do not
++ ** repeat them so as not to clutter the error log */
++ return;
++ }
++ rc = osFstat(pFile->h, &buf);
++ if( rc!=0 ){
++ sqlite3_log(SQLITE_WARNING, "cannot fstat db file %s", pFile->zPath);
++ pFile->ctrlFlags |= UNIXFILE_WARNED;
++ return;
++ }
++ if( buf.st_nlink==0 && (pFile->ctrlFlags & UNIXFILE_DELETE)==0 ){
++ sqlite3_log(SQLITE_WARNING, "file unlinked while open: %s", pFile->zPath);
++ pFile->ctrlFlags |= UNIXFILE_WARNED;
++ return;
++ }
++ if( buf.st_nlink>1 ){
++ sqlite3_log(SQLITE_WARNING, "multiple links to file: %s", pFile->zPath);
++ pFile->ctrlFlags |= UNIXFILE_WARNED;
++ return;
++ }
++ if( pFile->pInode!=0
++ && ((rc = osStat(pFile->zPath, &buf))!=0
++ || buf.st_ino!=pFile->pInode->fileId.ino)
++ ){
++ sqlite3_log(SQLITE_WARNING, "file renamed while open: %s", pFile->zPath);
++ pFile->ctrlFlags |= UNIXFILE_WARNED;
++ return;
++ }
++}
+
+
+ /*
+-** The fsync() system call does not work as advertised on many
+-** unix systems. The following procedure is an attempt to make
+-** it work better.
+-**
+-** The SQLITE_NO_SYNC macro disables all fsync()s. This is useful
+-** for testing when we want to run through the test suite quickly.
+-** You are strongly advised *not* to deploy with SQLITE_NO_SYNC
+-** enabled, however, since with SQLITE_NO_SYNC enabled, an OS crash
+-** or power failure will likely corrupt the database file.
+-**
+-** SQLite sets the dataOnly flag if the size of the file is unchanged.
+-** The idea behind dataOnly is that it should only write the file content
+-** to disk, not the inode. We only set dataOnly if the file size is
+-** unchanged since the file size is part of the inode. However,
+-** Ted Ts'o tells us that fdatasync() will also write the inode if the
+-** file size has changed. The only real difference between fdatasync()
+-** and fsync(), Ted tells us, is that fdatasync() will not flush the
+-** inode if the mtime or owner or other inode attributes have changed.
+-** We only care about the file size, not the other file attributes, so
+-** as far as SQLite is concerned, an fdatasync() is always adequate.
+-** So, we always use fdatasync() if it is available, regardless of
+-** the value of the dataOnly flag.
++** 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, set *pResOut
++** 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 full_fsync(int fd, int fullSync, int dataOnly){
+- int rc;
++static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){
++ int rc = SQLITE_OK;
++ int reserved = 0;
++ unixFile *pFile = (unixFile*)id;
+
+- /* The following "ifdef/elif/else/" block has the same structure as
+- ** the one below. It is replicated here solely to avoid cluttering
+- ** up the real code with the UNUSED_PARAMETER() macros.
+- */
+-#ifdef SQLITE_NO_SYNC
+- UNUSED_PARAMETER(fd);
+- UNUSED_PARAMETER(fullSync);
+- UNUSED_PARAMETER(dataOnly);
+-#elif HAVE_FULLFSYNC
+- UNUSED_PARAMETER(dataOnly);
+-#else
+- UNUSED_PARAMETER(fullSync);
+- UNUSED_PARAMETER(dataOnly);
+-#endif
++ SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
+
+- /* Record the number of times that we do a normal fsync() and
+- ** FULLSYNC. This is used during testing to verify that this procedure
+- ** gets called with the correct arguments.
+- */
+-#ifdef SQLITE_TEST
+- if( fullSync ) sqlite3_fullsync_count++;
+- sqlite3_sync_count++;
+-#endif
++ assert( pFile );
++ unixEnterMutex(); /* Because pFile->pInode is shared across threads */
+
+- /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a
+- ** no-op
+- */
+-#ifdef SQLITE_NO_SYNC
+- rc = SQLITE_OK;
+-#elif HAVE_FULLFSYNC
+- if( fullSync ){
+- rc = osFcntl(fd, F_FULLFSYNC, 0);
+- }else{
+- rc = 1;
++ /* Check if a thread in this process holds such a lock */
++ if( pFile->pInode->eFileLock>SHARED_LOCK ){
++ reserved = 1;
+ }
+- /* If the FULLFSYNC failed, fall back to attempting an fsync().
+- ** It shouldn't be possible for fullfsync to fail on the local
+- ** file system (on OSX), so failure indicates that FULLFSYNC
+- ** isn't supported for this file system. So, attempt an fsync
+- ** and (for now) ignore the overhead of a superfluous fcntl call.
+- ** It'd be better to detect fullfsync support once and avoid
+- ** the fcntl call every time sync is called.
+- */
+- if( rc ) rc = fsync(fd);
+
+-#elif defined(__APPLE__)
+- /* fdatasync() on HFS+ doesn't yet flush the file size if it changed correctly
+- ** so currently we default to the macro that redefines fdatasync to fsync
++ /* Otherwise see if some other process holds it.
+ */
+- rc = fsync(fd);
+-#else
+- rc = fdatasync(fd);
+-#if OS_VXWORKS
+- if( rc==-1 && errno==ENOTSUP ){
+- rc = fsync(fd);
++#ifndef __DJGPP__
++ if( !reserved && !pFile->pInode->bProcessLock ){
++ struct flock lock;
++ lock.l_whence = SEEK_SET;
++ lock.l_start = RESERVED_BYTE;
++ lock.l_len = 1;
++ lock.l_type = F_WRLCK;
++ if( osFcntl(pFile->h, F_GETLK, &lock) ){
++ rc = SQLITE_IOERR_CHECKRESERVEDLOCK;
++ pFile->lastErrno = errno;
++ } else if( lock.l_type!=F_UNLCK ){
++ reserved = 1;
++ }
+ }
+-#endif /* OS_VXWORKS */
+-#endif /* ifdef SQLITE_NO_SYNC elif HAVE_FULLFSYNC */
++#endif
++
++ unixLeaveMutex();
++ OSTRACE(("TEST WR-LOCK %d %d %d (unix)\n", pFile->h, rc, reserved));
+
+- if( OS_VXWORKS && rc!= -1 ){
+- rc = 0;
+- }
++ *pResOut = reserved;
+ return rc;
+ }
+
+ /*
+-** Open a file descriptor to the directory containing file zFilename.
+-** If successful, *pFd is set to the opened file descriptor and
+-** SQLITE_OK is returned. If an error occurs, either SQLITE_NOMEM
+-** or SQLITE_CANTOPEN is returned and *pFd is set to an undefined
+-** value.
+-**
+-** The directory file descriptor is used for only one thing - to
+-** fsync() a directory to make sure file creation and deletion events
+-** are flushed to disk. Such fsyncs are not needed on newer
+-** journaling filesystems, but are required on older filesystems.
++** Attempt to set a system-lock on the file pFile. The lock is
++** described by pLock.
+ **
+-** This routine can be overridden using the xSetSysCall interface.
+-** The ability to override this routine was added in support of the
+-** chromium sandbox. Opening a directory is a security risk (we are
+-** told) so making it overrideable allows the chromium sandbox to
+-** replace this routine with a harmless no-op. To make this routine
+-** a no-op, replace it with a stub that returns SQLITE_OK but leaves
+-** *pFd set to a negative number.
++** If the pFile was opened read/write from unix-excl, then the only lock
++** ever obtained is an exclusive lock, and it is obtained exactly once
++** the first time any lock is attempted. All subsequent system locking
++** operations become no-ops. Locking operations still happen internally,
++** in order to coordinate access between separate database connections
++** within this process, but all of that is handled in memory and the
++** operating system does not participate.
+ **
+-** If SQLITE_OK is returned, the caller is responsible for closing
+-** the file descriptor *pFd using close().
+-*/
+-static int openDirectory(const char *zFilename, int *pFd){
+- int ii;
+- int fd = -1;
+- char zDirname[MAX_PATHNAME+1];
+-
+- sqlite3_snprintf(MAX_PATHNAME, zDirname, "%s", zFilename);
+- for(ii=(int)strlen(zDirname); ii>1 && zDirname[ii]!='/'; ii--);
+- if( ii>0 ){
+- zDirname[ii] = '\0';
+- fd = robust_open(zDirname, O_RDONLY|O_BINARY, 0);
+- if( fd>=0 ){
+- OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname));
++** This function is a pass-through to fcntl(F_SETLK) if pFile is using
++** any VFS other than "unix-excl" or if pFile is opened on "unix-excl"
++** and is read-only.
++**
++** Zero is returned if the call completes successfully, or -1 if a call
++** to fcntl() fails. In this case, errno is set appropriately (by fcntl()).
++*/
++static int unixFileLock(unixFile *pFile, struct flock *pLock){
++ int rc;
++ unixInodeInfo *pInode = pFile->pInode;
++ assert( unixMutexHeld() );
++ assert( pInode!=0 );
++ if( ((pFile->ctrlFlags & UNIXFILE_EXCL)!=0 || pInode->bProcessLock)
++ && ((pFile->ctrlFlags & UNIXFILE_RDONLY)==0)
++ ){
++ if( pInode->bProcessLock==0 ){
++ struct flock lock;
++ assert( pInode->nLock==0 );
++ lock.l_whence = SEEK_SET;
++ lock.l_start = SHARED_FIRST;
++ lock.l_len = SHARED_SIZE;
++ lock.l_type = F_WRLCK;
++ rc = osFcntl(pFile->h, F_SETLK, &lock);
++ if( rc<0 ) return rc;
++ pInode->bProcessLock = 1;
++ pInode->nLock++;
++ }else{
++ rc = 0;
+ }
++ }else{
++ rc = osFcntl(pFile->h, F_SETLK, pLock);
+ }
+- *pFd = fd;
+- return (fd>=0?SQLITE_OK:unixLogError(SQLITE_CANTOPEN_BKPT, "open", zDirname));
++ return rc;
+ }
+
+ /*
+-** Make sure all writes to a particular file are committed to disk.
++** Lock the file with the lock specified by parameter eFileLock - one
++** of the following:
+ **
+-** If dataOnly==0 then both the file itself and its metadata (file
+-** size, access time, etc) are synced. If dataOnly!=0 then only the
+-** file data is synced.
++** (1) SHARED_LOCK
++** (2) RESERVED_LOCK
++** (3) PENDING_LOCK
++** (4) EXCLUSIVE_LOCK
+ **
+-** Under Unix, also make sure that the directory entry for the file
+-** has been created by fsync-ing the directory that contains the file.
+-** If we do not do this and we encounter a power failure, the directory
+-** entry for the journal might not exist after we reboot. The next
+-** SQLite to access the file will not know that the journal exists (because
+-** the directory entry for the journal was never created) and the transaction
+-** will not roll back - possibly leading to database corruption.
++** 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. Use the sqlite3OsUnlock()
++** routine to lower a locking level.
+ */
+-static int unixSync(sqlite3_file *id, int flags){
+- int rc;
++static int unixLock(sqlite3_file *id, int eFileLock){
++ /* The following describes the implementation of the various locks and
++ ** lock transitions in terms of the POSIX advisory shared and exclusive
++ ** lock primitives (called read-locks and write-locks below, to avoid
++ ** confusion with SQLite lock names). The algorithms are complicated
++ ** slightly in order to be compatible with windows systems simultaneously
++ ** accessing the same database file, in case that is ever required.
++ **
++ ** Symbols defined in os.h indentify the 'pending byte' and the 'reserved
++ ** byte', each single bytes at well known offsets, and the 'shared byte
++ ** range', a range of 510 bytes at a well known offset.
++ **
++ ** To obtain a SHARED lock, a read-lock is obtained on the 'pending
++ ** byte'. If this is successful, a random byte from the 'shared byte
++ ** range' is read-locked and the lock on the 'pending byte' released.
++ **
++ ** A process may only obtain a RESERVED lock after it has a SHARED lock.
++ ** A RESERVED lock is implemented by grabbing a write-lock on the
++ ** 'reserved byte'.
++ **
++ ** A process may only obtain a PENDING lock after it has obtained a
++ ** SHARED lock. A PENDING lock is implemented by obtaining a write-lock
++ ** on the 'pending byte'. This ensures that no new SHARED locks can be
++ ** obtained, but existing SHARED locks are allowed to persist. A process
++ ** does not have to obtain a RESERVED lock on the way to a PENDING lock.
++ ** This property is used by the algorithm for rolling back a journal file
++ ** after a crash.
++ **
++ ** An EXCLUSIVE lock, obtained after a PENDING lock is held, is
++ ** implemented by obtaining a write-lock on the entire 'shared byte
++ ** range'. Since all other locks require a read-lock on one of the bytes
++ ** within this range, this ensures that no other locks are held on the
++ ** database.
++ **
++ ** The reason a single byte cannot be used instead of the 'shared byte
++ ** range' is that some versions of windows do not support read-locks. By
++ ** locking a random byte from a range, concurrent SHARED locks may exist
++ ** even if the locking primitive used is always a write-lock.
++ */
++ int rc = SQLITE_OK;
+ unixFile *pFile = (unixFile*)id;
++ unixInodeInfo *pInode;
++ struct flock lock;
++ int tErrno = 0;
+
+- int isDataOnly = (flags&SQLITE_SYNC_DATAONLY);
+- int isFullsync = (flags&0x0F)==SQLITE_SYNC_FULL;
++ 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()));
+
+- /* Check that one of SQLITE_SYNC_NORMAL or FULL was passed */
+- assert((flags&0x0F)==SQLITE_SYNC_NORMAL
+- || (flags&0x0F)==SQLITE_SYNC_FULL
+- );
++ /* 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
++ ** unixEnterMutex() hasn't been called yet.
++ */
++ if( pFile->eFileLock>=eFileLock ){
++ OSTRACE(("LOCK %d %s ok (already held) (unix)\n", pFile->h,
++ azFileLock(eFileLock)));
++ return SQLITE_OK;
++ }
+
+- /* Unix cannot, but some systems may return SQLITE_FULL from here. This
+- ** line is to test that doing so does not cause any problems.
++ /* Make sure the locking sequence is correct.
++ ** (1) We never move from unlocked to anything higher than shared lock.
++ ** (2) SQLite never explicitly requests a pendig lock.
++ ** (3) A shared lock is always held when a reserve lock is requested.
+ */
+- SimulateDiskfullError( return SQLITE_FULL );
++ assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK );
++ assert( eFileLock!=PENDING_LOCK );
++ assert( eFileLock!=RESERVED_LOCK || pFile->eFileLock==SHARED_LOCK );
+
+- assert( pFile );
+- OSTRACE(("SYNC %-3d\n", pFile->h));
+- rc = full_fsync(pFile->h, isFullsync, isDataOnly);
+- SimulateIOError( rc=1 );
+- if( rc ){
+- pFile->lastErrno = errno;
+- return unixLogError(SQLITE_IOERR_FSYNC, "full_fsync", pFile->zPath);
++ /* This mutex is needed because pFile->pInode is shared across threads
++ */
++ unixEnterMutex();
++ pInode = pFile->pInode;
++
++ /* If some thread using this PID has a lock via a different unixFile*
++ ** handle that precludes the requested lock, return BUSY.
++ */
++ if( (pFile->eFileLock!=pInode->eFileLock &&
++ (pInode->eFileLock>=PENDING_LOCK || eFileLock>SHARED_LOCK))
++ ){
++ rc = SQLITE_BUSY;
++ goto end_lock;
+ }
+
+- /* Also fsync the directory containing the file if the DIRSYNC flag
+- ** is set. This is a one-time occurrence. Many systems (examples: AIX)
+- ** are unable to fsync a directory, so ignore errors on the fsync.
++ /* If a SHARED lock is requested, and some thread using this PID already
++ ** has a SHARED or RESERVED lock, then increment reference counts and
++ ** return SQLITE_OK.
+ */
+- if( pFile->ctrlFlags & UNIXFILE_DIRSYNC ){
+- int dirfd;
+- OSTRACE(("DIRSYNC %s (have_fullfsync=%d fullsync=%d)\n", pFile->zPath,
+- HAVE_FULLFSYNC, isFullsync));
+- rc = osOpenDirectory(pFile->zPath, &dirfd);
+- if( rc==SQLITE_OK && dirfd>=0 ){
+- full_fsync(dirfd, 0, 0);
+- robust_close(pFile, dirfd, __LINE__);
+- }else if( rc==SQLITE_CANTOPEN ){
+- rc = SQLITE_OK;
+- }
+- pFile->ctrlFlags &= ~UNIXFILE_DIRSYNC;
++ if( eFileLock==SHARED_LOCK &&
++ (pInode->eFileLock==SHARED_LOCK || pInode->eFileLock==RESERVED_LOCK) ){
++ assert( eFileLock==SHARED_LOCK );
++ assert( pFile->eFileLock==0 );
++ assert( pInode->nShared>0 );
++ pFile->eFileLock = SHARED_LOCK;
++ pInode->nShared++;
++ pInode->nLock++;
++ goto end_lock;
+ }
+- return rc;
+-}
+
+-/*
+-** Truncate an open file to a specified size
+-*/
+-static int unixTruncate(sqlite3_file *id, i64 nByte){
+- unixFile *pFile = (unixFile *)id;
+- int rc;
+- assert( pFile );
+- SimulateIOError( return SQLITE_IOERR_TRUNCATE );
+
+- /* 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).
++ /* A PENDING lock is needed before acquiring a SHARED lock and before
++ ** acquiring an EXCLUSIVE lock. For the SHARED lock, the PENDING will
++ ** be released.
+ */
+- if( pFile->szChunk>0 ){
+- nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
++ lock.l_len = 1L;
++ lock.l_whence = SEEK_SET;
++ if( eFileLock==SHARED_LOCK
++ || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock<PENDING_LOCK)
++ ){
++ lock.l_type = (eFileLock==SHARED_LOCK?F_RDLCK:F_WRLCK);
++ lock.l_start = PENDING_BYTE;
++ if( unixFileLock(pFile, &lock) ){
++ tErrno = errno;
++ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
++ if( rc!=SQLITE_BUSY ){
++ pFile->lastErrno = tErrno;
++ }
++ goto end_lock;
++ }
+ }
+
+- rc = robust_ftruncate(pFile->h, (off_t)nByte);
+- if( rc ){
+- pFile->lastErrno = errno;
+- return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
+- }else{
+-#ifdef SQLITE_DEBUG
+- /* If we are doing a normal write to a database file (as opposed to
+- ** doing a hot-journal rollback or a write to some file other than a
+- ** normal database file) and we truncate the file to zero length,
+- ** that effectively updates the change counter. This might happen
+- ** when restoring a database using the backup API from a zero-length
+- ** source.
+- */
+- if( pFile->inNormalWrite && nByte==0 ){
+- pFile->transCntrChng = 1;
++
++ /* If control gets to this point, then actually go ahead and make
++ ** operating system calls for the specified lock.
++ */
++ if( eFileLock==SHARED_LOCK ){
++ assert( pInode->nShared==0 );
++ assert( pInode->eFileLock==0 );
++ assert( rc==SQLITE_OK );
++
++ /* Now get the read-lock */
++ lock.l_start = SHARED_FIRST;
++ lock.l_len = SHARED_SIZE;
++ if( unixFileLock(pFile, &lock) ){
++ tErrno = errno;
++ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
+ }
+-#endif
+
+- /* If the file was just 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.
++ /* Drop the temporary PENDING lock */
++ lock.l_start = PENDING_BYTE;
++ lock.l_len = 1L;
++ lock.l_type = F_UNLCK;
++ if( unixFileLock(pFile, &lock) && rc==SQLITE_OK ){
++ /* This could happen with a network mount */
++ tErrno = errno;
++ rc = SQLITE_IOERR_UNLOCK;
++ }
++
++ if( rc ){
++ if( rc!=SQLITE_BUSY ){
++ pFile->lastErrno = tErrno;
++ }
++ goto end_lock;
++ }else{
++ pFile->eFileLock = SHARED_LOCK;
++ pInode->nLock++;
++ pInode->nShared = 1;
++ }
++ }else if( eFileLock==EXCLUSIVE_LOCK && pInode->nShared>1 ){
++ /* We are trying for an exclusive lock but another thread in this
++ ** same process is still holding a shared lock. */
++ rc = SQLITE_BUSY;
++ }else{
++ /* The request was for a RESERVED or EXCLUSIVE lock. It is
++ ** assumed that there is a SHARED or greater lock on the file
++ ** already.
+ */
+- if( nByte<pFile->mmapSize ){
+- pFile->mmapSize = nByte;
++ assert( 0!=pFile->eFileLock );
++ lock.l_type = F_WRLCK;
++
++ assert( eFileLock==RESERVED_LOCK || eFileLock==EXCLUSIVE_LOCK );
++ if( eFileLock==RESERVED_LOCK ){
++ lock.l_start = RESERVED_BYTE;
++ lock.l_len = 1L;
++ }else{
++ lock.l_start = SHARED_FIRST;
++ lock.l_len = SHARED_SIZE;
+ }
+
+- return SQLITE_OK;
++ if( unixFileLock(pFile, &lock) ){
++ tErrno = errno;
++ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
++ if( rc!=SQLITE_BUSY ){
++ pFile->lastErrno = tErrno;
++ }
++ }
+ }
+-}
++
+
+-/*
+-** Determine the current size of a file in bytes
+-*/
+-static int unixFileSize(sqlite3_file *id, i64 *pSize){
+- int rc;
+- struct stat buf;
+- assert( id );
+- rc = osFstat(((unixFile*)id)->h, &buf);
+- SimulateIOError( rc=1 );
+- if( rc!=0 ){
+- ((unixFile*)id)->lastErrno = errno;
+- return SQLITE_IOERR_FSTAT;
++#ifdef SQLITE_DEBUG
++ /* Set up the transaction-counter change checking flags when
++ ** transitioning from a SHARED to a RESERVED lock. The change
++ ** from SHARED to RESERVED marks the beginning of a normal
++ ** write operation (not a hot journal rollback).
++ */
++ if( rc==SQLITE_OK
++ && pFile->eFileLock<=SHARED_LOCK
++ && eFileLock==RESERVED_LOCK
++ ){
++ pFile->transCntrChng = 0;
++ pFile->dbUpdate = 0;
++ pFile->inNormalWrite = 1;
+ }
+- *pSize = buf.st_size;
++#endif
+
+- /* When opening a zero-size database, the findInodeInfo() procedure
+- ** writes a single byte into that file in order to work around a bug
+- ** in the OS-X msdos filesystem. In order to avoid problems with upper
+- ** layers, we need to report this file size as zero even though it is
+- ** really 1. Ticket #3260.
+- */
+- if( *pSize==1 ) *pSize = 0;
+
++ if( rc==SQLITE_OK ){
++ pFile->eFileLock = eFileLock;
++ pInode->eFileLock = eFileLock;
++ }else if( eFileLock==EXCLUSIVE_LOCK ){
++ pFile->eFileLock = PENDING_LOCK;
++ pInode->eFileLock = PENDING_LOCK;
++ }
+
+- return SQLITE_OK;
++end_lock:
++ unixLeaveMutex();
++ OSTRACE(("LOCK %d %s %s (unix)\n", pFile->h, azFileLock(eFileLock),
++ rc==SQLITE_OK ? "ok" : "failed"));
++ return rc;
+ }
+
+-#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
+ /*
+-** Handler for proxy-locking file-control verbs. Defined below in the
+-** proxying locking division.
++** Add the file descriptor used by file handle pFile to the corresponding
++** pUnused list.
+ */
+-static int proxyFileControl(sqlite3_file*,int,void*);
+-#endif
++static void setPendingFd(unixFile *pFile){
++ unixInodeInfo *pInode = pFile->pInode;
++ UnixUnusedFd *p = pFile->pUnused;
++ p->pNext = pInode->pUnused;
++ pInode->pUnused = p;
++ pFile->h = -1;
++ pFile->pUnused = 0;
++}
+
+-/*
+-** This function is called to handle the SQLITE_FCNTL_SIZE_HINT
+-** file-control operation. Enlarge the database to nBytes in size
+-** (rounded up to the next chunk-size). If the database is already
+-** nBytes or larger, this routine is a no-op.
++/*
++** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
++** 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.
++**
++** If handleNFSUnlock is true, then on downgrading an EXCLUSIVE_LOCK to SHARED
++** the byte range is divided into 2 parts and the first part is unlocked then
++** set to a read lock, then the other part is simply unlocked. This works
++** around a bug in BSD NFS lockd (also seen on MacOSX 10.3+) that fails to
++** remove the write lock on a region when a read lock is set.
+ */
+-static int fcntlSizeHint(unixFile *pFile, i64 nByte){
+- if( pFile->szChunk>0 ){
+- i64 nSize; /* Required file size */
+- struct stat buf; /* Used to hold return values of fstat() */
+-
+- if( osFstat(pFile->h, &buf) ) return SQLITE_IOERR_FSTAT;
++static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
++ unixFile *pFile = (unixFile*)id;
++ unixInodeInfo *pInode;
++ struct flock lock;
++ int rc = SQLITE_OK;
+
+- nSize = ((nByte+pFile->szChunk-1) / pFile->szChunk) * pFile->szChunk;
+- if( nSize>(i64)buf.st_size ){
++ 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()));
+
+-#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
+- /* The code below is handling the return value of osFallocate()
+- ** correctly. posix_fallocate() is defined to "returns zero on success,
+- ** or an error number on failure". See the manpage for details. */
+- int err;
+- do{
+- err = osFallocate(pFile->h, buf.st_size, nSize-buf.st_size);
+- }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.
+- */
+- int nBlk = buf.st_blksize; /* File-system block size */
+- i64 iWrite; /* Next offset to write to */
++ assert( eFileLock<=SHARED_LOCK );
++ if( pFile->eFileLock<=eFileLock ){
++ return SQLITE_OK;
++ }
++ unixEnterMutex();
++ pInode = pFile->pInode;
++ assert( pInode->nShared!=0 );
++ if( pFile->eFileLock>SHARED_LOCK ){
++ assert( pInode->eFileLock==pFile->eFileLock );
+
+- 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);
+- if( nWrite!=1 ) return SQLITE_IOERR_WRITE;
+- iWrite += nBlk;
++#ifdef SQLITE_DEBUG
++ /* When reducing a lock such that other processes can start
++ ** reading the database file again, make sure that the
++ ** transaction counter was updated if any part of the database
++ ** file changed. If the transaction counter is not updated,
++ ** other connections to the same file might not realize that
++ ** the file has changed and hence might not know to flush their
++ ** cache. The use of a stale cache can lead to database corruption.
++ */
++ pFile->inNormalWrite = 0;
++#endif
++
++ /* downgrading to a shared lock on NFS involves clearing the write lock
++ ** before establishing the readlock - to avoid a race condition we downgrade
++ ** the lock in 2 blocks, so that part of the range will be covered by a
++ ** write lock until the rest is covered by a read lock:
++ ** 1: [WWWWW]
++ ** 2: [....W]
++ ** 3: [RRRRW]
++ ** 4: [RRRR.]
++ */
++ if( eFileLock==SHARED_LOCK ){
++
++#if !defined(__APPLE__) || !SQLITE_ENABLE_LOCKING_STYLE
++ (void)handleNFSUnlock;
++ assert( handleNFSUnlock==0 );
++#endif
++#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
++ if( handleNFSUnlock ){
++ int tErrno; /* Error code from system call errors */
++ off_t divSize = SHARED_SIZE - 1;
++
++ lock.l_type = F_UNLCK;
++ lock.l_whence = SEEK_SET;
++ lock.l_start = SHARED_FIRST;
++ lock.l_len = divSize;
++ if( unixFileLock(pFile, &lock)==(-1) ){
++ tErrno = errno;
++ rc = SQLITE_IOERR_UNLOCK;
++ if( IS_LOCK_ERROR(rc) ){
++ pFile->lastErrno = tErrno;
++ }
++ goto end_unlock;
++ }
++ lock.l_type = F_RDLCK;
++ lock.l_whence = SEEK_SET;
++ lock.l_start = SHARED_FIRST;
++ lock.l_len = divSize;
++ if( unixFileLock(pFile, &lock)==(-1) ){
++ tErrno = errno;
++ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);
++ if( IS_LOCK_ERROR(rc) ){
++ pFile->lastErrno = tErrno;
++ }
++ goto end_unlock;
++ }
++ lock.l_type = F_UNLCK;
++ lock.l_whence = SEEK_SET;
++ lock.l_start = SHARED_FIRST+divSize;
++ lock.l_len = SHARED_SIZE-divSize;
++ if( unixFileLock(pFile, &lock)==(-1) ){
++ tErrno = errno;
++ rc = SQLITE_IOERR_UNLOCK;
++ if( IS_LOCK_ERROR(rc) ){
++ pFile->lastErrno = tErrno;
++ }
++ goto end_unlock;
++ }
++ }else
++#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
++ {
++ lock.l_type = F_RDLCK;
++ lock.l_whence = SEEK_SET;
++ lock.l_start = SHARED_FIRST;
++ lock.l_len = SHARED_SIZE;
++ if( unixFileLock(pFile, &lock) ){
++ /* In theory, the call to unixFileLock() cannot fail because another
++ ** process is holding an incompatible lock. If it does, this
++ ** indicates that the other process is not following the locking
++ ** protocol. If this happens, return SQLITE_IOERR_RDLOCK. Returning
++ ** SQLITE_BUSY would confuse the upper layer (in practice it causes
++ ** an assert to fail). */
++ rc = SQLITE_IOERR_RDLOCK;
++ pFile->lastErrno = errno;
++ goto end_unlock;
++ }
+ }
+-#endif
++ }
++ lock.l_type = F_UNLCK;
++ lock.l_whence = SEEK_SET;
++ lock.l_start = PENDING_BYTE;
++ lock.l_len = 2L; assert( PENDING_BYTE+1==RESERVED_BYTE );
++ if( unixFileLock(pFile, &lock)==0 ){
++ pInode->eFileLock = SHARED_LOCK;
++ }else{
++ rc = SQLITE_IOERR_UNLOCK;
++ pFile->lastErrno = errno;
++ goto end_unlock;
+ }
+ }
+-
+- if( pFile->mmapSizeMax>0 && nByte>pFile->mmapSize ){
+- int rc;
+- if( pFile->szChunk<=0 ){
+- if( robust_ftruncate(pFile->h, nByte) ){
++ if( eFileLock==NO_LOCK ){
++ /* Decrement the shared lock counter. Release the lock using an
++ ** OS call only when all threads in this same process have released
++ ** the lock.
++ */
++ pInode->nShared--;
++ if( pInode->nShared==0 ){
++ lock.l_type = F_UNLCK;
++ lock.l_whence = SEEK_SET;
++ lock.l_start = lock.l_len = 0L;
++ if( unixFileLock(pFile, &lock)==0 ){
++ pInode->eFileLock = NO_LOCK;
++ }else{
++ rc = SQLITE_IOERR_UNLOCK;
+ pFile->lastErrno = errno;
+- return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
++ pInode->eFileLock = NO_LOCK;
++ pFile->eFileLock = NO_LOCK;
+ }
+ }
+
+- rc = unixMapfile(pFile, nByte);
+- return rc;
++ /* Decrement the count of locks against this same file. When the
++ ** count reaches zero, close any other file descriptors whose close
++ ** was deferred because of outstanding locks.
++ */
++ pInode->nLock--;
++ assert( pInode->nLock>=0 );
++ if( pInode->nLock==0 ){
++ closePendingFds(pFile);
++ }
+ }
+
+- return SQLITE_OK;
++end_unlock:
++ unixLeaveMutex();
++ if( rc==SQLITE_OK ) pFile->eFileLock = eFileLock;
++ return rc;
+ }
+
+ /*
+-** If *pArg is inititially negative then this is a query. Set *pArg to
+-** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set.
++** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
++** must be either NO_LOCK or SHARED_LOCK.
+ **
+-** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags.
++** If the locking level of the file descriptor is already at or below
++** the requested locking level, this routine is a no-op.
+ */
+-static void unixModeBit(unixFile *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 int unixUnlock(sqlite3_file *id, int eFileLock){
++ assert( eFileLock==SHARED_LOCK || ((unixFile *)id)->nFetchOut==0 );
++ return posixUnlock(id, eFileLock, 0);
+ }
+
+-/* Forward declaration */
+-static int unixGetTempname(int nBuf, char *zBuf);
++static int unixMapfile(unixFile *pFd, i64 nByte);
++static void unixUnmapfile(unixFile *pFd);
+
+ /*
+-** Information and control of an open file handle.
++** This function performs the parts of the "close file" operation
++** common to all locking schemes. It closes the directory and file
++** handles, if they are valid, and sets all fields of the unixFile
++** structure to 0.
++**
++** It is *not* necessary to hold the mutex when this routine is called,
++** even on VxWorks. A mutex will be acquired on VxWorks by the
++** vxworksReleaseFileId() routine.
+ */
+-static int unixFileControl(sqlite3_file *id, int op, void *pArg){
++static int closeUnixFile(sqlite3_file *id){
+ unixFile *pFile = (unixFile*)id;
+- switch( op ){
+- case SQLITE_FCNTL_LOCKSTATE: {
+- *(int*)pArg = pFile->eFileLock;
+- return SQLITE_OK;
+- }
+- case SQLITE_LAST_ERRNO: {
+- *(int*)pArg = pFile->lastErrno;
+- return SQLITE_OK;
+- }
+- case SQLITE_FCNTL_CHUNK_SIZE: {
+- pFile->szChunk = *(int *)pArg;
+- return SQLITE_OK;
+- }
+- case SQLITE_FCNTL_SIZE_HINT: {
+- int rc;
+- SimulateIOErrorBenign(1);
+- rc = fcntlSizeHint(pFile, *(i64 *)pArg);
+- SimulateIOErrorBenign(0);
+- return rc;
+- }
+- case SQLITE_FCNTL_PERSIST_WAL: {
+- unixModeBit(pFile, UNIXFILE_PERSIST_WAL, (int*)pArg);
+- return SQLITE_OK;
+- }
+- case SQLITE_FCNTL_POWERSAFE_OVERWRITE: {
+- unixModeBit(pFile, UNIXFILE_PSOW, (int*)pArg);
+- return SQLITE_OK;
+- }
+- case SQLITE_FCNTL_VFSNAME: {
+- *(char**)pArg = sqlite3_mprintf("%s", pFile->pVfs->zName);
+- return SQLITE_OK;
+- }
+- case SQLITE_FCNTL_TEMPFILENAME: {
+- char *zTFile = sqlite3_malloc( pFile->pVfs->mxPathname );
+- if( zTFile ){
+- unixGetTempname(pFile->pVfs->mxPathname, zTFile);
+- *(char**)pArg = zTFile;
+- }
+- return SQLITE_OK;
+- }
+- case SQLITE_FCNTL_MMAP_SIZE: {
+- i64 newLimit = *(i64*)pArg;
+- if( newLimit>sqlite3GlobalConfig.mxMmap ){
+- newLimit = sqlite3GlobalConfig.mxMmap;
+- }
+- *(i64*)pArg = pFile->mmapSizeMax;
+- if( newLimit>=0 ){
+- pFile->mmapSizeMax = newLimit;
+- if( newLimit<pFile->mmapSize ) pFile->mmapSize = newLimit;
+- }
+- return SQLITE_OK;
+- }
+-#ifdef SQLITE_DEBUG
+- /* The pager calls this method to signal that it has done
+- ** a rollback and that the database is therefore unchanged and
+- ** it hence it is OK for the transaction change counter to be
+- ** unchanged.
+- */
+- case SQLITE_FCNTL_DB_UNCHANGED: {
+- ((unixFile*)id)->dbUpdate = 0;
+- return SQLITE_OK;
+- }
+-#endif
+-#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
+- case SQLITE_SET_LOCKPROXYFILE:
+- case SQLITE_GET_LOCKPROXYFILE: {
+- return proxyFileControl(id,op,pArg);
++ unixUnmapfile(pFile);
++ if( pFile->h>=0 ){
++ robust_close(pFile, pFile->h, __LINE__);
++ pFile->h = -1;
++ }
++#if OS_VXWORKS
++ if( pFile->pId ){
++ if( pFile->ctrlFlags & UNIXFILE_DELETE ){
++ osUnlink(pFile->pId->zCanonicalName);
+ }
+-#endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */
++ vxworksReleaseFileId(pFile->pId);
++ pFile->pId = 0;
+ }
+- return SQLITE_NOTFOUND;
++#endif
++ OSTRACE(("CLOSE %-3d\n", pFile->h));
++ OpenCounter(-1);
++ sqlite3_free(pFile->pUnused);
++ memset(pFile, 0, sizeof(unixFile));
++ return SQLITE_OK;
+ }
+
+ /*
+-** 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.
++** Close a file.
+ */
+-#ifndef __QNXNTO__
+-static int unixSectorSize(sqlite3_file *NotUsed){
+- UNUSED_PARAMETER(NotUsed);
+- return SQLITE_DEFAULT_SECTOR_SIZE;
++static int unixClose(sqlite3_file *id){
++ int rc = SQLITE_OK;
++ unixFile *pFile = (unixFile *)id;
++ verifyDbFile(pFile);
++ unixUnlock(id, NO_LOCK);
++ unixEnterMutex();
++
++ /* unixFile.pInode is always valid here. Otherwise, a different close
++ ** routine (e.g. nolockClose()) would be called instead.
++ */
++ assert( pFile->pInode->nLock>0 || pFile->pInode->bProcessLock==0 );
++ if( ALWAYS(pFile->pInode) && pFile->pInode->nLock ){
++ /* If there are outstanding locks, do not actually close the file just
++ ** yet because that would clear those locks. Instead, add the file
++ ** descriptor to pInode->pUnused list. It will be automatically closed
++ ** when the last lock is cleared.
++ */
++ setPendingFd(pFile);
++ }
++ releaseInodeInfo(pFile);
++ rc = closeUnixFile(id);
++ unixLeaveMutex();
++ return rc;
+ }
+-#endif
+
+-/*
+-** The following version of unixSectorSize() is optimized for QNX.
++/************** End of the posix advisory lock implementation *****************
++******************************************************************************/
++
++/******************************************************************************
++****************************** No-op Locking **********************************
++**
++** Of the various locking implementations available, this is by far the
++** simplest: locking is ignored. No attempt is made to lock the database
++** file for reading or writing.
++**
++** This locking mode is appropriate for use on read-only databases
++** (ex: databases that are burned into CD-ROM, for example.) It can
++** also be used if the application employs some external mechanism to
++** prevent simultaneous access of the same database by two or more
++** database connections. But there is a serious risk of database
++** corruption if this locking mode is used in situations where multiple
++** database connections are accessing the same database file at the same
++** time and one or more of those connections are writing.
+ */
+-#ifdef __QNXNTO__
+-#include <sys/dcmd_blk.h>
+-#include <sys/statvfs.h>
+-static int unixSectorSize(sqlite3_file *id){
+- unixFile *pFile = (unixFile*)id;
+- if( pFile->sectorSize == 0 ){
+- struct statvfs fsInfo;
+-
+- /* Set defaults for non-supported filesystems */
+- pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
+- pFile->deviceCharacteristics = 0;
+- if( fstatvfs(pFile->h, &fsInfo) == -1 ) {
+- return pFile->sectorSize;
+- }
+
+- if( !strcmp(fsInfo.f_basetype, "tmp") ) {
+- pFile->sectorSize = fsInfo.f_bsize;
+- pFile->deviceCharacteristics =
+- SQLITE_IOCAP_ATOMIC4K | /* All ram filesystem writes are atomic */
+- SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until
+- ** the write succeeds */
+- SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
+- ** so it is ordered */
+- 0;
+- }else if( strstr(fsInfo.f_basetype, "etfs") ){
+- pFile->sectorSize = fsInfo.f_bsize;
+- pFile->deviceCharacteristics =
+- /* etfs cluster size writes are atomic */
+- (pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) |
+- SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until
+- ** the write succeeds */
+- SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
+- ** so it is ordered */
+- 0;
+- }else if( !strcmp(fsInfo.f_basetype, "qnx6") ){
+- pFile->sectorSize = fsInfo.f_bsize;
+- pFile->deviceCharacteristics =
+- SQLITE_IOCAP_ATOMIC | /* All filesystem writes are atomic */
+- SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until
+- ** the write succeeds */
+- SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
+- ** so it is ordered */
+- 0;
+- }else if( !strcmp(fsInfo.f_basetype, "qnx4") ){
+- pFile->sectorSize = fsInfo.f_bsize;
+- pFile->deviceCharacteristics =
+- /* full bitset of atomics from max sector size and smaller */
+- ((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2 |
+- SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
+- ** so it is ordered */
+- 0;
+- }else if( strstr(fsInfo.f_basetype, "dos") ){
+- pFile->sectorSize = fsInfo.f_bsize;
+- pFile->deviceCharacteristics =
+- /* full bitset of atomics from max sector size and smaller */
+- ((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2 |
+- SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
+- ** so it is ordered */
+- 0;
+- }else{
+- pFile->deviceCharacteristics =
+- SQLITE_IOCAP_ATOMIC512 | /* blocks are atomic */
+- SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until
+- ** the write succeeds */
+- 0;
+- }
+- }
+- /* Last chance verification. If the sector size isn't a multiple of 512
+- ** then it isn't valid.*/
+- if( pFile->sectorSize % 512 != 0 ){
+- pFile->deviceCharacteristics = 0;
+- pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
+- }
+- return pFile->sectorSize;
++static int nolockCheckReservedLock(sqlite3_file *NotUsed, int *pResOut){
++ UNUSED_PARAMETER(NotUsed);
++ *pResOut = 0;
++ return SQLITE_OK;
++}
++static int nolockLock(sqlite3_file *NotUsed, int NotUsed2){
++ UNUSED_PARAMETER2(NotUsed, NotUsed2);
++ return SQLITE_OK;
++}
++static int nolockUnlock(sqlite3_file *NotUsed, int NotUsed2){
++ UNUSED_PARAMETER2(NotUsed, NotUsed2);
++ return SQLITE_OK;
+ }
+-#endif /* __QNXNTO__ */
+
+ /*
+-** 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
+-** 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,
+-** very rare. And asserting PSOW makes a large reduction in the amount
+-** of required I/O for journaling, since a lot of padding is eliminated.
+-** Hence, while POWERSAFE_OVERWRITE is on by default, there is a file-control
+-** available to turn it off and URI query parameter available to turn it off.
++** Close the file.
+ */
+-static int unixDeviceCharacteristics(sqlite3_file *id){
+- unixFile *p = (unixFile*)id;
+- int rc = 0;
+-#ifdef __QNXNTO__
+- if( p->sectorSize==0 ) unixSectorSize(id);
+- rc = p->deviceCharacteristics;
+-#endif
+- if( p->ctrlFlags & UNIXFILE_PSOW ){
+- rc |= SQLITE_IOCAP_POWERSAFE_OVERWRITE;
+- }
+- return rc;
++static int nolockClose(sqlite3_file *id) {
++ return closeUnixFile(id);
+ }
+
+-#ifndef SQLITE_OMIT_WAL
+-
++/******************* End of the no-op lock implementation *********************
++******************************************************************************/
+
+-/*
+-** Object used to represent an shared memory buffer.
+-**
+-** When multiple threads all reference the same wal-index, each thread
+-** has its own unixShm object, but they all point to a single instance
+-** of this unixShmNode object. In other words, each wal-index is opened
+-** only once per process.
+-**
+-** Each unixShmNode object is connected to a single unixInodeInfo object.
+-** We could coalesce this object into unixInodeInfo, but that would mean
+-** every open file that does not use shared memory (in other words, most
+-** open files) would have to carry around this extra information. So
+-** the unixInodeInfo object contains a pointer to this unixShmNode object
+-** and the unixShmNode object is created only when needed.
+-**
+-** unixMutexHeld() must be true when creating or destroying
+-** this object or while reading or writing the following fields:
+-**
+-** nRef
++/******************************************************************************
++************************* Begin dot-file Locking ******************************
+ **
+-** The following fields are read-only after the object is created:
+-**
+-** fid
+-** zFilename
++** The dotfile locking implementation uses the existence of separate lock
++** files (really a directory) to control access to the database. This works
++** on just about every filesystem imaginable. But there are serious downsides:
+ **
+-** Either unixShmNode.mutex must be held or unixShmNode.nRef==0 and
+-** unixMutexHeld() is true when reading or writing any other field
+-** in this structure.
+-*/
+-struct unixShmNode {
+- unixInodeInfo *pInode; /* unixInodeInfo that owns this SHM node */
+- sqlite3_mutex *mutex; /* Mutex to access this object */
+- char *zFilename; /* Name of the mmapped file */
+- int h; /* Open file descriptor */
+- int szRegion; /* Size of shared-memory regions */
+- u16 nRegion; /* Size of array apRegion */
+- u8 isReadonly; /* True if read-only */
+- char **apRegion; /* Array of mapped shared-memory regions */
+- int nRef; /* Number of unixShm objects pointing to this */
+- unixShm *pFirst; /* All unixShm objects pointing to this */
+-#ifdef SQLITE_DEBUG
+- u8 exclMask; /* Mask of exclusive locks held */
+- u8 sharedMask; /* Mask of shared locks held */
+- u8 nextShmId; /* Next available unixShm.id value */
+-#endif
+-};
+-
+-/*
+-** Structure used internally by this VFS to record the state of an
+-** open shared memory connection.
++** (1) There is zero concurrency. A single reader blocks all other
++** connections from reading or writing the database.
+ **
+-** The following fields are initialized when this object is created and
+-** are read-only thereafter:
++** (2) An application crash or power loss can leave stale lock files
++** sitting around that need to be cleared manually.
+ **
+-** unixShm.pFile
+-** unixShm.id
++** Nevertheless, a dotlock is an appropriate locking mode for use if no
++** other locking strategy is available.
+ **
+-** All other fields are read/write. The unixShm.pFile->mutex must be held
+-** while accessing any read/write fields.
++** Dotfile locking works by creating a subdirectory in the same directory as
++** the database and with the same name but with a ".lock" extension added.
++** The existence of a lock directory implies an EXCLUSIVE lock. All other
++** lock types (SHARED, RESERVED, PENDING) are mapped into EXCLUSIVE.
+ */
+-struct unixShm {
+- unixShmNode *pShmNode; /* The underlying unixShmNode object */
+- unixShm *pNext; /* Next unixShm with the same unixShmNode */
+- u8 hasMutex; /* True if holding the unixShmNode mutex */
+- u8 id; /* Id of this connection within its unixShmNode */
+- u16 sharedMask; /* Mask of shared locks held */
+- u16 exclMask; /* Mask of exclusive locks held */
+-};
+
+ /*
+-** Constants used for locking
++** The file suffix added to the data base filename in order to create the
++** lock directory.
+ */
+-#define UNIX_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */
+-#define UNIX_SHM_DMS (UNIX_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */
++#define DOTLOCK_SUFFIX ".lock"
+
+ /*
+-** Apply posix advisory locks for all bytes from ofst through ofst+n-1.
++** 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, set *pResOut
++** 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.
+ **
+-** Locks block if the mask is exactly UNIX_SHM_C and are non-blocking
+-** otherwise.
++** In dotfile locking, either a lock exists or it does not. So in this
++** variation of CheckReservedLock(), *pResOut is set to true if any lock
++** is held on the file and false if the file is unlocked.
+ */
+-static int unixShmSystemLock(
+- unixShmNode *pShmNode, /* Apply locks to this open shared-memory segment */
+- 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() */
+-
+- /* Access to the unixShmNode object is serialized by the caller */
+- assert( sqlite3_mutex_held(pShmNode->mutex) || pShmNode->nRef==0 );
+-
+- /* Shared locks never span more than one byte */
+- assert( n==1 || lockType!=F_RDLCK );
+-
+- /* Locks are within range */
+- assert( n>=1 && n<SQLITE_SHM_NLOCK );
+-
+- if( pShmNode->h>=0 ){
+- /* Initialize the locking parameters */
+- memset(&f, 0, sizeof(f));
+- f.l_type = lockType;
+- f.l_whence = SEEK_SET;
+- f.l_start = ofst;
+- f.l_len = n;
+-
+- rc = osFcntl(pShmNode->h, F_SETLK, &f);
+- rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY;
+- }
+-
+- /* Update the global lock state and do debug tracing */
+-#ifdef SQLITE_DEBUG
+- { u16 mask;
+- OSTRACE(("SHM-LOCK "));
+- mask = (1<<(ofst+n)) - (1<<ofst);
+- if( rc==SQLITE_OK ){
+- if( lockType==F_UNLCK ){
+- OSTRACE(("unlock %d ok", ofst));
+- pShmNode->exclMask &= ~mask;
+- pShmNode->sharedMask &= ~mask;
+- }else if( lockType==F_RDLCK ){
+- OSTRACE(("read-lock %d ok", ofst));
+- pShmNode->exclMask &= ~mask;
+- pShmNode->sharedMask |= mask;
+- }else{
+- assert( lockType==F_WRLCK );
+- OSTRACE(("write-lock %d ok", ofst));
+- pShmNode->exclMask |= mask;
+- pShmNode->sharedMask &= ~mask;
+- }
+- }else{
+- if( lockType==F_UNLCK ){
+- OSTRACE(("unlock %d failed", ofst));
+- }else if( lockType==F_RDLCK ){
+- OSTRACE(("read-lock failed"));
+- }else{
+- assert( lockType==F_WRLCK );
+- OSTRACE(("write-lock %d failed", ofst));
+- }
+- }
+- OSTRACE((" - afterwards %03x,%03x\n",
+- pShmNode->sharedMask, pShmNode->exclMask));
+- }
+-#endif
+-
+- return rc;
+-}
++static int dotlockCheckReservedLock(sqlite3_file *id, int *pResOut) {
++ int rc = SQLITE_OK;
++ int reserved = 0;
++ unixFile *pFile = (unixFile*)id;
+
++ SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
++
++ assert( pFile );
+
+-/*
+-** Purge the unixShmNodeList list of all entries with unixShmNode.nRef==0.
+-**
+-** This is not a VFS shared-memory method; it is a utility function called
+-** by VFS shared-memory methods.
+-*/
+-static void unixShmPurge(unixFile *pFd){
+- unixShmNode *p = pFd->pInode->pShmNode;
+- assert( unixMutexHeld() );
+- if( p && p->nRef==0 ){
+- int i;
+- assert( p->pInode==pFd->pInode );
+- sqlite3_mutex_free(p->mutex);
+- for(i=0; i<p->nRegion; i++){
+- if( p->h>=0 ){
+- osMunmap(p->apRegion[i], p->szRegion);
+- }else{
+- sqlite3_free(p->apRegion[i]);
+- }
+- }
+- sqlite3_free(p->apRegion);
+- if( p->h>=0 ){
+- robust_close(pFd, p->h, __LINE__);
+- p->h = -1;
+- }
+- p->pInode->pShmNode = 0;
+- sqlite3_free(p);
++ /* Check if a thread in this process holds such a lock */
++ if( pFile->eFileLock>SHARED_LOCK ){
++ /* Either this connection or some other connection in the same process
++ ** holds a lock on the file. No need to check further. */
++ reserved = 1;
++ }else{
++ /* The lock is held if and only if the lockfile exists */
++ const char *zLockFile = (const char*)pFile->lockingContext;
++ reserved = osAccess(zLockFile, 0)==0;
+ }
++ OSTRACE(("TEST WR-LOCK %d %d %d (dotlock)\n", pFile->h, rc, reserved));
++ *pResOut = reserved;
++ return rc;
+ }
+
+ /*
+-** Open a shared-memory area associated with open database file pDbFd.
+-** This particular implementation uses mmapped files.
++** Lock the file with the lock specified by parameter eFileLock - one
++** of the following:
+ **
+-** The file used to implement shared-memory is in the same directory
+-** as the open database file and has the same name as the open database
+-** file with the "-shm" suffix added. For example, if the database file
+-** is "/home/user1/config.db" then the file that is created and mmapped
+-** for shared memory will be called "/home/user1/config.db-shm".
++** (1) SHARED_LOCK
++** (2) RESERVED_LOCK
++** (3) PENDING_LOCK
++** (4) EXCLUSIVE_LOCK
+ **
+-** Another approach to is to use files in /dev/shm or /dev/tmp or an
+-** some other tmpfs mount. But if a file in a different directory
+-** from the database file is used, then differing access permissions
+-** or a chroot() might cause two different processes on the same
+-** database to end up using different files for shared memory -
+-** meaning that their memory would not really be shared - resulting
+-** in database corruption. Nevertheless, this tmpfs file usage
+-** can be enabled at compile-time using -DSQLITE_SHM_DIRECTORY="/dev/shm"
+-** or the equivalent. The use of the SQLITE_SHM_DIRECTORY compile-time
+-** option results in an incompatible build of SQLite; builds of SQLite
+-** that with differing SQLITE_SHM_DIRECTORY settings attempt to use the
+-** same database file at the same time, database corruption will likely
+-** result. The SQLITE_SHM_DIRECTORY compile-time option is considered
+-** "unsupported" and may go away in a future SQLite release.
++** 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:
+ **
+-** 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.
++** UNLOCKED -> SHARED
++** SHARED -> RESERVED
++** SHARED -> (PENDING) -> EXCLUSIVE
++** RESERVED -> (PENDING) -> EXCLUSIVE
++** PENDING -> EXCLUSIVE
+ **
+-** If the original database file (pDbFd) is using the "unix-excl" VFS
+-** that means that an exclusive lock is held on the database file and
+-** that no other processes are able to read or write the database. In
+-** that case, we do not really need shared memory. No shared memory
+-** file is created. The shared memory will be simulated with heap memory.
++** This routine will only increase a lock. Use the sqlite3OsUnlock()
++** routine to lower a locking level.
++**
++** With dotfile locking, we really only support state (4): EXCLUSIVE.
++** But we track the other locking levels internally.
+ */
+-static int unixOpenSharedMemory(unixFile *pDbFd){
+- struct unixShm *p = 0; /* The connection to be opened */
+- struct unixShmNode *pShmNode; /* The underlying mmapped file */
+- int rc; /* Result code */
+- unixInodeInfo *pInode; /* The inode of fd */
+- char *zShmFilename; /* Name of the file used for SHM */
+- int nShmFilename; /* Size of the SHM filename in bytes */
++static int dotlockLock(sqlite3_file *id, int eFileLock) {
++ unixFile *pFile = (unixFile*)id;
++ char *zLockFile = (char *)pFile->lockingContext;
++ int rc = SQLITE_OK;
+
+- /* Allocate space for the new unixShm object. */
+- p = sqlite3_malloc( sizeof(*p) );
+- if( p==0 ) return SQLITE_NOMEM;
+- memset(p, 0, sizeof(*p));
+- assert( pDbFd->pShm==0 );
+
+- /* Check to see if a unixShmNode object already exists. Reuse an existing
+- ** one if present. Create a new one if necessary.
++ /* If we have any lock, then the lock file already exists. All we have
++ ** to do is adjust our internal record of the lock level.
+ */
+- unixEnterMutex();
+- pInode = pDbFd->pInode;
+- pShmNode = pInode->pShmNode;
+- if( pShmNode==0 ){
+- struct stat sStat; /* fstat() info for database file */
+-
+- /* 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
+- ** with the same permissions.
+- */
+- if( osFstat(pDbFd->h, &sStat) && pInode->bProcessLock==0 ){
+- rc = SQLITE_IOERR_FSTAT;
+- goto shm_open_err;
+- }
+-
+-#ifdef SQLITE_SHM_DIRECTORY
+- nShmFilename = sizeof(SQLITE_SHM_DIRECTORY) + 31;
+-#else
+- nShmFilename = 6 + (int)strlen(pDbFd->zPath);
+-#endif
+- pShmNode = sqlite3_malloc( sizeof(*pShmNode) + nShmFilename );
+- if( pShmNode==0 ){
+- rc = SQLITE_NOMEM;
+- goto shm_open_err;
+- }
+- memset(pShmNode, 0, sizeof(*pShmNode)+nShmFilename);
+- zShmFilename = pShmNode->zFilename = (char*)&pShmNode[1];
+-#ifdef SQLITE_SHM_DIRECTORY
+- sqlite3_snprintf(nShmFilename, zShmFilename,
+- SQLITE_SHM_DIRECTORY "/sqlite-shm-%x-%x",
+- (u32)sStat.st_ino, (u32)sStat.st_dev);
++ if( pFile->eFileLock > NO_LOCK ){
++ pFile->eFileLock = eFileLock;
++ /* Always update the timestamp on the old file */
++#ifdef HAVE_UTIME
++ utime(zLockFile, NULL);
+ #else
+- sqlite3_snprintf(nShmFilename, zShmFilename, "%s-shm", pDbFd->zPath);
+- sqlite3FileSuffix3(pDbFd->zPath, zShmFilename);
++ utimes(zLockFile, NULL);
+ #endif
+- pShmNode->h = -1;
+- pDbFd->pInode->pShmNode = pShmNode;
+- pShmNode->pInode = pDbFd->pInode;
+- pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
+- if( pShmNode->mutex==0 ){
+- rc = SQLITE_NOMEM;
+- goto shm_open_err;
+- }
+-
+- if( pInode->bProcessLock==0 ){
+- int openFlags = O_RDWR | O_CREAT;
+- if( sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){
+- openFlags = O_RDONLY;
+- pShmNode->isReadonly = 1;
+- }
+- pShmNode->h = robust_open(zShmFilename, openFlags, (sStat.st_mode&0777));
+- if( pShmNode->h<0 ){
+- rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename);
+- goto shm_open_err;
+- }
+-
+- /* If this process is running as root, make sure that the SHM file
+- ** is owned by the same user that owns the original database. Otherwise,
+- ** the original owner will not be able to connect.
+- */
+- osFchown(pShmNode->h, sStat.st_uid, sStat.st_gid);
++ return SQLITE_OK;
++ }
+
+- /* Check to see if another process is holding the dead-man switch.
+- ** If not, truncate the file to zero length.
+- */
+- rc = SQLITE_OK;
+- if( unixShmSystemLock(pShmNode, 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);
++ /* grab an exclusive lock */
++ rc = osMkdir(zLockFile, 0777);
++ if( rc<0 ){
++ /* failed to open/create the lock directory */
++ int tErrno = errno;
++ if( EEXIST == tErrno ){
++ rc = SQLITE_BUSY;
++ } else {
++ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
++ if( IS_LOCK_ERROR(rc) ){
++ pFile->lastErrno = tErrno;
+ }
+- if( rc ) goto shm_open_err;
+ }
+- }
+-
+- /* Make the new connection a child of the unixShmNode */
+- p->pShmNode = pShmNode;
+-#ifdef SQLITE_DEBUG
+- p->id = pShmNode->nextShmId++;
+-#endif
+- pShmNode->nRef++;
+- pDbFd->pShm = p;
+- unixLeaveMutex();
+-
+- /* The reference count on pShmNode has already been incremented under
+- ** the cover of the unixEnterMutex() mutex and the pointer from the
+- ** new (struct unixShm) 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:
+- unixShmPurge(pDbFd); /* This call frees pShmNode if required */
+- sqlite3_free(p);
+- unixLeaveMutex();
++ return rc;
++ }
++
++ /* got it, set the type and return ok */
++ pFile->eFileLock = eFileLock;
+ return rc;
+ }
+
+ /*
+-** 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.
++** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
++** must be either NO_LOCK or SHARED_LOCK.
+ **
+-** Otherwise, if the bExtend 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
+-** bExtend is non-zero and the requested shared-memory region has not yet
+-** been allocated, it is allocated by this function.
++** If the locking level of the file descriptor is already at or below
++** the requested locking level, this routine is a no-op.
+ **
+-** 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.
++** When the locking level reaches NO_LOCK, delete the lock file.
+ */
+-static int unixShmMap(
+- sqlite3_file *fd, /* Handle open on database file */
+- int iRegion, /* Region to retrieve */
+- int szRegion, /* Size of regions */
+- int bExtend, /* True to extend file if necessary */
+- void volatile **pp /* OUT: Mapped memory */
+-){
+- unixFile *pDbFd = (unixFile*)fd;
+- unixShm *p;
+- unixShmNode *pShmNode;
+- int rc = SQLITE_OK;
++static int dotlockUnlock(sqlite3_file *id, int eFileLock) {
++ unixFile *pFile = (unixFile*)id;
++ char *zLockFile = (char *)pFile->lockingContext;
++ int rc;
+
+- /* If the shared-memory file has not yet been opened, open it now. */
+- if( pDbFd->pShm==0 ){
+- rc = unixOpenSharedMemory(pDbFd);
+- if( rc!=SQLITE_OK ) return rc;
++ assert( pFile );
++ OSTRACE(("UNLOCK %d %d was %d pid=%d (dotlock)\n", pFile->h, eFileLock,
++ pFile->eFileLock, getpid()));
++ assert( eFileLock<=SHARED_LOCK );
++
++ /* no-op if possible */
++ if( pFile->eFileLock==eFileLock ){
++ return SQLITE_OK;
+ }
+
+- p = pDbFd->pShm;
+- pShmNode = p->pShmNode;
+- sqlite3_mutex_enter(pShmNode->mutex);
+- assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
+- assert( pShmNode->pInode==pDbFd->pInode );
+- assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 );
+- assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 );
+-
+- if( pShmNode->nRegion<=iRegion ){
+- char **apNew; /* New apRegion[] array */
+- int nByte = (iRegion+1)*szRegion; /* Minimum required file size */
+- struct stat sStat; /* Used by fstat() */
+-
+- pShmNode->szRegion = szRegion;
+-
+- if( pShmNode->h>=0 ){
+- /* 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).
+- */
+- if( osFstat(pShmNode->h, &sStat) ){
+- rc = SQLITE_IOERR_SHMSIZE;
+- goto shmpage_out;
+- }
++ /* To downgrade to shared, simply update our internal notion of the
++ ** lock state. No need to mess with the file on disk.
++ */
++ if( eFileLock==SHARED_LOCK ){
++ pFile->eFileLock = SHARED_LOCK;
++ return SQLITE_OK;
++ }
+
+- if( sStat.st_size<nByte ){
+- /* The requested memory region does not exist. If bExtend is set to
+- ** false, exit early. *pp will be set to NULL and SQLITE_OK returned.
+- */
+- if( !bExtend ){
+- goto shmpage_out;
+- }
+-
+- /* Alternatively, if bExtend is true, extend the file. Do this by
+- ** writing a single byte to the end of each (OS) page being
+- ** allocated or extended. Technically, we need only write to the
+- ** last page in order to extend the file. But writing to all new
+- ** pages forces the OS to allocate them immediately, which reduces
+- ** the chances of SIGBUS while accessing the mapped region later on.
+- */
+- else{
+- static const int pgsz = 4096;
+- int iPg;
+-
+- /* Write to the last byte of each newly allocated or extended page */
+- assert( (nByte % pgsz)==0 );
+- for(iPg=(sStat.st_size/pgsz); iPg<(nByte/pgsz); iPg++){
+- if( seekAndWriteFd(pShmNode->h, iPg*pgsz + pgsz-1, "", 1, 0)!=1 ){
+- const char *zFile = pShmNode->zFilename;
+- rc = unixLogError(SQLITE_IOERR_SHMSIZE, "write", zFile);
+- goto shmpage_out;
+- }
+- }
+- }
+- }
+- }
+-
+- /* Map the requested memory region into this processes address space. */
+- apNew = (char **)sqlite3_realloc(
+- pShmNode->apRegion, (iRegion+1)*sizeof(char *)
+- );
+- if( !apNew ){
+- rc = SQLITE_IOERR_NOMEM;
+- goto shmpage_out;
++ /* To fully unlock the database, delete the lock file */
++ assert( eFileLock==NO_LOCK );
++ rc = osRmdir(zLockFile);
++ if( rc<0 && errno==ENOTDIR ) rc = osUnlink(zLockFile);
++ if( rc<0 ){
++ int tErrno = errno;
++ rc = 0;
++ if( ENOENT != tErrno ){
++ rc = SQLITE_IOERR_UNLOCK;
+ }
+- pShmNode->apRegion = apNew;
+- while(pShmNode->nRegion<=iRegion){
+- void *pMem;
+- if( pShmNode->h>=0 ){
+- pMem = osMmap(0, szRegion,
+- pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE,
+- MAP_SHARED, pShmNode->h, szRegion*(i64)pShmNode->nRegion
+- );
+- if( pMem==MAP_FAILED ){
+- rc = unixLogError(SQLITE_IOERR_SHMMAP, "mmap", pShmNode->zFilename);
+- goto shmpage_out;
+- }
+- }else{
+- pMem = sqlite3_malloc(szRegion);
+- if( pMem==0 ){
+- rc = SQLITE_NOMEM;
+- goto shmpage_out;
+- }
+- memset(pMem, 0, szRegion);
+- }
+- pShmNode->apRegion[pShmNode->nRegion] = pMem;
+- pShmNode->nRegion++;
++ if( IS_LOCK_ERROR(rc) ){
++ pFile->lastErrno = tErrno;
+ }
++ return rc;
+ }
++ pFile->eFileLock = NO_LOCK;
++ return SQLITE_OK;
++}
+
+-shmpage_out:
+- if( pShmNode->nRegion>iRegion ){
+- *pp = pShmNode->apRegion[iRegion];
+- }else{
+- *pp = 0;
++/*
++** Close a file. Make sure the lock has been released before closing.
++*/
++static int dotlockClose(sqlite3_file *id) {
++ int rc = SQLITE_OK;
++ if( id ){
++ unixFile *pFile = (unixFile*)id;
++ dotlockUnlock(id, NO_LOCK);
++ sqlite3_free(pFile->lockingContext);
++ rc = closeUnixFile(id);
+ }
+- if( pShmNode->isReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY;
+- sqlite3_mutex_leave(pShmNode->mutex);
+ return rc;
+ }
++/****************** End of the dot-file lock implementation *******************
++******************************************************************************/
+
+-/*
+-** Change the lock state for a shared-memory segment.
++/******************************************************************************
++************************** Begin flock Locking ********************************
+ **
+-** Note that the relationship between SHAREd and EXCLUSIVE locks is a little
+-** different here than in posix. In xShmLock(), one can go from unlocked
+-** to shared and back or from unlocked to exclusive and back. But one may
+-** not go from shared to exclusive or from exclusive to shared.
++** Use the flock() system call to do file locking.
++**
++** flock() locking is like dot-file locking in that the various
++** fine-grain locking levels supported by SQLite are collapsed into
++** a single exclusive lock. In other words, SHARED, RESERVED, and
++** PENDING locks are the same thing as an EXCLUSIVE lock. SQLite
++** 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.
+ */
+-static int unixShmLock(
+- 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 */
+-){
+- unixFile *pDbFd = (unixFile*)fd; /* Connection holding shared memory */
+- unixShm *p = pDbFd->pShm; /* The shared memory being locked */
+- unixShm *pX; /* For looping over all siblings */
+- unixShmNode *pShmNode = p->pShmNode; /* The underlying file iNode */
+- int rc = SQLITE_OK; /* Result code */
+- u16 mask; /* Mask of locks to take or release */
+-
+- assert( pShmNode==pDbFd->pInode->pShmNode );
+- assert( pShmNode->pInode==pDbFd->pInode );
+- 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 );
+- assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 );
+- assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 );
+-
+- mask = (1<<(ofst+n)) - (1<<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 */
+-
+- /* 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;
+- }
+-
+- /* Unlock the system-level locks */
+- if( (mask & allMask)==0 ){
+- rc = unixShmSystemLock(pShmNode, F_UNLCK, ofst+UNIX_SHM_BASE, n);
+- }else{
+- rc = SQLITE_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" */
+-
+- /* 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;
+- }
++#if SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS
+
+- /* 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);
+- }else{
+- rc = SQLITE_OK;
+- }
+- }
++/*
++** Retry flock() calls that fail with EINTR
++*/
++#ifdef EINTR
++static int robust_flock(int fd, int op){
++ int rc;
++ do{ rc = flock(fd,op); }while( rc<0 && errno==EINTR );
++ return rc;
++}
++#else
++# define robust_flock(a,b) flock(a,b)
++#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;
+- }
+- }
++/*
++** 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, set *pResOut
++** 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 flockCheckReservedLock(sqlite3_file *id, int *pResOut){
++ int rc = SQLITE_OK;
++ int reserved = 0;
++ unixFile *pFile = (unixFile*)id;
+
+- /* Get the exclusive locks at the system level. Then if successful
+- ** also mark the local connection as being locked.
+- */
+- if( rc==SQLITE_OK ){
+- rc = unixShmSystemLock(pShmNode, F_WRLCK, ofst+UNIX_SHM_BASE, n);
+- if( rc==SQLITE_OK ){
+- assert( (p->sharedMask & mask)==0 );
+- p->exclMask |= mask;
++ SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
++
++ assert( pFile );
++
++ /* Check if a thread in this process holds such a lock */
++ if( pFile->eFileLock>SHARED_LOCK ){
++ reserved = 1;
++ }
++
++ /* Otherwise see if some other process holds it. */
++ if( !reserved ){
++ /* attempt to get the lock */
++ int lrc = robust_flock(pFile->h, LOCK_EX | LOCK_NB);
++ if( !lrc ){
++ /* got the lock, unlock it */
++ lrc = robust_flock(pFile->h, LOCK_UN);
++ if ( lrc ) {
++ int tErrno = errno;
++ /* unlock failed with an error */
++ lrc = SQLITE_IOERR_UNLOCK;
++ if( IS_LOCK_ERROR(lrc) ){
++ pFile->lastErrno = tErrno;
++ rc = lrc;
++ }
++ }
++ } else {
++ int tErrno = errno;
++ reserved = 1;
++ /* someone else might have it reserved */
++ lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
++ if( IS_LOCK_ERROR(lrc) ){
++ pFile->lastErrno = tErrno;
++ rc = lrc;
+ }
+ }
+ }
+- sqlite3_mutex_leave(pShmNode->mutex);
+- OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n",
+- p->id, getpid(), p->sharedMask, p->exclMask));
++ OSTRACE(("TEST WR-LOCK %d %d %d (flock)\n", pFile->h, rc, reserved));
++
++#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
++ if( (rc & SQLITE_IOERR) == SQLITE_IOERR ){
++ rc = SQLITE_OK;
++ reserved=1;
++ }
++#endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */
++ *pResOut = reserved;
+ return rc;
+ }
+
+ /*
+-** Implement a memory barrier or memory fence on shared memory.
++** Lock the file with the lock specified by parameter eFileLock - one
++** of the following:
+ **
+-** All loads and stores begun before the barrier must complete before
+-** any load or store begun after the barrier.
+-*/
+-static void unixShmBarrier(
+- sqlite3_file *fd /* Database file holding the shared memory */
+-){
+- UNUSED_PARAMETER(fd);
+- unixEnterMutex();
+- unixLeaveMutex();
+-}
+-
+-/*
+-** Close a connection to shared-memory. Delete the underlying
+-** storage if deleteFlag is true.
++** (1) SHARED_LOCK
++** (2) RESERVED_LOCK
++** (3) PENDING_LOCK
++** (4) EXCLUSIVE_LOCK
+ **
+-** If there is no shared memory associated with the connection then this
+-** routine is a harmless no-op.
++** 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
++**
++** flock() only really support EXCLUSIVE locks. We track intermediate
++** lock states in the sqlite3_file structure, but all locks SHARED or
++** above are really EXCLUSIVE locks and exclude all other processes from
++** access the file.
++**
++** This routine will only increase a lock. Use the sqlite3OsUnlock()
++** routine to lower a locking level.
+ */
+-static int unixShmUnmap(
+- sqlite3_file *fd, /* The underlying database file */
+- int deleteFlag /* Delete shared-memory if true */
+-){
+- unixShm *p; /* The connection to be closed */
+- unixShmNode *pShmNode; /* The underlying shared-memory file */
+- unixShm **pp; /* For looping over sibling connections */
+- unixFile *pDbFd; /* The underlying database file */
+-
+- pDbFd = (unixFile*)fd;
+- p = pDbFd->pShm;
+- if( p==0 ) return SQLITE_OK;
+- pShmNode = p->pShmNode;
+-
+- assert( pShmNode==pDbFd->pInode->pShmNode );
+- assert( pShmNode->pInode==pDbFd->pInode );
+-
+- /* 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;
++static int flockLock(sqlite3_file *id, int eFileLock) {
++ int rc = SQLITE_OK;
++ unixFile *pFile = (unixFile*)id;
+
+- /* Free the connection p */
+- sqlite3_free(p);
+- pDbFd->pShm = 0;
+- sqlite3_mutex_leave(pShmNode->mutex);
++ assert( pFile );
+
+- /* If pShmNode->nRef has reached 0, then close the underlying
+- ** shared-memory file, too */
+- unixEnterMutex();
+- assert( pShmNode->nRef>0 );
+- pShmNode->nRef--;
+- if( pShmNode->nRef==0 ){
+- if( deleteFlag && pShmNode->h>=0 ) osUnlink(pShmNode->zFilename);
+- unixShmPurge(pDbFd);
++ /* if we already have a lock, it is exclusive.
++ ** Just adjust level and punt on outta here. */
++ if (pFile->eFileLock > NO_LOCK) {
++ pFile->eFileLock = eFileLock;
++ return SQLITE_OK;
+ }
+- unixLeaveMutex();
+-
+- return SQLITE_OK;
++
++ /* grab an exclusive lock */
++
++ if (robust_flock(pFile->h, LOCK_EX | LOCK_NB)) {
++ int tErrno = errno;
++ /* didn't get, must be busy */
++ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
++ if( IS_LOCK_ERROR(rc) ){
++ pFile->lastErrno = tErrno;
++ }
++ } else {
++ /* got it, set the type and return ok */
++ pFile->eFileLock = eFileLock;
++ }
++ OSTRACE(("LOCK %d %s %s (flock)\n", pFile->h, azFileLock(eFileLock),
++ rc==SQLITE_OK ? "ok" : "failed"));
++#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
++ if( (rc & SQLITE_IOERR) == SQLITE_IOERR ){
++ rc = SQLITE_BUSY;
++ }
++#endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */
++ return rc;
+ }
+
+
+-#else
+-# define unixShmMap 0
+-# define unixShmLock 0
+-# define unixShmBarrier 0
+-# define unixShmUnmap 0
+-#endif /* #ifndef SQLITE_OMIT_WAL */
+-
+ /*
+-** If it is currently memory mapped, unmap file pFd.
++** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
++** 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.
+ */
+-static void unixUnmapfile(unixFile *pFd){
+- assert( pFd->nFetchOut==0 );
+-#if SQLITE_MAX_MMAP_SIZE>0
+- if( pFd->pMapRegion ){
+- osMunmap(pFd->pMapRegion, pFd->mmapSizeActual);
+- pFd->pMapRegion = 0;
+- pFd->mmapSize = 0;
+- pFd->mmapSizeActual = 0;
++static int flockUnlock(sqlite3_file *id, int eFileLock) {
++ unixFile *pFile = (unixFile*)id;
++
++ assert( pFile );
++ OSTRACE(("UNLOCK %d %d was %d pid=%d (flock)\n", pFile->h, eFileLock,
++ pFile->eFileLock, getpid()));
++ assert( eFileLock<=SHARED_LOCK );
++
++ /* no-op if possible */
++ if( pFile->eFileLock==eFileLock ){
++ return SQLITE_OK;
++ }
++
++ /* shared can just be set because we always have an exclusive */
++ if (eFileLock==SHARED_LOCK) {
++ pFile->eFileLock = eFileLock;
++ return SQLITE_OK;
++ }
++
++ /* no, really, unlock. */
++ if( robust_flock(pFile->h, LOCK_UN) ){
++#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
++ return SQLITE_OK;
++#endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */
++ return SQLITE_IOERR_UNLOCK;
++ }else{
++ pFile->eFileLock = NO_LOCK;
++ return SQLITE_OK;
+ }
+-#endif
+ }
+
+-#if SQLITE_MAX_MMAP_SIZE>0
+ /*
+-** Return the system page size.
++** Close a file.
+ */
+-static int unixGetPagesize(void){
+-#if HAVE_MREMAP
+- return 512;
+-#elif defined(_BSD_SOURCE)
+- return getpagesize();
+-#else
+- return (int)sysconf(_SC_PAGESIZE);
+-#endif
++static int flockClose(sqlite3_file *id) {
++ int rc = SQLITE_OK;
++ if( id ){
++ flockUnlock(id, NO_LOCK);
++ rc = closeUnixFile(id);
++ }
++ return rc;
+ }
+-#endif /* SQLITE_MAX_MMAP_SIZE>0 */
+
+-#if SQLITE_MAX_MMAP_SIZE>0
+-/*
+-** Attempt to set the size of the memory mapping maintained by file
+-** descriptor pFd to nNew bytes. Any existing mapping is discarded.
+-**
+-** If successful, this function sets the following variables:
++#endif /* SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORK */
++
++/******************* End of the flock lock implementation *********************
++******************************************************************************/
++
++/******************************************************************************
++************************ Begin Named Semaphore Locking ************************
+ **
+-** unixFile.pMapRegion
+-** unixFile.mmapSize
+-** unixFile.mmapSizeActual
++** Named semaphore locking is only supported on VxWorks.
+ **
+-** If unsuccessful, an error message is logged via sqlite3_log() and
+-** the three variables above are zeroed. In this case SQLite should
+-** continue accessing the database using the xRead() and xWrite()
+-** methods.
++** Semaphore locking is like dot-lock and flock in that it really only
++** supports EXCLUSIVE locking. Only a single process can read or write
++** the database file at a time. This reduces potential concurrency, but
++** makes the lock implementation much easier.
+ */
+-static void unixRemapfile(
+- unixFile *pFd, /* File descriptor object */
+- i64 nNew /* Required mapping size */
+-){
+- const char *zErr = "mmap";
+- int h = pFd->h; /* File descriptor open on db file */
+- u8 *pOrig = (u8 *)pFd->pMapRegion; /* Pointer to current file mapping */
+- i64 nOrig = pFd->mmapSizeActual; /* Size of pOrig region in bytes */
+- u8 *pNew = 0; /* Location of new mapping */
+- int flags = PROT_READ; /* Flags to pass to mmap() */
+-
+- assert( pFd->nFetchOut==0 );
+- assert( nNew>pFd->mmapSize );
+- assert( nNew<=pFd->mmapSizeMax );
+- assert( nNew>0 );
+- assert( pFd->mmapSizeActual>=pFd->mmapSize );
+- assert( MAP_FAILED!=0 );
++#if OS_VXWORKS
+
+- if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE;
++/*
++** 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, set *pResOut
++** 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) {
++ int rc = SQLITE_OK;
++ int reserved = 0;
++ unixFile *pFile = (unixFile*)id;
+
+- if( pOrig ){
+- const int szSyspage = unixGetPagesize();
+- i64 nReuse = (pFd->mmapSize & ~(szSyspage-1));
+- u8 *pReq = &pOrig[nReuse];
++ SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
++
++ assert( pFile );
+
+- /* Unmap any pages of the existing mapping that cannot be reused. */
+- if( nReuse!=nOrig ){
+- osMunmap(pReq, nOrig-nReuse);
+- }
++ /* Check if a thread in this process holds such a lock */
++ if( pFile->eFileLock>SHARED_LOCK ){
++ reserved = 1;
++ }
++
++ /* Otherwise see if some other process holds it. */
++ if( !reserved ){
++ sem_t *pSem = pFile->pInode->pSem;
++ struct stat statBuf;
+
+-#if HAVE_MREMAP
+- pNew = osMremap(pOrig, nReuse, nNew, MREMAP_MAYMOVE);
+- zErr = "mremap";
+-#else
+- pNew = osMmap(pReq, nNew-nReuse, flags, MAP_SHARED, h, nReuse);
+- if( pNew!=MAP_FAILED ){
+- if( pNew!=pReq ){
+- osMunmap(pNew, nNew - nReuse);
+- pNew = 0;
+- }else{
+- pNew = pOrig;
++ if( sem_trywait(pSem)==-1 ){
++ int tErrno = errno;
++ if( EAGAIN != tErrno ){
++ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_CHECKRESERVEDLOCK);
++ pFile->lastErrno = tErrno;
++ } else {
++ /* someone else has the lock when we are in NO_LOCK */
++ reserved = (pFile->eFileLock < SHARED_LOCK);
+ }
++ }else{
++ /* we could have it if we want it */
++ sem_post(pSem);
+ }
+-#endif
+-
+- /* The attempt to extend the existing mapping failed. Free it. */
+- if( pNew==MAP_FAILED || pNew==0 ){
+- osMunmap(pOrig, nReuse);
+- }
+- }
+-
+- /* If pNew is still NULL, try to create an entirely new mapping. */
+- if( pNew==0 ){
+- pNew = osMmap(0, nNew, flags, MAP_SHARED, h, 0);
+ }
++ OSTRACE(("TEST WR-LOCK %d %d %d (sem)\n", pFile->h, rc, reserved));
+
+- if( pNew==MAP_FAILED ){
+- pNew = 0;
+- nNew = 0;
+- unixLogError(SQLITE_OK, zErr, pFd->zPath);
+-
+- /* If the mmap() above failed, assume that all subsequent mmap() calls
+- ** will probably fail too. Fall back to using xRead/xWrite exclusively
+- ** in this case. */
+- pFd->mmapSizeMax = 0;
+- }
+- pFd->pMapRegion = (void *)pNew;
+- pFd->mmapSize = pFd->mmapSizeActual = nNew;
++ *pResOut = reserved;
++ return rc;
+ }
+-#endif
+
+ /*
+-** 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.
++** Lock the file with the lock specified by parameter eFileLock - one
++** of the following:
+ **
+-** 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_LIMIT, whichever is smaller.
++** (1) SHARED_LOCK
++** (2) RESERVED_LOCK
++** (3) PENDING_LOCK
++** (4) EXCLUSIVE_LOCK
+ **
+-** 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.
++** 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
++**
++** Semaphore locks only really support EXCLUSIVE locks. We track intermediate
++** lock states in the sqlite3_file structure, but all locks SHARED or
++** above are really EXCLUSIVE locks and exclude all other processes from
++** access the file.
++**
++** This routine will only increase a lock. Use the sqlite3OsUnlock()
++** routine to lower a locking level.
+ */
+-static int unixMapfile(unixFile *pFd, i64 nByte){
+-#if SQLITE_MAX_MMAP_SIZE>0
+- i64 nMap = nByte;
+- int rc;
+-
+- assert( nMap>=0 || pFd->nFetchOut==0 );
+- if( pFd->nFetchOut>0 ) return SQLITE_OK;
++static int semLock(sqlite3_file *id, int eFileLock) {
++ unixFile *pFile = (unixFile*)id;
++ int fd;
++ sem_t *pSem = pFile->pInode->pSem;
++ int rc = SQLITE_OK;
+
+- if( nMap<0 ){
+- struct stat statbuf; /* Low-level file information */
+- rc = osFstat(pFd->h, &statbuf);
+- if( rc!=SQLITE_OK ){
+- return SQLITE_IOERR_FSTAT;
+- }
+- nMap = statbuf.st_size;
++ /* if we already have a lock, it is exclusive.
++ ** Just adjust level and punt on outta here. */
++ if (pFile->eFileLock > NO_LOCK) {
++ pFile->eFileLock = eFileLock;
++ rc = SQLITE_OK;
++ goto sem_end_lock;
+ }
+- if( nMap>pFd->mmapSizeMax ){
+- nMap = pFd->mmapSizeMax;
++
++ /* lock semaphore now but bail out when already locked. */
++ if( sem_trywait(pSem)==-1 ){
++ rc = SQLITE_BUSY;
++ goto sem_end_lock;
+ }
+
+- if( nMap!=pFd->mmapSize ){
+- if( nMap>0 ){
+- unixRemapfile(pFd, nMap);
+- }else{
+- unixUnmapfile(pFd);
+- }
+- }
+-#endif
++ /* got it, set the type and return ok */
++ pFile->eFileLock = eFileLock;
+
+- return SQLITE_OK;
++ sem_end_lock:
++ return rc;
+ }
+
+ /*
+-** 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.
++** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
++** must be either NO_LOCK or SHARED_LOCK.
+ **
+-** If this function does return a pointer, the caller must eventually
+-** release the reference by calling unixUnfetch().
++** 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 unixFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
+-#if SQLITE_MAX_MMAP_SIZE>0
+- unixFile *pFd = (unixFile *)fd; /* The underlying database file */
+-#endif
+- *pp = 0;
++static int semUnlock(sqlite3_file *id, int eFileLock) {
++ unixFile *pFile = (unixFile*)id;
++ sem_t *pSem = pFile->pInode->pSem;
+
+-#if SQLITE_MAX_MMAP_SIZE>0
+- if( pFd->mmapSizeMax>0 ){
+- if( pFd->pMapRegion==0 ){
+- int rc = unixMapfile(pFd, -1);
+- if( rc!=SQLITE_OK ) return rc;
+- }
+- if( pFd->mmapSize >= iOff+nAmt ){
+- *pp = &((u8 *)pFd->pMapRegion)[iOff];
+- pFd->nFetchOut++;
++ assert( pFile );
++ assert( pSem );
++ OSTRACE(("UNLOCK %d %d was %d pid=%d (sem)\n", pFile->h, eFileLock,
++ pFile->eFileLock, getpid()));
++ assert( eFileLock<=SHARED_LOCK );
++
++ /* no-op if possible */
++ if( pFile->eFileLock==eFileLock ){
++ return SQLITE_OK;
++ }
++
++ /* shared can just be set because we always have an exclusive */
++ if (eFileLock==SHARED_LOCK) {
++ pFile->eFileLock = eFileLock;
++ return SQLITE_OK;
++ }
++
++ /* no, really unlock. */
++ if ( sem_post(pSem)==-1 ) {
++ int rc, tErrno = errno;
++ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
++ if( IS_LOCK_ERROR(rc) ){
++ pFile->lastErrno = tErrno;
+ }
++ return rc;
+ }
+-#endif
++ pFile->eFileLock = NO_LOCK;
+ return SQLITE_OK;
+ }
+
+ /*
+-** If the third argument is non-NULL, then this function releases a
+-** reference obtained by an earlier call to unixFetch(). The second
+-** argument passed to this function must be the same as the corresponding
+-** argument that was passed to the unixFetch() 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 unixUnfetch(sqlite3_file *fd, i64 iOff, void *p){
+- unixFile *pFd = (unixFile *)fd; /* The underlying database file */
+- UNUSED_PARAMETER(iOff);
+-
+- /* 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] );
+-
+- if( p ){
+- pFd->nFetchOut--;
+- }else{
+- unixUnmapfile(pFd);
++ ** Close a file.
++ */
++static int semClose(sqlite3_file *id) {
++ if( id ){
++ unixFile *pFile = (unixFile*)id;
++ semUnlock(id, NO_LOCK);
++ assert( pFile );
++ unixEnterMutex();
++ releaseInodeInfo(pFile);
++ unixLeaveMutex();
++ closeUnixFile(id);
+ }
+-
+- assert( pFd->nFetchOut>=0 );
+ return SQLITE_OK;
+ }
+
++#endif /* OS_VXWORKS */
+ /*
+-** Here ends the implementation of all sqlite3_file methods.
++** Named semaphore locking is only available on VxWorks.
+ **
+-********************** End sqlite3_file Methods *******************************
++*************** End of the named semaphore lock implementation ****************
+ ******************************************************************************/
+
+-/*
+-** This division contains definitions of sqlite3_io_methods objects that
+-** implement various file locking strategies. It also contains definitions
+-** of "finder" functions. A finder-function is used to locate the appropriate
+-** sqlite3_io_methods object for a particular database file. The pAppData
+-** field of the sqlite3_vfs VFS objects are initialized to be pointers to
+-** the correct finder-function for that VFS.
+-**
+-** Most finder functions return a pointer to a fixed sqlite3_io_methods
+-** object. The only interesting finder-function is autolockIoFinder, which
+-** looks at the filesystem type and tries to guess the best locking
+-** strategy from that.
+-**
+-** For finder-funtion F, two objects are created:
+-**
+-** (1) The real finder-function named "FImpt()".
+-**
+-** (2) A constant pointer to this function named just "F".
+-**
+-**
+-** A pointer to the F pointer is used as the pAppData value for VFS
+-** objects. We have to do this instead of letting pAppData point
+-** directly at the finder-function since C90 rules prevent a void*
+-** from be cast into a function pointer.
+-**
+-**
+-** Each instance of this macro generates two objects:
++
++/******************************************************************************
++*************************** Begin AFP Locking *********************************
+ **
+-** * A constant sqlite3_io_methods object call METHOD that has locking
+-** methods CLOSE, LOCK, UNLOCK, CKRESLOCK.
++** AFP is the Apple Filing Protocol. AFP is a network filesystem found
++** on Apple Macintosh computers - both OS9 and OSX.
+ **
+-** * An I/O method finder function called FINDER that returns a pointer
+-** to the METHOD object in the previous bullet.
++** Third-party implementations of AFP are available. But this code here
++** only works on OSX.
+ */
+-#define IOMETHODS(FINDER, METHOD, VERSION, CLOSE, LOCK, UNLOCK, CKLOCK) \
+-static const sqlite3_io_methods METHOD = { \
+- VERSION, /* iVersion */ \
+- CLOSE, /* xClose */ \
+- unixRead, /* xRead */ \
+- unixWrite, /* xWrite */ \
+- unixTruncate, /* xTruncate */ \
+- unixSync, /* xSync */ \
+- unixFileSize, /* xFileSize */ \
+- LOCK, /* xLock */ \
+- UNLOCK, /* xUnlock */ \
+- CKLOCK, /* xCheckReservedLock */ \
+- unixFileControl, /* xFileControl */ \
+- unixSectorSize, /* xSectorSize */ \
+- unixDeviceCharacteristics, /* xDeviceCapabilities */ \
+- unixShmMap, /* xShmMap */ \
+- unixShmLock, /* xShmLock */ \
+- unixShmBarrier, /* xShmBarrier */ \
+- unixShmUnmap, /* xShmUnmap */ \
+- unixFetch, /* xFetch */ \
+- unixUnfetch, /* xUnfetch */ \
+-}; \
+-static const sqlite3_io_methods *FINDER##Impl(const char *z, unixFile *p){ \
+- UNUSED_PARAMETER(z); UNUSED_PARAMETER(p); \
+- return &METHOD; \
+-} \
+-static const sqlite3_io_methods *(*const FINDER)(const char*,unixFile *p) \
+- = FINDER##Impl;
+
++#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
+ /*
+-** Here are all of the sqlite3_io_methods objects for each of the
+-** locking strategies. Functions that return pointers to these methods
+-** are also created.
++** The afpLockingContext structure contains all afp lock specific state
+ */
+-IOMETHODS(
+- posixIoFinder, /* Finder function name */
+- posixIoMethods, /* sqlite3_io_methods object name */
+- 3, /* shared memory and mmap are enabled */
+- unixClose, /* xClose method */
+- unixLock, /* xLock method */
+- unixUnlock, /* xUnlock method */
+- unixCheckReservedLock /* xCheckReservedLock method */
+-)
+-IOMETHODS(
+- nolockIoFinder, /* Finder function name */
+- nolockIoMethods, /* sqlite3_io_methods object name */
+- 1, /* shared memory is disabled */
+- nolockClose, /* xClose method */
+- nolockLock, /* xLock method */
+- nolockUnlock, /* xUnlock method */
+- nolockCheckReservedLock /* xCheckReservedLock method */
+-)
+-IOMETHODS(
+- dotlockIoFinder, /* Finder function name */
+- dotlockIoMethods, /* sqlite3_io_methods object name */
+- 1, /* shared memory is disabled */
+- dotlockClose, /* xClose method */
+- dotlockLock, /* xLock method */
+- dotlockUnlock, /* xUnlock method */
+- dotlockCheckReservedLock /* xCheckReservedLock method */
+-)
++typedef struct afpLockingContext afpLockingContext;
++struct afpLockingContext {
++ int reserved;
++ const char *dbPath; /* Name of the open file */
++};
+
+-#if SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS
+-IOMETHODS(
+- flockIoFinder, /* Finder function name */
+- flockIoMethods, /* sqlite3_io_methods object name */
+- 1, /* shared memory is disabled */
+- flockClose, /* xClose method */
+- flockLock, /* xLock method */
+- flockUnlock, /* xUnlock method */
+- flockCheckReservedLock /* xCheckReservedLock method */
+-)
+-#endif
++struct ByteRangeLockPB2
++{
++ unsigned long long offset; /* offset to first byte to lock */
++ unsigned long long length; /* nbr of bytes to lock */
++ unsigned long long retRangeStart; /* nbr of 1st byte locked if successful */
++ unsigned char unLockFlag; /* 1 = unlock, 0 = lock */
++ unsigned char startEndFlag; /* 1=rel to end of fork, 0=rel to start */
++ int fd; /* file desc to assoc this lock with */
++};
+
+-#if OS_VXWORKS
+-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 */
+-)
+-#endif
++#define afpfsByteRangeLock2FSCTL _IOWR('z', 23, struct ByteRangeLockPB2)
+
+-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
+-IOMETHODS(
+- afpIoFinder, /* Finder function name */
+- afpIoMethods, /* sqlite3_io_methods object name */
+- 1, /* shared memory is disabled */
+- afpClose, /* xClose method */
+- afpLock, /* xLock method */
+- afpUnlock, /* xUnlock method */
+- afpCheckReservedLock /* xCheckReservedLock method */
+-)
+-#endif
++/*
++** This is a utility for setting or clearing a bit-range lock on an
++** AFP filesystem.
++**
++** Return SQLITE_OK on success, SQLITE_BUSY on failure.
++*/
++static int afpSetLock(
++ const char *path, /* Name of the file to be locked or unlocked */
++ unixFile *pFile, /* Open file descriptor on path */
++ unsigned long long offset, /* First byte to be locked */
++ unsigned long long length, /* Number of bytes to lock */
++ int setLockFlag /* True to set lock. False to clear lock */
++){
++ struct ByteRangeLockPB2 pb;
++ int err;
++
++ pb.unLockFlag = setLockFlag ? 0 : 1;
++ pb.startEndFlag = 0;
++ pb.offset = offset;
++ pb.length = length;
++ pb.fd = pFile->h;
++
++ OSTRACE(("AFPSETLOCK [%s] for %d%s in range %llx:%llx\n",
++ (setLockFlag?"ON":"OFF"), pFile->h, (pb.fd==-1?"[testval-1]":""),
++ offset, length));
++ err = fsctl(path, afpfsByteRangeLock2FSCTL, &pb, 0);
++ if ( err==-1 ) {
++ int rc;
++ int tErrno = errno;
++ OSTRACE(("AFPSETLOCK failed to fsctl() '%s' %d %s\n",
++ path, tErrno, strerror(tErrno)));
++#ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS
++ rc = SQLITE_BUSY;
++#else
++ rc = sqliteErrorFromPosixError(tErrno,
++ setLockFlag ? SQLITE_IOERR_LOCK : SQLITE_IOERR_UNLOCK);
++#endif /* SQLITE_IGNORE_AFP_LOCK_ERRORS */
++ if( IS_LOCK_ERROR(rc) ){
++ pFile->lastErrno = tErrno;
++ }
++ return rc;
++ } else {
++ return SQLITE_OK;
++ }
++}
+
+ /*
+-** The proxy locking method is a "super-method" in the sense that it
+-** opens secondary file descriptors for the conch and lock files and
+-** it uses proxy, dot-file, AFP, and flock() locking methods on those
+-** secondary files. For this reason, the division that implements
+-** proxy locking is located much further down in the file. But we need
+-** to go ahead and define the sqlite3_io_methods and finder function
+-** for proxy locking here. So we forward declare the I/O methods.
++** 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, set *pResOut
++** 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.
+ */
+-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
+-static int proxyClose(sqlite3_file*);
+-static int proxyLock(sqlite3_file*, int);
+-static int proxyUnlock(sqlite3_file*, int);
+-static int proxyCheckReservedLock(sqlite3_file*, int*);
+-IOMETHODS(
+- proxyIoFinder, /* Finder function name */
+- proxyIoMethods, /* sqlite3_io_methods object name */
+- 1, /* shared memory is disabled */
+- proxyClose, /* xClose method */
+- proxyLock, /* xLock method */
+- proxyUnlock, /* xUnlock method */
+- proxyCheckReservedLock /* xCheckReservedLock method */
+-)
+-#endif
++static int afpCheckReservedLock(sqlite3_file *id, int *pResOut){
++ int rc = SQLITE_OK;
++ int reserved = 0;
++ unixFile *pFile = (unixFile*)id;
++ afpLockingContext *context;
++
++ SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
++
++ assert( pFile );
++ context = (afpLockingContext *) pFile->lockingContext;
++ if( context->reserved ){
++ *pResOut = 1;
++ return SQLITE_OK;
++ }
++ unixEnterMutex(); /* Because pFile->pInode is shared across threads */
++
++ /* Check if a thread in this process holds such a lock */
++ if( pFile->pInode->eFileLock>SHARED_LOCK ){
++ reserved = 1;
++ }
++
++ /* Otherwise see if some other process holds it.
++ */
++ if( !reserved ){
++ /* lock the RESERVED byte */
++ int lrc = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1,1);
++ if( SQLITE_OK==lrc ){
++ /* if we succeeded in taking the reserved lock, unlock it to restore
++ ** the original state */
++ lrc = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1, 0);
++ } else {
++ /* if we failed to get the lock then someone else must have it */
++ reserved = 1;
++ }
++ if( IS_LOCK_ERROR(lrc) ){
++ rc=lrc;
++ }
++ }
++
++ unixLeaveMutex();
++ OSTRACE(("TEST WR-LOCK %d %d %d (afp)\n", pFile->h, rc, reserved));
++
++ *pResOut = reserved;
++ return rc;
++}
+
+-/* nfs lockd on OSX 10.3+ doesn't clear write locks when a read lock is set */
+-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
+-IOMETHODS(
+- nfsIoFinder, /* Finder function name */
+- nfsIoMethods, /* sqlite3_io_methods object name */
+- 1, /* shared memory is disabled */
+- unixClose, /* xClose method */
+- unixLock, /* xLock method */
+- nfsUnlock, /* xUnlock method */
+- unixCheckReservedLock /* xCheckReservedLock method */
+-)
+-#endif
++/*
++** Lock the file with the lock specified by parameter eFileLock - 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. Use the sqlite3OsUnlock()
++** routine to lower a locking level.
++*/
++static int afpLock(sqlite3_file *id, int eFileLock){
++ int rc = SQLITE_OK;
++ unixFile *pFile = (unixFile*)id;
++ unixInodeInfo *pInode = pFile->pInode;
++ afpLockingContext *context = (afpLockingContext *) pFile->lockingContext;
++
++ 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()));
++
++ /* 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
++ ** unixEnterMutex() hasn't been called yet.
++ */
++ if( pFile->eFileLock>=eFileLock ){
++ OSTRACE(("LOCK %d %s ok (already held) (afp)\n", pFile->h,
++ azFileLock(eFileLock)));
++ return SQLITE_OK;
++ }
++
++ /* Make sure the locking sequence is correct
++ ** (1) We never move from unlocked to anything higher than shared lock.
++ ** (2) SQLite never explicitly requests a pendig lock.
++ ** (3) A shared lock is always held when a reserve lock is requested.
++ */
++ assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK );
++ assert( eFileLock!=PENDING_LOCK );
++ assert( eFileLock!=RESERVED_LOCK || pFile->eFileLock==SHARED_LOCK );
++
++ /* This mutex is needed because pFile->pInode is shared across threads
++ */
++ unixEnterMutex();
++ pInode = pFile->pInode;
++
++ /* If some thread using this PID has a lock via a different unixFile*
++ ** handle that precludes the requested lock, return BUSY.
++ */
++ if( (pFile->eFileLock!=pInode->eFileLock &&
++ (pInode->eFileLock>=PENDING_LOCK || eFileLock>SHARED_LOCK))
++ ){
++ rc = SQLITE_BUSY;
++ goto afp_end_lock;
++ }
++
++ /* If a SHARED lock is requested, and some thread using this PID already
++ ** has a SHARED or RESERVED lock, then increment reference counts and
++ ** return SQLITE_OK.
++ */
++ if( eFileLock==SHARED_LOCK &&
++ (pInode->eFileLock==SHARED_LOCK || pInode->eFileLock==RESERVED_LOCK) ){
++ assert( eFileLock==SHARED_LOCK );
++ assert( pFile->eFileLock==0 );
++ assert( pInode->nShared>0 );
++ pFile->eFileLock = SHARED_LOCK;
++ pInode->nShared++;
++ pInode->nLock++;
++ goto afp_end_lock;
++ }
++
++ /* A PENDING lock is needed before acquiring a SHARED lock and before
++ ** acquiring an EXCLUSIVE lock. For the SHARED lock, the PENDING will
++ ** be released.
++ */
++ if( eFileLock==SHARED_LOCK
++ || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock<PENDING_LOCK)
++ ){
++ int failed;
++ failed = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 1);
++ if (failed) {
++ rc = failed;
++ goto afp_end_lock;
++ }
++ }
++
++ /* If control gets to this point, then actually go ahead and make
++ ** operating system calls for the specified lock.
++ */
++ if( eFileLock==SHARED_LOCK ){
++ int lrc1, lrc2, lrc1Errno = 0;
++ long lk, mask;
++
++ assert( pInode->nShared==0 );
++ assert( pInode->eFileLock==0 );
++
++ mask = (sizeof(long)==8) ? LARGEST_INT64 : 0x7fffffff;
++ /* Now get the read-lock SHARED_LOCK */
++ /* note that the quality of the randomness doesn't matter that much */
++ lk = random();
++ pInode->sharedByte = (lk & mask)%(SHARED_SIZE - 1);
++ lrc1 = afpSetLock(context->dbPath, pFile,
++ SHARED_FIRST+pInode->sharedByte, 1, 1);
++ if( IS_LOCK_ERROR(lrc1) ){
++ lrc1Errno = pFile->lastErrno;
++ }
++ /* Drop the temporary PENDING lock */
++ lrc2 = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 0);
++
++ if( IS_LOCK_ERROR(lrc1) ) {
++ pFile->lastErrno = lrc1Errno;
++ rc = lrc1;
++ goto afp_end_lock;
++ } else if( IS_LOCK_ERROR(lrc2) ){
++ rc = lrc2;
++ goto afp_end_lock;
++ } else if( lrc1 != SQLITE_OK ) {
++ rc = lrc1;
++ } else {
++ pFile->eFileLock = SHARED_LOCK;
++ pInode->nLock++;
++ pInode->nShared = 1;
++ }
++ }else if( eFileLock==EXCLUSIVE_LOCK && pInode->nShared>1 ){
++ /* We are trying for an exclusive lock but another thread in this
++ ** same process is still holding a shared lock. */
++ rc = SQLITE_BUSY;
++ }else{
++ /* The request was for a RESERVED or EXCLUSIVE lock. It is
++ ** assumed that there is a SHARED or greater lock on the file
++ ** already.
++ */
++ int failed = 0;
++ assert( 0!=pFile->eFileLock );
++ if (eFileLock >= RESERVED_LOCK && pFile->eFileLock < RESERVED_LOCK) {
++ /* Acquire a RESERVED lock */
++ failed = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1,1);
++ if( !failed ){
++ context->reserved = 1;
++ }
++ }
++ if (!failed && eFileLock == EXCLUSIVE_LOCK) {
++ /* Acquire an EXCLUSIVE lock */
++
++ /* Remove the shared lock before trying the range. we'll need to
++ ** reestablish the shared lock if we can't get the afpUnlock
++ */
++ if( !(failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST +
++ pInode->sharedByte, 1, 0)) ){
++ int failed2 = SQLITE_OK;
++ /* now attemmpt to get the exclusive lock range */
++ failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST,
++ SHARED_SIZE, 1);
++ if( failed && (failed2 = afpSetLock(context->dbPath, pFile,
++ SHARED_FIRST + pInode->sharedByte, 1, 1)) ){
++ /* Can't reestablish the shared lock. Sqlite can't deal, this is
++ ** a critical I/O error
++ */
++ rc = ((failed & SQLITE_IOERR) == SQLITE_IOERR) ? failed2 :
++ SQLITE_IOERR_LOCK;
++ goto afp_end_lock;
++ }
++ }else{
++ rc = failed;
++ }
++ }
++ if( failed ){
++ rc = failed;
++ }
++ }
++
++ if( rc==SQLITE_OK ){
++ pFile->eFileLock = eFileLock;
++ pInode->eFileLock = eFileLock;
++ }else if( eFileLock==EXCLUSIVE_LOCK ){
++ pFile->eFileLock = PENDING_LOCK;
++ pInode->eFileLock = PENDING_LOCK;
++ }
++
++afp_end_lock:
++ unixLeaveMutex();
++ OSTRACE(("LOCK %d %s %s (afp)\n", pFile->h, azFileLock(eFileLock),
++ rc==SQLITE_OK ? "ok" : "failed"));
++ return rc;
++}
+
+-#if defined(__APPLE__) && 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.
++/*
++** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
++** must be either NO_LOCK or SHARED_LOCK.
+ **
+-** This is for MacOSX only.
++** If the locking level of the file descriptor is already at or below
++** the requested locking level, this routine is a no-op.
+ */
+-static const sqlite3_io_methods *autolockIoFinderImpl(
+- const char *filePath, /* name of the database file */
+- unixFile *pNew /* open file object for the database file */
+-){
+- static const struct Mapping {
+- const char *zFilesystem; /* Filesystem type name */
+- const sqlite3_io_methods *pMethods; /* Appropriate locking method */
+- } aMap[] = {
+- { "hfs", &posixIoMethods },
+- { "ufs", &posixIoMethods },
+- { "afpfs", &afpIoMethods },
+- { "smbfs", &afpIoMethods },
+- { "webdav", &nolockIoMethods },
+- { 0, 0 }
+- };
+- int i;
+- struct statfs fsInfo;
+- struct flock lockInfo;
++static int afpUnlock(sqlite3_file *id, int eFileLock) {
++ int rc = SQLITE_OK;
++ unixFile *pFile = (unixFile*)id;
++ unixInodeInfo *pInode;
++ afpLockingContext *context = (afpLockingContext *) pFile->lockingContext;
++ int skipShared = 0;
++#ifdef SQLITE_TEST
++ int h = pFile->h;
++#endif
+
+- if( !filePath ){
+- /* If filePath==NULL that means we are dealing with a transient file
+- ** that does not need to be locked. */
+- return &nolockIoMethods;
++ 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()));
++
++ assert( eFileLock<=SHARED_LOCK );
++ if( pFile->eFileLock<=eFileLock ){
++ return SQLITE_OK;
+ }
+- if( statfs(filePath, &fsInfo) != -1 ){
+- if( fsInfo.f_flags & MNT_RDONLY ){
+- return &nolockIoMethods;
++ unixEnterMutex();
++ pInode = pFile->pInode;
++ assert( pInode->nShared!=0 );
++ if( pFile->eFileLock>SHARED_LOCK ){
++ assert( pInode->eFileLock==pFile->eFileLock );
++ SimulateIOErrorBenign(1);
++ SimulateIOError( h=(-1) )
++ SimulateIOErrorBenign(0);
++
++#ifdef SQLITE_DEBUG
++ /* When reducing a lock such that other processes can start
++ ** reading the database file again, make sure that the
++ ** transaction counter was updated if any part of the database
++ ** file changed. If the transaction counter is not updated,
++ ** other connections to the same file might not realize that
++ ** the file has changed and hence might not know to flush their
++ ** cache. The use of a stale cache can lead to database corruption.
++ */
++ assert( pFile->inNormalWrite==0
++ || pFile->dbUpdate==0
++ || pFile->transCntrChng==1 );
++ pFile->inNormalWrite = 0;
++#endif
++
++ if( pFile->eFileLock==EXCLUSIVE_LOCK ){
++ rc = afpSetLock(context->dbPath, pFile, SHARED_FIRST, SHARED_SIZE, 0);
++ if( rc==SQLITE_OK && (eFileLock==SHARED_LOCK || pInode->nShared>1) ){
++ /* only re-establish the shared lock if necessary */
++ int sharedLockByte = SHARED_FIRST+pInode->sharedByte;
++ rc = afpSetLock(context->dbPath, pFile, sharedLockByte, 1, 1);
++ } else {
++ skipShared = 1;
++ }
+ }
+- for(i=0; aMap[i].zFilesystem; i++){
+- if( strcmp(fsInfo.f_fstypename, aMap[i].zFilesystem)==0 ){
+- return aMap[i].pMethods;
++ if( rc==SQLITE_OK && pFile->eFileLock>=PENDING_LOCK ){
++ rc = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 0);
++ }
++ if( rc==SQLITE_OK && pFile->eFileLock>=RESERVED_LOCK && context->reserved ){
++ rc = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1, 0);
++ if( !rc ){
++ context->reserved = 0;
+ }
+ }
++ if( rc==SQLITE_OK && (eFileLock==SHARED_LOCK || pInode->nShared>1)){
++ pInode->eFileLock = SHARED_LOCK;
++ }
+ }
++ if( rc==SQLITE_OK && eFileLock==NO_LOCK ){
+
+- /* Default case. Handles, amongst others, "nfs".
+- ** Test byte-range lock using fcntl(). If the call succeeds,
+- ** assume that the file-system supports POSIX style locks.
+- */
+- lockInfo.l_len = 1;
+- lockInfo.l_start = 0;
+- lockInfo.l_whence = SEEK_SET;
+- lockInfo.l_type = F_RDLCK;
+- if( osFcntl(pNew->h, F_GETLK, &lockInfo)!=-1 ) {
+- if( strcmp(fsInfo.f_fstypename, "nfs")==0 ){
+- return &nfsIoMethods;
+- } else {
+- return &posixIoMethods;
++ /* Decrement the shared lock counter. Release the lock using an
++ ** OS call only when all threads in this same process have released
++ ** the lock.
++ */
++ unsigned long long sharedLockByte = SHARED_FIRST+pInode->sharedByte;
++ pInode->nShared--;
++ if( pInode->nShared==0 ){
++ SimulateIOErrorBenign(1);
++ SimulateIOError( h=(-1) )
++ SimulateIOErrorBenign(0);
++ if( !skipShared ){
++ rc = afpSetLock(context->dbPath, pFile, sharedLockByte, 1, 0);
++ }
++ if( !rc ){
++ pInode->eFileLock = NO_LOCK;
++ pFile->eFileLock = NO_LOCK;
++ }
++ }
++ if( rc==SQLITE_OK ){
++ pInode->nLock--;
++ assert( pInode->nLock>=0 );
++ if( pInode->nLock==0 ){
++ closePendingFds(pFile);
++ }
+ }
+- }else{
+- return &dotlockIoMethods;
+ }
++
++ unixLeaveMutex();
++ if( rc==SQLITE_OK ) pFile->eFileLock = eFileLock;
++ return rc;
+ }
+-static const sqlite3_io_methods
+- *(*const autolockIoFinder)(const char*,unixFile*) = autolockIoFinderImpl;
+-
+-#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.
++/*
++** Close a file & cleanup AFP specific locking context
+ */
+-static const sqlite3_io_methods *autolockIoFinderImpl(
+- const char *filePath, /* name of the database file */
+- unixFile *pNew /* the open file object */
+-){
+- struct flock lockInfo;
+-
+- if( !filePath ){
+- /* If filePath==NULL that means we are dealing with a transient file
+- ** that does not need to be locked. */
+- return &nolockIoMethods;
+- }
+-
+- /* Test if fcntl() is supported and use POSIX style locks.
+- ** Otherwise fall back to the named semaphore method.
+- */
+- lockInfo.l_len = 1;
+- lockInfo.l_start = 0;
+- lockInfo.l_whence = SEEK_SET;
+- lockInfo.l_type = F_RDLCK;
+- if( osFcntl(pNew->h, F_GETLK, &lockInfo)!=-1 ) {
+- return &posixIoMethods;
+- }else{
+- return &semIoMethods;
++static int afpClose(sqlite3_file *id) {
++ int rc = SQLITE_OK;
++ if( id ){
++ unixFile *pFile = (unixFile*)id;
++ afpUnlock(id, NO_LOCK);
++ unixEnterMutex();
++ if( pFile->pInode && pFile->pInode->nLock ){
++ /* If there are outstanding locks, do not actually close the file just
++ ** yet because that would clear those locks. Instead, add the file
++ ** descriptor to pInode->aPending. It will be automatically closed when
++ ** the last lock is cleared.
++ */
++ setPendingFd(pFile);
++ }
++ releaseInodeInfo(pFile);
++ sqlite3_free(pFile->lockingContext);
++ rc = closeUnixFile(id);
++ unixLeaveMutex();
+ }
++ return rc;
+ }
+-static const sqlite3_io_methods
+- *(*const autolockIoFinder)(const char*,unixFile*) = autolockIoFinderImpl;
+
+-#endif /* OS_VXWORKS && SQLITE_ENABLE_LOCKING_STYLE */
++#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
++/*
++** The code above is the AFP lock implementation. The code is specific
++** to MacOSX and does not work on other unix platforms. No alternative
++** is available. If you don't compile for a mac, then the "unix-afp"
++** VFS is not available.
++**
++********************* End of the AFP lock implementation **********************
++******************************************************************************/
++
++/******************************************************************************
++*************************** Begin NFS Locking ********************************/
+
++#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
+ /*
+-** An abstract type for a pointer to a IO method finder function:
+-*/
+-typedef const sqlite3_io_methods *(*finder_type)(const char*,unixFile*);
++ ** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
++ ** 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.
++ */
++static int nfsUnlock(sqlite3_file *id, int eFileLock){
++ return posixUnlock(id, eFileLock, 1);
++}
+
++#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
++/*
++** The code above is the NFS lock implementation. The code is specific
++** to MacOSX and does not work on other unix platforms. No alternative
++** is available.
++**
++********************* End of the NFS lock implementation **********************
++******************************************************************************/
+
+-/****************************************************************************
+-**************************** sqlite3_vfs methods ****************************
++/******************************************************************************
++**************** Non-locking sqlite3_file methods *****************************
+ **
+-** This division contains the implementation of methods on the
+-** sqlite3_vfs object.
++** The next division contains implementations for all methods of the
++** sqlite3_file object other than the locking methods. The locking
++** methods were defined in divisions above (one locking method per
++** division). Those methods that are common to all locking modes
++** are gather together into this division.
+ */
+
+ /*
+-** Initialize the contents of the unixFile structure pointed to by pId.
++** Seek to the offset passed as the second argument, then read cnt
++** bytes into pBuf. Return the number of bytes actually read.
++**
++** 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.
++** See tickets #2741 and #2681.
++**
++** To avoid stomping the errno value on a failed read the lastErrno value
++** is set before returning.
+ */
+-static int fillInUnixFile(
+- sqlite3_vfs *pVfs, /* Pointer to vfs object */
+- int h, /* Open file descriptor of file being opened */
+- sqlite3_file *pId, /* Write to the unixFile structure here */
+- const char *zFilename, /* Name of the file being opened */
+- int ctrlFlags /* Zero or more UNIXFILE_* values */
+-){
+- const sqlite3_io_methods *pLockingStyle;
+- unixFile *pNew = (unixFile *)pId;
+- int rc = SQLITE_OK;
+-
+- assert( pNew->pInode==NULL );
+-
+- /* Usually the path zFilename should not be a relative pathname. The
+- ** exception is when opening the proxy "conch" file in builds that
+- ** include the special Apple locking styles.
+- */
+-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
+- assert( zFilename==0 || zFilename[0]=='/'
+- || pVfs->pAppData==(void*)&autolockIoFinder );
++static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){
++ int got;
++ int prior = 0;
++#if (!defined(USE_PREAD) && !defined(USE_PREAD64))
++ i64 newOffset;
++#endif
++ TIMER_START;
++ assert( cnt==(cnt&0x1ffff) );
++ cnt &= 0x1ffff;
++ do{
++#if defined(USE_PREAD)
++ got = osPread(id->h, pBuf, cnt, offset);
++ SimulateIOError( got = -1 );
++#elif defined(USE_PREAD64)
++ got = osPread64(id->h, pBuf, cnt, offset);
++ SimulateIOError( got = -1 );
+ #else
+- assert( zFilename==0 || zFilename[0]=='/' );
++ newOffset = lseek(id->h, offset, SEEK_SET);
++ SimulateIOError( newOffset-- );
++ if( newOffset!=offset ){
++ if( newOffset == -1 ){
++ ((unixFile*)id)->lastErrno = errno;
++ }else{
++ ((unixFile*)id)->lastErrno = 0;
++ }
++ return -1;
++ }
++ got = osRead(id->h, pBuf, cnt);
+ #endif
++ if( got==cnt ) break;
++ if( got<0 ){
++ if( errno==EINTR ){ got = 1; continue; }
++ prior = 0;
++ ((unixFile*)id)->lastErrno = errno;
++ break;
++ }else if( got>0 ){
++ cnt -= got;
++ offset += got;
++ prior += got;
++ pBuf = (void*)(got + (char*)pBuf);
++ }
++ }while( got>0 );
++ TIMER_END;
++ OSTRACE(("READ %-3d %5d %7lld %llu\n",
++ id->h, got+prior, offset-prior, TIMER_ELAPSED));
++ return got+prior;
++}
+
+- /* No locking occurs in temporary files */
+- assert( zFilename!=0 || (ctrlFlags & UNIXFILE_NOLOCK)!=0 );
++/*
++** Read data from a file into a buffer. Return SQLITE_OK if all
++** bytes were read successfully and SQLITE_IOERR if anything goes
++** wrong.
++*/
++static int unixRead(
++ sqlite3_file *id,
++ void *pBuf,
++ int amt,
++ sqlite3_int64 offset
++){
++ unixFile *pFile = (unixFile *)id;
++ int got;
++ assert( id );
++ assert( offset>=0 );
++ assert( amt>0 );
+
+- OSTRACE(("OPEN %-3d %s\n", h, zFilename));
+- pNew->h = h;
+- pNew->pVfs = pVfs;
+- pNew->zPath = zFilename;
+- pNew->ctrlFlags = (u8)ctrlFlags;
+- pNew->mmapSizeMax = sqlite3GlobalConfig.szMmap;
+- if( sqlite3_uri_boolean(((ctrlFlags & UNIXFILE_URI) ? zFilename : 0),
+- "psow", SQLITE_POWERSAFE_OVERWRITE) ){
+- pNew->ctrlFlags |= UNIXFILE_PSOW;
+- }
+- if( strcmp(pVfs->zName,"unix-excl")==0 ){
+- pNew->ctrlFlags |= UNIXFILE_EXCL;
+- }
++ /* If this is a database file (not a journal, master-journal or temp
++ ** file), the bytes in the locking range should never be read or written. */
++#if 0
++ assert( pFile->pUnused==0
++ || offset>=PENDING_BYTE+512
++ || offset+amt<=PENDING_BYTE
++ );
++#endif
+
+-#if OS_VXWORKS
+- pNew->pId = vxworksFindFileId(zFilename);
+- if( pNew->pId==0 ){
+- ctrlFlags |= UNIXFILE_NOLOCK;
+- rc = SQLITE_NOMEM;
++#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);
++ return SQLITE_OK;
++ }else{
++ int nCopy = pFile->mmapSize - offset;
++ memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], nCopy);
++ pBuf = &((u8 *)pBuf)[nCopy];
++ amt -= nCopy;
++ offset += nCopy;
++ }
+ }
+ #endif
+
+- if( ctrlFlags & UNIXFILE_NOLOCK ){
+- pLockingStyle = &nolockIoMethods;
++ got = seekAndRead(pFile, offset, pBuf, amt);
++ if( got==amt ){
++ return SQLITE_OK;
++ }else if( got<0 ){
++ /* lastErrno set by seekAndRead */
++ return SQLITE_IOERR_READ;
+ }else{
+- pLockingStyle = (**(finder_type*)pVfs->pAppData)(zFilename, pNew);
+-#if SQLITE_ENABLE_LOCKING_STYLE
+- /* Cache zFilename in the locking context (AFP and dotlock override) for
+- ** proxyLock activation is possible (remote proxy is based on db name)
+- ** zFilename remains valid until file is closed, to support */
+- pNew->lockingContext = (void*)zFilename;
+-#endif
++ pFile->lastErrno = 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;
+ }
++}
+
+- if( pLockingStyle == &posixIoMethods
+-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
+- || pLockingStyle == &nfsIoMethods
+-#endif
+- ){
+- unixEnterMutex();
+- rc = findInodeInfo(pNew, &pNew->pInode);
+- if( rc!=SQLITE_OK ){
+- /* If an error occurred in findInodeInfo(), close the file descriptor
+- ** immediately, before releasing the mutex. findInodeInfo() may fail
+- ** in two scenarios:
+- **
+- ** (a) A call to fstat() failed.
+- ** (b) A malloc failed.
+- **
+- ** Scenario (b) may only occur if the process is holding no other
+- ** file descriptors open on the same file. If there were other file
+- ** descriptors on this file, then no malloc would be required by
+- ** findInodeInfo(). If this is the case, it is quite safe to close
+- ** handle h - as it is guaranteed that no posix locks will be released
+- ** by doing so.
+- **
+- ** If scenario (a) caused the error then things are not so safe. The
+- ** implicit assumption here is that if fstat() fails, things are in
+- ** such bad shape that dropping a lock or two doesn't matter much.
+- */
+- robust_close(pNew, h, __LINE__);
+- h = -1;
++/*
++** Attempt to seek the file-descriptor passed as the first argument to
++** absolute offset iOff, then attempt to write nBuf bytes of data from
++** pBuf to it. If an error occurs, return -1 and set *piErrno. Otherwise,
++** return the actual number of bytes written (which may be less than
++** nBuf).
++*/
++static int seekAndWriteFd(
++ int fd, /* File descriptor to write to */
++ i64 iOff, /* File offset to begin writing at */
++ const void *pBuf, /* Copy data from this buffer to the file */
++ int nBuf, /* Size of buffer pBuf in bytes */
++ int *piErrno /* OUT: Error number if error occurs */
++){
++ int rc = 0; /* Value returned by system call */
++
++ assert( nBuf==(nBuf&0x1ffff) );
++ nBuf &= 0x1ffff;
++ TIMER_START;
++
++#if defined(USE_PREAD)
++ do{ rc = 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);
++#else
++ do{
++ i64 iSeek = lseek(fd, iOff, SEEK_SET);
++ SimulateIOError( iSeek-- );
++
++ if( iSeek!=iOff ){
++ if( piErrno ) *piErrno = (iSeek==-1 ? errno : 0);
++ return -1;
+ }
+- unixLeaveMutex();
+- }
++ rc = osWrite(fd, pBuf, nBuf);
++ }while( rc<0 && errno==EINTR );
++#endif
++
++ TIMER_END;
++ OSTRACE(("WRITE %-3d %5d %7lld %llu\n", fd, rc, iOff, TIMER_ELAPSED));
++
++ if( rc<0 && piErrno ) *piErrno = errno;
++ return rc;
++}
++
++
++/*
++** Seek to the offset in id->offset then read cnt bytes into pBuf.
++** Return the number of bytes actually read. Update the offset.
++**
++** To avoid stomping the errno value on a failed write the lastErrno value
++** is set before returning.
++*/
++static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){
++ return seekAndWriteFd(id->h, offset, pBuf, cnt, &id->lastErrno);
++}
++
++
++/*
++** Write data from a buffer into a file. Return SQLITE_OK on success
++** or some other error code on failure.
++*/
++static int unixWrite(
++ sqlite3_file *id,
++ const void *pBuf,
++ int amt,
++ sqlite3_int64 offset
++){
++ unixFile *pFile = (unixFile*)id;
++ int wrote = 0;
++ assert( id );
++ assert( amt>0 );
++
++ /* If this is a database file (not a journal, master-journal or temp
++ ** file), the bytes in the locking range should never be read or written. */
++#if 0
++ assert( pFile->pUnused==0
++ || offset>=PENDING_BYTE+512
++ || offset+amt<=PENDING_BYTE
++ );
++#endif
+
+-#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
+- else if( pLockingStyle == &afpIoMethods ){
+- /* AFP locking uses the file path so it needs to be included in
+- ** the afpLockingContext.
+- */
+- afpLockingContext *pCtx;
+- pNew->lockingContext = pCtx = sqlite3_malloc( sizeof(*pCtx) );
+- if( pCtx==0 ){
+- rc = SQLITE_NOMEM;
+- }else{
+- /* NB: zFilename exists and remains valid until the file is closed
+- ** according to requirement F11141. So we do not need to make a
+- ** copy of the filename. */
+- pCtx->dbPath = zFilename;
+- pCtx->reserved = 0;
+- srandomdev();
+- unixEnterMutex();
+- rc = findInodeInfo(pNew, &pNew->pInode);
+- if( rc!=SQLITE_OK ){
+- sqlite3_free(pNew->lockingContext);
+- robust_close(pNew, h, __LINE__);
+- h = -1;
++#ifdef SQLITE_DEBUG
++ /* If we are doing a normal write to a database file (as opposed to
++ ** doing a hot-journal rollback or a write to some file other than a
++ ** normal database file) then record the fact that the database
++ ** has changed. If the transaction counter is modified, record that
++ ** fact too.
++ */
++ if( pFile->inNormalWrite ){
++ pFile->dbUpdate = 1; /* The database has been modified */
++ if( offset<=24 && offset+amt>=27 ){
++ int rc;
++ char oldCntr[4];
++ SimulateIOErrorBenign(1);
++ rc = seekAndRead(pFile, 24, oldCntr, 4);
++ SimulateIOErrorBenign(0);
++ if( rc!=4 || memcmp(oldCntr, &((char*)pBuf)[24-offset], 4)!=0 ){
++ pFile->transCntrChng = 1; /* The transaction counter has changed */
+ }
+- unixLeaveMutex();
+ }
+ }
+ #endif
+
+- else if( pLockingStyle == &dotlockIoMethods ){
+- /* Dotfile locking uses the file path so it needs to be included in
+- ** the dotlockLockingContext
+- */
+- char *zLockFile;
+- int nFilename;
+- assert( zFilename!=0 );
+- nFilename = (int)strlen(zFilename) + 6;
+- zLockFile = (char *)sqlite3_malloc(nFilename);
+- if( zLockFile==0 ){
+- rc = SQLITE_NOMEM;
++#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);
++ return SQLITE_OK;
+ }else{
+- sqlite3_snprintf(nFilename, zLockFile, "%s" DOTLOCK_SUFFIX, zFilename);
++ int nCopy = pFile->mmapSize - offset;
++ memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, nCopy);
++ pBuf = &((u8 *)pBuf)[nCopy];
++ amt -= nCopy;
++ offset += nCopy;
+ }
+- pNew->lockingContext = zLockFile;
+ }
++#endif
+
+-#if OS_VXWORKS
+- else if( pLockingStyle == &semIoMethods ){
+- /* Named semaphore locking uses the file path so it needs to be
+- ** included in the semLockingContext
+- */
+- unixEnterMutex();
+- rc = findInodeInfo(pNew, &pNew->pInode);
+- if( (rc==SQLITE_OK) && (pNew->pInode->pSem==NULL) ){
+- char *zSemName = pNew->pInode->aSemName;
+- int n;
+- sqlite3_snprintf(MAX_PATHNAME, zSemName, "/%s.sem",
+- pNew->pId->zCanonicalName);
+- for( n=1; zSemName[n]; n++ )
+- if( zSemName[n]=='/' ) zSemName[n] = '_';
+- pNew->pInode->pSem = sem_open(zSemName, O_CREAT, 0666, 1);
+- if( pNew->pInode->pSem == SEM_FAILED ){
+- rc = SQLITE_NOMEM;
+- pNew->pInode->aSemName[0] = '\0';
+- }
++ while( amt>0 && (wrote = seekAndWrite(pFile, offset, pBuf, amt))>0 ){
++ amt -= wrote;
++ offset += wrote;
++ pBuf = &((char*)pBuf)[wrote];
++ }
++ SimulateIOError(( wrote=(-1), amt=1 ));
++ SimulateDiskfullError(( wrote=0, amt=1 ));
++
++ if( amt>0 ){
++ if( wrote<0 && pFile->lastErrno!=ENOSPC ){
++ /* lastErrno set by seekAndWrite */
++ return SQLITE_IOERR_WRITE;
++ }else{
++ pFile->lastErrno = 0; /* not a system error */
++ return SQLITE_FULL;
+ }
+- unixLeaveMutex();
+ }
++
++ return SQLITE_OK;
++}
++
++#ifdef SQLITE_TEST
++/*
++** Count the number of fullsyncs and normal syncs. This is used to test
++** that syncs and fullsyncs are occurring at the right times.
++*/
++SQLITE_API int sqlite3_sync_count = 0;
++SQLITE_API int sqlite3_fullsync_count = 0;
+ #endif
+-
+- pNew->lastErrno = 0;
+-#if OS_VXWORKS
+- if( rc!=SQLITE_OK ){
+- if( h>=0 ) robust_close(pNew, h, __LINE__);
+- h = -1;
+- osUnlink(zFilename);
+- pNew->ctrlFlags |= UNIXFILE_DELETE;
+- }
++
++/*
++** 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
++*/
++#if !defined(fdatasync)
++# define fdatasync fsync
+ #endif
+- if( rc!=SQLITE_OK ){
+- if( h>=0 ) robust_close(pNew, h, __LINE__);
+- }else{
+- pNew->pMethod = pLockingStyle;
+- OpenCounter(+1);
+- verifyDbFile(pNew);
+- }
+- return rc;
+-}
+
+ /*
+-** Return the name of a directory in which to put temporary files.
+-** If no suitable temporary file directory can be found, return NULL.
++** Define HAVE_FULLFSYNC to 0 or 1 depending on whether or not
++** the F_FULLFSYNC macro is defined. F_FULLFSYNC is currently
++** only available on Mac OS X. But that could change.
+ */
+-static const char *unixTempFileDir(void){
+- static const char *azDirs[] = {
+- 0,
+- 0,
+- "/var/tmp",
+- "/usr/tmp",
+- "/tmp",
+- 0 /* List terminator */
+- };
+- unsigned int i;
+- struct stat buf;
+- const char *zDir = 0;
++#ifdef F_FULLFSYNC
++# define HAVE_FULLFSYNC 1
++#else
++# define HAVE_FULLFSYNC 0
++#endif
+
+- azDirs[0] = sqlite3_temp_directory;
+- if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR");
+- for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); zDir=azDirs[i++]){
+- if( zDir==0 ) continue;
+- if( osStat(zDir, &buf) ) continue;
+- if( !S_ISDIR(buf.st_mode) ) continue;
+- if( osAccess(zDir, 07) ) continue;
+- break;
+- }
+- return zDir;
+-}
+
+ /*
+-** Create a temporary file name in zBuf. zBuf must be allocated
+-** by the calling process and must be big enough to hold at least
+-** pVfs->mxPathname bytes.
++** The fsync() system call does not work as advertised on many
++** unix systems. The following procedure is an attempt to make
++** it work better.
++**
++** The SQLITE_NO_SYNC macro disables all fsync()s. This is useful
++** for testing when we want to run through the test suite quickly.
++** You are strongly advised *not* to deploy with SQLITE_NO_SYNC
++** enabled, however, since with SQLITE_NO_SYNC enabled, an OS crash
++** or power failure will likely corrupt the database file.
++**
++** SQLite sets the dataOnly flag if the size of the file is unchanged.
++** The idea behind dataOnly is that it should only write the file content
++** to disk, not the inode. We only set dataOnly if the file size is
++** unchanged since the file size is part of the inode. However,
++** Ted Ts'o tells us that fdatasync() will also write the inode if the
++** file size has changed. The only real difference between fdatasync()
++** and fsync(), Ted tells us, is that fdatasync() will not flush the
++** inode if the mtime or owner or other inode attributes have changed.
++** We only care about the file size, not the other file attributes, so
++** as far as SQLite is concerned, an fdatasync() is always adequate.
++** So, we always use fdatasync() if it is available, regardless of
++** the value of the dataOnly flag.
+ */
+-static int unixGetTempname(int nBuf, char *zBuf){
+- static const unsigned char zChars[] =
+- "abcdefghijklmnopqrstuvwxyz"
+- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+- "0123456789";
+- unsigned int i, j;
+- const char *zDir;
++static int full_fsync(int fd, int fullSync, int dataOnly){
++ int rc;
+
+- /* 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.
++ /* The following "ifdef/elif/else/" block has the same structure as
++ ** the one below. It is replicated here solely to avoid cluttering
++ ** up the real code with the UNUSED_PARAMETER() macros.
+ */
+- SimulateIOError( return SQLITE_IOERR );
++#ifdef SQLITE_NO_SYNC
++ UNUSED_PARAMETER(fd);
++ UNUSED_PARAMETER(fullSync);
++ UNUSED_PARAMETER(dataOnly);
++#elif HAVE_FULLFSYNC
++ UNUSED_PARAMETER(dataOnly);
++#else
++ UNUSED_PARAMETER(fullSync);
++ UNUSED_PARAMETER(dataOnly);
++#endif
+
+- zDir = unixTempFileDir();
+- if( zDir==0 ) zDir = ".";
++ /* Record the number of times that we do a normal fsync() and
++ ** FULLSYNC. This is used during testing to verify that this procedure
++ ** gets called with the correct arguments.
++ */
++#ifdef SQLITE_TEST
++ if( fullSync ) sqlite3_fullsync_count++;
++ sqlite3_sync_count++;
++#endif
+
+- /* Check that the output buffer is large enough for the temporary file
+- ** name. If it is not, return SQLITE_ERROR.
++ /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a
++ ** no-op
+ */
+- if( (strlen(zDir) + strlen(SQLITE_TEMP_FILE_PREFIX) + 18) >= (size_t)nBuf ){
+- return SQLITE_ERROR;
++#ifdef SQLITE_NO_SYNC
++ rc = SQLITE_OK;
++#elif HAVE_FULLFSYNC
++ if( fullSync ){
++ rc = osFcntl(fd, F_FULLFSYNC, 0);
++ }else{
++ rc = 1;
++ }
++ /* If the FULLFSYNC failed, fall back to attempting an fsync().
++ ** It shouldn't be possible for fullfsync to fail on the local
++ ** file system (on OSX), so failure indicates that FULLFSYNC
++ ** isn't supported for this file system. So, attempt an fsync
++ ** and (for now) ignore the overhead of a superfluous fcntl call.
++ ** It'd be better to detect fullfsync support once and avoid
++ ** the fcntl call every time sync is called.
++ */
++ if( rc ) rc = fsync(fd);
++
++#elif defined(__APPLE__)
++ /* fdatasync() on HFS+ doesn't yet flush the file size if it changed correctly
++ ** so currently we default to the macro that redefines fdatasync to fsync
++ */
++ rc = fsync(fd);
++#else
++ rc = fdatasync(fd);
++#if OS_VXWORKS
++ if( rc==-1 && errno==ENOTSUP ){
++ rc = fsync(fd);
+ }
++#endif /* OS_VXWORKS */
++#endif /* ifdef SQLITE_NO_SYNC elif HAVE_FULLFSYNC */
+
+- do{
+- sqlite3_snprintf(nBuf-18, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX, zDir);
+- j = (int)strlen(zBuf);
+- sqlite3_randomness(15, &zBuf[j]);
+- for(i=0; i<15; i++, j++){
+- zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
+- }
+- zBuf[j] = 0;
+- zBuf[j+1] = 0;
+- }while( osAccess(zBuf,0)==0 );
+- return SQLITE_OK;
++ if( OS_VXWORKS && rc!= -1 ){
++ rc = 0;
++ }
++ return rc;
+ }
+
+-#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
+ /*
+-** Routine to transform a unixFile into a proxy-locking unixFile.
+-** Implementation in the proxy-lock division, but used by unixOpen()
+-** if SQLITE_PREFER_PROXY_LOCKING is defined.
++** Open a file descriptor to the directory containing file zFilename.
++** If successful, *pFd is set to the opened file descriptor and
++** SQLITE_OK is returned. If an error occurs, either SQLITE_NOMEM
++** or SQLITE_CANTOPEN is returned and *pFd is set to an undefined
++** value.
++**
++** The directory file descriptor is used for only one thing - to
++** fsync() a directory to make sure file creation and deletion events
++** are flushed to disk. Such fsyncs are not needed on newer
++** journaling filesystems, but are required on older filesystems.
++**
++** This routine can be overridden using the xSetSysCall interface.
++** The ability to override this routine was added in support of the
++** chromium sandbox. Opening a directory is a security risk (we are
++** told) so making it overrideable allows the chromium sandbox to
++** replace this routine with a harmless no-op. To make this routine
++** a no-op, replace it with a stub that returns SQLITE_OK but leaves
++** *pFd set to a negative number.
++**
++** If SQLITE_OK is returned, the caller is responsible for closing
++** the file descriptor *pFd using close().
+ */
+-static int proxyTransformUnixFile(unixFile*, const char*);
+-#endif
++static int openDirectory(const char *zFilename, int *pFd){
++ int ii;
++ int fd = -1;
++ char zDirname[MAX_PATHNAME+1];
++
++ sqlite3_snprintf(MAX_PATHNAME, zDirname, "%s", zFilename);
++ for(ii=(int)strlen(zDirname); ii>1 && zDirname[ii]!='/'; ii--);
++ if( ii>0 ){
++ zDirname[ii] = '\0';
++ fd = robust_open(zDirname, O_RDONLY|O_BINARY, 0);
++ if( fd>=0 ){
++ OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname));
++ }
++ }
++ *pFd = fd;
++ return (fd>=0?SQLITE_OK:unixLogError(SQLITE_CANTOPEN_BKPT, "open", zDirname));
++}
+
+ /*
+-** Search for an unused file descriptor that was opened on the database
+-** file (not a journal or master-journal file) identified by pathname
+-** zPath with SQLITE_OPEN_XXX flags matching those passed as the second
+-** argument to this function.
++** Make sure all writes to a particular file are committed to disk.
+ **
+-** Such a file descriptor may exist if a database connection was closed
+-** but the associated file descriptor could not be closed because some
+-** other file descriptor open on the same file is holding a file-lock.
+-** Refer to comments in the unixClose() function and the lengthy comment
+-** describing "Posix Advisory Locking" at the start of this file for
+-** further details. Also, ticket #4018.
++** If dataOnly==0 then both the file itself and its metadata (file
++** size, access time, etc) are synced. If dataOnly!=0 then only the
++** file data is synced.
+ **
+-** If a suitable file descriptor is found, then it is returned. If no
+-** such file descriptor is located, -1 is returned.
++** Under Unix, also make sure that the directory entry for the file
++** has been created by fsync-ing the directory that contains the file.
++** If we do not do this and we encounter a power failure, the directory
++** entry for the journal might not exist after we reboot. The next
++** SQLite to access the file will not know that the journal exists (because
++** the directory entry for the journal was never created) and the transaction
++** will not roll back - possibly leading to database corruption.
+ */
+-static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
+- UnixUnusedFd *pUnused = 0;
++static int unixSync(sqlite3_file *id, int flags){
++ int rc;
++ unixFile *pFile = (unixFile*)id;
+
+- /* Do not search for an unused file descriptor on vxworks. Not because
+- ** vxworks would not benefit from the change (it might, we're not sure),
+- ** but because no way to test it is currently available. It is better
+- ** not to risk breaking vxworks support for the sake of such an obscure
+- ** feature. */
+-#if !OS_VXWORKS
+- struct stat sStat; /* Results of stat() call */
++ int isDataOnly = (flags&SQLITE_SYNC_DATAONLY);
++ int isFullsync = (flags&0x0F)==SQLITE_SYNC_FULL;
+
+- /* A stat() call may fail for various reasons. If this happens, it is
+- ** almost certain that an open() call on the same path will also fail.
+- ** For this reason, if an error occurs in the stat() call here, it is
+- ** ignored and -1 is returned. The caller will try to open a new file
+- ** 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. */
+- if( 0==osStat(zPath, &sStat) ){
+- unixInodeInfo *pInode;
++ /* Check that one of SQLITE_SYNC_NORMAL or FULL was passed */
++ assert((flags&0x0F)==SQLITE_SYNC_NORMAL
++ || (flags&0x0F)==SQLITE_SYNC_FULL
++ );
+
+- unixEnterMutex();
+- pInode = inodeList;
+- while( pInode && (pInode->fileId.dev!=sStat.st_dev
+- || pInode->fileId.ino!=sStat.st_ino) ){
+- pInode = pInode->pNext;
+- }
+- if( pInode ){
+- UnixUnusedFd **pp;
+- for(pp=&pInode->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext));
+- pUnused = *pp;
+- if( pUnused ){
+- *pp = pUnused->pNext;
+- }
++ /* 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 );
++
++ assert( pFile );
++ OSTRACE(("SYNC %-3d\n", pFile->h));
++ rc = full_fsync(pFile->h, isFullsync, isDataOnly);
++ SimulateIOError( rc=1 );
++ if( rc ){
++ pFile->lastErrno = errno;
++ return unixLogError(SQLITE_IOERR_FSYNC, "full_fsync", pFile->zPath);
++ }
++
++ /* Also fsync the directory containing the file if the DIRSYNC flag
++ ** is set. This is a one-time occurrence. Many systems (examples: AIX)
++ ** are unable to fsync a directory, so ignore errors on the fsync.
++ */
++ if( pFile->ctrlFlags & UNIXFILE_DIRSYNC ){
++ int dirfd;
++ OSTRACE(("DIRSYNC %s (have_fullfsync=%d fullsync=%d)\n", pFile->zPath,
++ HAVE_FULLFSYNC, isFullsync));
++ rc = osOpenDirectory(pFile->zPath, &dirfd);
++ if( rc==SQLITE_OK && dirfd>=0 ){
++ full_fsync(dirfd, 0, 0);
++ robust_close(pFile, dirfd, __LINE__);
++ }else if( rc==SQLITE_CANTOPEN ){
++ rc = SQLITE_OK;
+ }
+- unixLeaveMutex();
++ pFile->ctrlFlags &= ~UNIXFILE_DIRSYNC;
+ }
+-#endif /* if !OS_VXWORKS */
+- return pUnused;
++ return rc;
+ }
+
+ /*
+-** This function is called by unixOpen() to determine the unix permissions
+-** to create new files with. If no error occurs, then SQLITE_OK is returned
+-** and a value suitable for passing as the third argument to open(2) is
+-** 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
+-** 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
+-** this function queries the file-system for the permissions on the
+-** corresponding database file and sets *pMode to this value. Whenever
+-** possible, WAL and journal files are created using the same permissions
+-** as the associated database file.
+-**
+-** If the SQLITE_ENABLE_8_3_NAMES option is enabled, then the
+-** original filename is unavailable. But 8_3_NAMES is only used for
+-** FAT filesystems and permissions do not matter there, so just use
+-** the default permissions.
++** Truncate an open file to a specified size
+ */
+-static int findCreateFileMode(
+- const char *zPath, /* Path of file (possibly) being created */
+- int flags, /* Flags passed as 4th argument to xOpen() */
+- mode_t *pMode, /* OUT: Permissions to open file with */
+- uid_t *pUid, /* OUT: uid to set on the file */
+- gid_t *pGid /* OUT: gid to set on the file */
+-){
+- int rc = SQLITE_OK; /* Return Code */
+- *pMode = 0;
+- *pUid = 0;
+- *pGid = 0;
+- if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){
+- char zDb[MAX_PATHNAME+1]; /* Database file path */
+- int nDb; /* Number of valid bytes in zDb */
+- struct stat sStat; /* Output of stat() on database file */
++static int unixTruncate(sqlite3_file *id, i64 nByte){
++ unixFile *pFile = (unixFile *)id;
++ int rc;
++ assert( pFile );
++ SimulateIOError( return SQLITE_IOERR_TRUNCATE );
+
+- /* zPath is a path to a WAL or journal file. The following block derives
+- ** the path to the associated database file from zPath. This block handles
+- ** the following naming conventions:
+- **
+- ** "<path to db>-journal"
+- ** "<path to db>-wal"
+- ** "<path to db>-journalNN"
+- ** "<path to db>-walNN"
+- **
+- ** where NN is a decimal number. The NN naming schemes are
+- ** used by the test_multiplex.c module.
+- */
+- nDb = sqlite3Strlen30(zPath) - 1;
+-#ifdef SQLITE_ENABLE_8_3_NAMES
+- while( nDb>0 && sqlite3Isalnum(zPath[nDb]) ) nDb--;
+- if( nDb==0 || zPath[nDb]!='-' ) return SQLITE_OK;
+-#else
+- while( zPath[nDb]!='-' ){
+- assert( nDb>0 );
+- assert( zPath[nDb]!='\n' );
+- nDb--;
++ /* 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;
++ }
++
++ rc = robust_ftruncate(pFile->h, (off_t)nByte);
++ if( rc ){
++ pFile->lastErrno = errno;
++ return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
++ }else{
++#ifdef SQLITE_DEBUG
++ /* If we are doing a normal write to a database file (as opposed to
++ ** doing a hot-journal rollback or a write to some file other than a
++ ** normal database file) and we truncate the file to zero length,
++ ** that effectively updates the change counter. This might happen
++ ** when restoring a database using the backup API from a zero-length
++ ** source.
++ */
++ if( pFile->inNormalWrite && nByte==0 ){
++ pFile->transCntrChng = 1;
+ }
+ #endif
+- memcpy(zDb, zPath, nDb);
+- zDb[nDb] = '\0';
+
+- if( 0==osStat(zDb, &sStat) ){
+- *pMode = sStat.st_mode & 0777;
+- *pUid = sStat.st_uid;
+- *pGid = sStat.st_gid;
+- }else{
+- rc = SQLITE_IOERR_FSTAT;
++ /* If the file was just 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( nByte<pFile->mmapSize ){
++ pFile->mmapSize = nByte;
+ }
+- }else if( flags & SQLITE_OPEN_DELETEONCLOSE ){
+- *pMode = 0600;
++
++ return SQLITE_OK;
+ }
+- return rc;
+ }
+
+ /*
+-** Open the file zPath.
+-**
+-** Previously, the SQLite OS layer used three functions in place of this
+-** one:
+-**
+-** sqlite3OsOpenReadWrite();
+-** sqlite3OsOpenReadOnly();
+-** sqlite3OsOpenExclusive();
+-**
+-** These calls correspond to the following combinations of flags:
+-**
+-** ReadWrite() -> (READWRITE | CREATE)
+-** ReadOnly() -> (READONLY)
+-** OpenExclusive() -> (READWRITE | CREATE | EXCLUSIVE)
+-**
+-** The old OpenExclusive() accepted a boolean argument - "delFlag". If
+-** true, the file was configured to be automatically deleted when the
+-** file handle closed. To achieve the same effect using this new
+-** interface, add the DELETEONCLOSE flag to those specified above for
+-** OpenExclusive().
++** Determine the current size of a file in bytes
+ */
+-static int unixOpen(
+- sqlite3_vfs *pVfs, /* The VFS for which this is the xOpen method */
+- const char *zPath, /* Pathname of file to be opened */
+- sqlite3_file *pFile, /* The file descriptor to be filled in */
+- int flags, /* Input flags to control the opening */
+- int *pOutFlags /* Output flags returned to SQLite core */
+-){
+- unixFile *p = (unixFile *)pFile;
+- int fd = -1; /* File descriptor returned by open() */
+- int openFlags = 0; /* Flags to pass to open() */
+- int eType = flags&0xFFFFFF00; /* Type of file to open */
+- int noLock; /* True to omit locking primitives */
+- int rc = SQLITE_OK; /* Function Return Code */
+- int ctrlFlags = 0; /* UNIXFILE_* flags */
+-
+- 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 SQLITE_ENABLE_LOCKING_STYLE
+- int isAutoProxy = (flags & SQLITE_OPEN_AUTOPROXY);
+-#endif
+-#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
+- struct statfs fsInfo;
+-#endif
++static int unixFileSize(sqlite3_file *id, i64 *pSize){
++ int rc;
++ struct stat buf;
++ assert( id );
++ rc = osFstat(((unixFile*)id)->h, &buf);
++ SimulateIOError( rc=1 );
++ if( rc!=0 ){
++ ((unixFile*)id)->lastErrno = errno;
++ return SQLITE_IOERR_FSTAT;
++ }
++ *pSize = buf.st_size;
+
+- /* If creating a master or main-file journal, this function will open
+- ** a file-descriptor on the directory too. The first time unixSync()
+- ** is called the directory file descriptor will be fsync()ed and close()d.
++ /* When opening a zero-size database, the findInodeInfo() procedure
++ ** writes a single byte into that file in order to work around a bug
++ ** in the OS-X msdos filesystem. In order to avoid problems with upper
++ ** layers, we need to report this file size as zero even though it is
++ ** really 1. Ticket #3260.
+ */
+- int syncDir = (isCreate && (
+- eType==SQLITE_OPEN_MASTER_JOURNAL
+- || eType==SQLITE_OPEN_MAIN_JOURNAL
+- || eType==SQLITE_OPEN_WAL
+- ));
++ if( *pSize==1 ) *pSize = 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[MAX_PATHNAME+2];
+- const char *zName = zPath;
+
+- /* 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);
++ return SQLITE_OK;
++}
+
+- /* 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 );
++#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
++/*
++** Handler for proxy-locking file-control verbs. Defined below in the
++** proxying locking division.
++*/
++static int proxyFileControl(sqlite3_file*,int,void*);
++#endif
+
+- /* 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
+- );
++/*
++** This function is called to handle the SQLITE_FCNTL_SIZE_HINT
++** file-control operation. Enlarge the database to nBytes in size
++** (rounded up to the next chunk-size). If the database is already
++** nBytes or larger, this routine is a no-op.
++*/
++static int fcntlSizeHint(unixFile *pFile, i64 nByte){
++ if( pFile->szChunk>0 ){
++ i64 nSize; /* Required file size */
++ struct stat buf; /* Used to hold return values of fstat() */
++
++ if( osFstat(pFile->h, &buf) ) return SQLITE_IOERR_FSTAT;
+
+- memset(p, 0, sizeof(unixFile));
++ nSize = ((nByte+pFile->szChunk-1) / pFile->szChunk) * pFile->szChunk;
++ if( nSize>(i64)buf.st_size ){
+
+- if( eType==SQLITE_OPEN_MAIN_DB ){
+- UnixUnusedFd *pUnused;
+- pUnused = findReusableFd(zName, flags);
+- if( pUnused ){
+- fd = pUnused->fd;
+- }else{
+- pUnused = sqlite3_malloc(sizeof(*pUnused));
+- if( !pUnused ){
+- return SQLITE_NOMEM;
++#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
++ /* The code below is handling the return value of osFallocate()
++ ** correctly. posix_fallocate() is defined to "returns zero on success,
++ ** or an error number on failure". See the manpage for details. */
++ int err;
++ do{
++ err = osFallocate(pFile->h, buf.st_size, nSize-buf.st_size);
++ }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.
++ */
++ int nBlk = buf.st_blksize; /* File-system block size */
++ 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);
++ if( nWrite!=1 ) return SQLITE_IOERR_WRITE;
++ iWrite += nBlk;
+ }
++#endif
+ }
+- p->pUnused = pUnused;
+-
+- /* Database filenames are double-zero terminated if they are not
+- ** URIs with parameters. Hence, they can always be passed into
+- ** sqlite3_uri_parameter(). */
+- assert( (flags & SQLITE_OPEN_URI) || zName[strlen(zName)+1]==0 );
++ }
+
+- }else if( !zName ){
+- /* If zName is NULL, the upper layer is requesting a temp file. */
+- assert(isDelete && !syncDir);
+- rc = unixGetTempname(MAX_PATHNAME+2, zTmpname);
+- if( rc!=SQLITE_OK ){
+- return rc;
++ if( pFile->mmapSizeMax>0 && nByte>pFile->mmapSize ){
++ int rc;
++ if( pFile->szChunk<=0 ){
++ if( robust_ftruncate(pFile->h, nByte) ){
++ pFile->lastErrno = errno;
++ return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
++ }
+ }
+- zName = zTmpname;
+
+- /* Generated temporary filenames are always double-zero terminated
+- ** for use by sqlite3_uri_parameter(). */
+- assert( zName[strlen(zName)+1]==0 );
++ rc = unixMapfile(pFile, nByte);
++ return rc;
+ }
+
+- /* Determine the value of the flags parameter passed to POSIX function
+- ** open(). These must be calculated even if open() is not called, as
+- ** they may be stored as part of the file handle and used by the
+- ** 'conch file' locking functions later on. */
+- if( isReadonly ) openFlags |= O_RDONLY;
+- if( isReadWrite ) openFlags |= O_RDWR;
+- if( isCreate ) openFlags |= O_CREAT;
+- if( isExclusive ) openFlags |= (O_EXCL|O_NOFOLLOW);
+- openFlags |= (O_LARGEFILE|O_BINARY);
++ return SQLITE_OK;
++}
+
+- if( fd<0 ){
+- mode_t openMode; /* Permissions to create file with */
+- uid_t uid; /* Userid for the file */
+- gid_t gid; /* Groupid for the file */
+- rc = findCreateFileMode(zName, flags, &openMode, &uid, &gid);
+- if( rc!=SQLITE_OK ){
+- assert( !p->pUnused );
+- assert( eType==SQLITE_OPEN_WAL || eType==SQLITE_OPEN_MAIN_JOURNAL );
++/*
++** If *pArg is inititially 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.
++*/
++static void unixModeBit(unixFile *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;
++ }
++}
++
++/* Forward declaration */
++static int unixGetTempname(int nBuf, char *zBuf);
++
++/*
++** Information and control of an open file handle.
++*/
++static int unixFileControl(sqlite3_file *id, int op, void *pArg){
++ unixFile *pFile = (unixFile*)id;
++ switch( op ){
++ case SQLITE_FCNTL_LOCKSTATE: {
++ *(int*)pArg = pFile->eFileLock;
++ return SQLITE_OK;
++ }
++ case SQLITE_LAST_ERRNO: {
++ *(int*)pArg = pFile->lastErrno;
++ return SQLITE_OK;
++ }
++ case SQLITE_FCNTL_CHUNK_SIZE: {
++ pFile->szChunk = *(int *)pArg;
++ return SQLITE_OK;
++ }
++ case SQLITE_FCNTL_SIZE_HINT: {
++ int rc;
++ SimulateIOErrorBenign(1);
++ rc = fcntlSizeHint(pFile, *(i64 *)pArg);
++ SimulateIOErrorBenign(0);
+ return rc;
+ }
+- fd = robust_open(zName, openFlags, openMode);
+- OSTRACE(("OPENX %-3d %s 0%o\n", fd, zName, openFlags));
+- if( fd<0 && errno!=EISDIR && isReadWrite && !isExclusive ){
+- /* Failed to open the file for read/write access. Try read-only. */
+- flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
+- openFlags &= ~(O_RDWR|O_CREAT);
+- flags |= SQLITE_OPEN_READONLY;
+- openFlags |= O_RDONLY;
+- isReadonly = 1;
+- fd = robust_open(zName, openFlags, openMode);
++ case SQLITE_FCNTL_PERSIST_WAL: {
++ unixModeBit(pFile, UNIXFILE_PERSIST_WAL, (int*)pArg);
++ return SQLITE_OK;
+ }
+- if( fd<0 ){
+- rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
+- goto open_finished;
++ case SQLITE_FCNTL_POWERSAFE_OVERWRITE: {
++ unixModeBit(pFile, UNIXFILE_PSOW, (int*)pArg);
++ return SQLITE_OK;
+ }
+-
+- /* If this process is running as root and if creating a new rollback
+- ** journal or WAL file, set the ownership of the journal or WAL to be
+- ** the same as the original database.
++ case SQLITE_FCNTL_VFSNAME: {
++ *(char**)pArg = sqlite3_mprintf("%s", pFile->pVfs->zName);
++ return SQLITE_OK;
++ }
++ case SQLITE_FCNTL_TEMPFILENAME: {
++ char *zTFile = sqlite3_malloc( pFile->pVfs->mxPathname );
++ if( zTFile ){
++ unixGetTempname(pFile->pVfs->mxPathname, zTFile);
++ *(char**)pArg = zTFile;
++ }
++ return SQLITE_OK;
++ }
++ case SQLITE_FCNTL_MMAP_SIZE: {
++ i64 newLimit = *(i64*)pArg;
++ if( newLimit>sqlite3GlobalConfig.mxMmap ){
++ newLimit = sqlite3GlobalConfig.mxMmap;
++ }
++ *(i64*)pArg = pFile->mmapSizeMax;
++ if( newLimit>=0 ){
++ pFile->mmapSizeMax = newLimit;
++ if( newLimit<pFile->mmapSize ) pFile->mmapSize = newLimit;
++ }
++ return SQLITE_OK;
++ }
++#ifdef SQLITE_DEBUG
++ /* The pager calls this method to signal that it has done
++ ** a rollback and that the database is therefore unchanged and
++ ** it hence it is OK for the transaction change counter to be
++ ** unchanged.
+ */
+- if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){
+- osFchown(fd, uid, gid);
++ case SQLITE_FCNTL_DB_UNCHANGED: {
++ ((unixFile*)id)->dbUpdate = 0;
++ return SQLITE_OK;
+ }
+- }
+- assert( fd>=0 );
+- if( pOutFlags ){
+- *pOutFlags = flags;
+- }
+-
+- if( p->pUnused ){
+- p->pUnused->fd = fd;
+- p->pUnused->flags = flags;
+- }
+-
+- if( isDelete ){
+-#if OS_VXWORKS
+- zPath = zName;
+-#else
+- osUnlink(zName);
+ #endif
++#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
++ case SQLITE_SET_LOCKPROXYFILE:
++ case SQLITE_GET_LOCKPROXYFILE: {
++ return proxyFileControl(id,op,pArg);
++ }
++#endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */
+ }
+-#if SQLITE_ENABLE_LOCKING_STYLE
+- else{
+- p->openFlags = openFlags;
+- }
+-#endif
+-
+- noLock = eType!=SQLITE_OPEN_MAIN_DB;
++ return SQLITE_NOTFOUND;
++}
+
+-
+-#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
+- if( fstatfs(fd, &fsInfo) == -1 ){
+- ((unixFile*)pFile)->lastErrno = 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;
+- }
++/*
++** 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.
++*/
++#ifndef __QNXNTO__
++static int unixSectorSize(sqlite3_file *NotUsed){
++ UNUSED_PARAMETER(NotUsed);
++ return SQLITE_DEFAULT_SECTOR_SIZE;
++}
+ #endif
+
+- /* Set up appropriate ctrlFlags */
+- if( isDelete ) ctrlFlags |= UNIXFILE_DELETE;
+- if( isReadonly ) ctrlFlags |= UNIXFILE_RDONLY;
+- if( noLock ) ctrlFlags |= UNIXFILE_NOLOCK;
+- if( syncDir ) ctrlFlags |= UNIXFILE_DIRSYNC;
+- if( flags & SQLITE_OPEN_URI ) ctrlFlags |= UNIXFILE_URI;
+-
+-#if SQLITE_ENABLE_LOCKING_STYLE
+-#if SQLITE_PREFER_PROXY_LOCKING
+- isAutoProxy = 1;
+-#endif
+- if( isAutoProxy && (zPath!=NULL) && (!noLock) && pVfs->xOpen ){
+- char *envforce = getenv("SQLITE_FORCE_PROXY_LOCKING");
+- int useProxy = 0;
++/*
++** The following version of unixSectorSize() is optimized for QNX.
++*/
++#ifdef __QNXNTO__
++#include <sys/dcmd_blk.h>
++#include <sys/statvfs.h>
++static int unixSectorSize(sqlite3_file *id){
++ unixFile *pFile = (unixFile*)id;
++ if( pFile->sectorSize == 0 ){
++ struct statvfs fsInfo;
++
++ /* Set defaults for non-supported filesystems */
++ pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
++ pFile->deviceCharacteristics = 0;
++ if( fstatvfs(pFile->h, &fsInfo) == -1 ) {
++ return pFile->sectorSize;
++ }
+
+- /* SQLITE_FORCE_PROXY_LOCKING==1 means force always use proxy, 0 means
+- ** never use proxy, NULL means use proxy for non-local files only. */
+- if( envforce!=NULL ){
+- useProxy = atoi(envforce)>0;
++ if( !strcmp(fsInfo.f_basetype, "tmp") ) {
++ pFile->sectorSize = fsInfo.f_bsize;
++ pFile->deviceCharacteristics =
++ SQLITE_IOCAP_ATOMIC4K | /* All ram filesystem writes are atomic */
++ SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until
++ ** the write succeeds */
++ SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
++ ** so it is ordered */
++ 0;
++ }else if( strstr(fsInfo.f_basetype, "etfs") ){
++ pFile->sectorSize = fsInfo.f_bsize;
++ pFile->deviceCharacteristics =
++ /* etfs cluster size writes are atomic */
++ (pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) |
++ SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until
++ ** the write succeeds */
++ SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
++ ** so it is ordered */
++ 0;
++ }else if( !strcmp(fsInfo.f_basetype, "qnx6") ){
++ pFile->sectorSize = fsInfo.f_bsize;
++ pFile->deviceCharacteristics =
++ SQLITE_IOCAP_ATOMIC | /* All filesystem writes are atomic */
++ SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until
++ ** the write succeeds */
++ SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
++ ** so it is ordered */
++ 0;
++ }else if( !strcmp(fsInfo.f_basetype, "qnx4") ){
++ pFile->sectorSize = fsInfo.f_bsize;
++ pFile->deviceCharacteristics =
++ /* full bitset of atomics from max sector size and smaller */
++ ((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2 |
++ SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
++ ** so it is ordered */
++ 0;
++ }else if( strstr(fsInfo.f_basetype, "dos") ){
++ pFile->sectorSize = fsInfo.f_bsize;
++ pFile->deviceCharacteristics =
++ /* full bitset of atomics from max sector size and smaller */
++ ((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2 |
++ SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
++ ** so it is ordered */
++ 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 ){
+- rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
+- if( rc==SQLITE_OK ){
+- rc = proxyTransformUnixFile((unixFile*)pFile, ":auto:");
+- if( rc!=SQLITE_OK ){
+- /* Use unixClose to clean up the resources added in fillInUnixFile
+- ** and clear all the structure's references. Specifically,
+- ** pFile->pMethods will be NULL so sqlite3OsClose will be a no-op
+- */
+- unixClose(pFile);
+- return rc;
+- }
+- }
+- goto open_finished;
++ pFile->deviceCharacteristics =
++ SQLITE_IOCAP_ATOMIC512 | /* blocks are atomic */
++ SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until
++ ** the write succeeds */
++ 0;
+ }
+ }
+-#endif
+-
+- rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
+-
+-open_finished:
+- if( rc!=SQLITE_OK ){
+- sqlite3_free(p->pUnused);
++ /* Last chance verification. If the sector size isn't a multiple of 512
++ ** then it isn't valid.*/
++ if( pFile->sectorSize % 512 != 0 ){
++ pFile->deviceCharacteristics = 0;
++ pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
+ }
+- return rc;
++ return pFile->sectorSize;
+ }
+-
++#endif /* __QNXNTO__ */
+
+ /*
+-** Delete the file at zPath. If the dirSync argument is true, fsync()
+-** the directory after deleting the file.
++** 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
++** 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,
++** very rare. And asserting PSOW makes a large reduction in the amount
++** of required I/O for journaling, since a lot of padding is eliminated.
++** Hence, while POWERSAFE_OVERWRITE is on by default, there is a file-control
++** available to turn it off and URI query parameter available to turn it off.
+ */
+-static int unixDelete(
+- sqlite3_vfs *NotUsed, /* VFS containing this as the xDelete method */
+- const char *zPath, /* Name of file to be deleted */
+- int dirSync /* If true, fsync() directory after deleting file */
+-){
+- int rc = SQLITE_OK;
+- UNUSED_PARAMETER(NotUsed);
+- SimulateIOError(return SQLITE_IOERR_DELETE);
+- if( osUnlink(zPath)==(-1) ){
+- if( errno==ENOENT ){
+- rc = SQLITE_IOERR_DELETE_NOENT;
+- }else{
+- rc = unixLogError(SQLITE_IOERR_DELETE, "unlink", zPath);
+- }
+- return rc;
+- }
+-#ifndef SQLITE_DISABLE_DIRSYNC
+- if( (dirSync & 1)!=0 ){
+- int fd;
+- rc = osOpenDirectory(zPath, &fd);
+- if( rc==SQLITE_OK ){
+-#if OS_VXWORKS
+- if( fsync(fd)==-1 )
+-#else
+- if( fsync(fd) )
++static int unixDeviceCharacteristics(sqlite3_file *id){
++ unixFile *p = (unixFile*)id;
++ int rc = 0;
++#ifdef __QNXNTO__
++ if( p->sectorSize==0 ) unixSectorSize(id);
++ rc = p->deviceCharacteristics;
+ #endif
+- {
+- rc = unixLogError(SQLITE_IOERR_DIR_FSYNC, "fsync", zPath);
+- }
+- robust_close(0, fd, __LINE__);
+- }else if( rc==SQLITE_CANTOPEN ){
+- rc = SQLITE_OK;
+- }
++ if( p->ctrlFlags & UNIXFILE_PSOW ){
++ rc |= SQLITE_IOCAP_POWERSAFE_OVERWRITE;
+ }
+-#endif
+ return rc;
+ }
+
++#ifndef SQLITE_OMIT_WAL
++
++
+ /*
+-** Test the existence of or access permissions of file zPath. The
+-** test performed depends on the value of flags:
++** Object used to represent an shared memory buffer.
+ **
+-** SQLITE_ACCESS_EXISTS: Return 1 if the file exists
+-** SQLITE_ACCESS_READWRITE: Return 1 if the file is read and writable.
+-** SQLITE_ACCESS_READONLY: Return 1 if the file is readable.
++** When multiple threads all reference the same wal-index, each thread
++** has its own unixShm object, but they all point to a single instance
++** of this unixShmNode object. In other words, each wal-index is opened
++** only once per process.
+ **
+-** Otherwise return 0.
++** Each unixShmNode object is connected to a single unixInodeInfo object.
++** We could coalesce this object into unixInodeInfo, but that would mean
++** every open file that does not use shared memory (in other words, most
++** open files) would have to carry around this extra information. So
++** the unixInodeInfo object contains a pointer to this unixShmNode object
++** and the unixShmNode object is created only when needed.
++**
++** unixMutexHeld() must be true when creating or destroying
++** this object or while reading or writing the following fields:
++**
++** nRef
++**
++** The following fields are read-only after the object is created:
++**
++** fid
++** zFilename
++**
++** Either unixShmNode.mutex must be held or unixShmNode.nRef==0 and
++** unixMutexHeld() is true when reading or writing any other field
++** in this structure.
+ */
+-static int unixAccess(
+- sqlite3_vfs *NotUsed, /* The VFS containing this xAccess method */
+- const char *zPath, /* Path of the file to examine */
+- int flags, /* What do we want to learn about the zPath file? */
+- int *pResOut /* Write result boolean here */
+-){
+- int amode = 0;
+- UNUSED_PARAMETER(NotUsed);
+- SimulateIOError( return SQLITE_IOERR_ACCESS; );
+- switch( flags ){
+- case SQLITE_ACCESS_EXISTS:
+- amode = F_OK;
+- break;
+- case SQLITE_ACCESS_READWRITE:
+- amode = W_OK|R_OK;
+- break;
+- case SQLITE_ACCESS_READ:
+- amode = R_OK;
+- break;
++struct unixShmNode {
++ unixInodeInfo *pInode; /* unixInodeInfo that owns this SHM node */
++ sqlite3_mutex *mutex; /* Mutex to access this object */
++ char *zFilename; /* Name of the mmapped file */
++ int h; /* Open file descriptor */
++ int szRegion; /* Size of shared-memory regions */
++ u16 nRegion; /* Size of array apRegion */
++ u8 isReadonly; /* True if read-only */
++ char **apRegion; /* Array of mapped shared-memory regions */
++ int nRef; /* Number of unixShm objects pointing to this */
++ unixShm *pFirst; /* All unixShm objects pointing to this */
++#ifdef SQLITE_DEBUG
++ u8 exclMask; /* Mask of exclusive locks held */
++ u8 sharedMask; /* Mask of shared locks held */
++ u8 nextShmId; /* Next available unixShm.id value */
++#endif
++};
+
+- default:
+- assert(!"Invalid flags argument");
+- }
+- *pResOut = (osAccess(zPath, amode)==0);
+- if( flags==SQLITE_ACCESS_EXISTS && *pResOut ){
+- struct stat buf;
+- if( 0==osStat(zPath, &buf) && buf.st_size==0 ){
+- *pResOut = 0;
+- }
+- }
+- return SQLITE_OK;
+-}
++/*
++** 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:
++**
++** unixShm.pFile
++** unixShm.id
++**
++** All other fields are read/write. The unixShm.pFile->mutex must be held
++** while accessing any read/write fields.
++*/
++struct unixShm {
++ unixShmNode *pShmNode; /* The underlying unixShmNode object */
++ unixShm *pNext; /* Next unixShm with the same unixShmNode */
++ u8 hasMutex; /* True if holding the unixShmNode mutex */
++ u8 id; /* Id of this connection within its unixShmNode */
++ u16 sharedMask; /* Mask of shared locks held */
++ u16 exclMask; /* Mask of exclusive locks held */
++};
+
++/*
++** Constants used for locking
++*/
++#define UNIX_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */
++#define UNIX_SHM_DMS (UNIX_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */
+
+ /*
+-** Turn a relative pathname into a full pathname. The relative path
+-** is stored as a nul-terminated string in the buffer pointed to by
+-** zPath.
++** Apply posix advisory locks for all bytes from ofst through ofst+n-1.
+ **
+-** zOut points to a buffer of at least sqlite3_vfs.mxPathname bytes
+-** (in this case, MAX_PATHNAME bytes). The full-path is written to
+-** this buffer before returning.
++** Locks block if the mask is exactly UNIX_SHM_C and are non-blocking
++** otherwise.
+ */
+-static int unixFullPathname(
+- sqlite3_vfs *pVfs, /* Pointer to vfs object */
+- const char *zPath, /* Possibly relative input path */
+- int nOut, /* Size of output buffer in bytes */
+- char *zOut /* Output buffer */
++static int unixShmSystemLock(
++ unixShmNode *pShmNode, /* Apply locks to this open shared-memory segment */
++ 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() */
+
+- /* 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 );
++ /* Access to the unixShmNode object is serialized by the caller */
++ assert( sqlite3_mutex_held(pShmNode->mutex) || pShmNode->nRef==0 );
+
+- assert( pVfs->mxPathname==MAX_PATHNAME );
+- UNUSED_PARAMETER(pVfs);
++ /* Shared locks never span more than one byte */
++ assert( n==1 || lockType!=F_RDLCK );
+
+- zOut[nOut-1] = '\0';
+- if( zPath[0]=='/' ){
+- sqlite3_snprintf(nOut, zOut, "%s", zPath);
++ /* Locks are within range */
++ assert( n>=1 && n<SQLITE_SHM_NLOCK );
++
++ if( pShmNode->h>=0 ){
++ /* Initialize the locking parameters */
++ memset(&f, 0, sizeof(f));
++ f.l_type = lockType;
++ f.l_whence = SEEK_SET;
++ f.l_start = ofst;
++ f.l_len = n;
++
++ rc = osFcntl(pShmNode->h, F_SETLK, &f);
++ rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY;
++ }
++
++ /* Update the global lock state and do debug tracing */
++#ifdef SQLITE_DEBUG
++ { u16 mask;
++ OSTRACE(("SHM-LOCK "));
++ mask = (1<<(ofst+n)) - (1<<ofst);
++ if( rc==SQLITE_OK ){
++ if( lockType==F_UNLCK ){
++ OSTRACE(("unlock %d ok", ofst));
++ pShmNode->exclMask &= ~mask;
++ pShmNode->sharedMask &= ~mask;
++ }else if( lockType==F_RDLCK ){
++ OSTRACE(("read-lock %d ok", ofst));
++ pShmNode->exclMask &= ~mask;
++ pShmNode->sharedMask |= mask;
++ }else{
++ assert( lockType==F_WRLCK );
++ OSTRACE(("write-lock %d ok", ofst));
++ pShmNode->exclMask |= mask;
++ pShmNode->sharedMask &= ~mask;
++ }
+ }else{
+- int nCwd;
+- if( osGetcwd(zOut, nOut-1)==0 ){
+- return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath);
++ if( lockType==F_UNLCK ){
++ OSTRACE(("unlock %d failed", ofst));
++ }else if( lockType==F_RDLCK ){
++ OSTRACE(("read-lock failed"));
++ }else{
++ assert( lockType==F_WRLCK );
++ OSTRACE(("write-lock %d failed", ofst));
+ }
+- nCwd = (int)strlen(zOut);
+- sqlite3_snprintf(nOut-nCwd, &zOut[nCwd], "/%s", zPath);
+ }
+- return SQLITE_OK;
+-}
+-
++ OSTRACE((" - afterwards %03x,%03x\n",
++ pShmNode->sharedMask, pShmNode->exclMask));
++ }
++#endif
+
+-#ifndef SQLITE_OMIT_LOAD_EXTENSION
+-/*
+-** Interfaces for opening a shared library, finding entry points
+-** within the shared library, and closing the shared library.
+-*/
+-#include <dlfcn.h>
+-static void *unixDlOpen(sqlite3_vfs *NotUsed, const char *zFilename){
+- UNUSED_PARAMETER(NotUsed);
+- return dlopen(zFilename, RTLD_NOW | RTLD_GLOBAL);
++ return rc;
+ }
+
++
+ /*
+-** SQLite calls this function immediately after a call to unixDlSym() or
+-** unixDlOpen() fails (returns a null pointer). If a more detailed error
+-** message is available, it is written to zBufOut. If no error message
+-** is available, zBufOut is left unmodified and SQLite uses a default
+-** error message.
++** Purge the unixShmNodeList list of all entries with unixShmNode.nRef==0.
++**
++** This is not a VFS shared-memory method; it is a utility function called
++** by VFS shared-memory methods.
+ */
+-static void unixDlError(sqlite3_vfs *NotUsed, int nBuf, char *zBufOut){
+- const char *zErr;
+- UNUSED_PARAMETER(NotUsed);
+- unixEnterMutex();
+- zErr = dlerror();
+- if( zErr ){
+- sqlite3_snprintf(nBuf, zBufOut, "%s", zErr);
++static void unixShmPurge(unixFile *pFd){
++ unixShmNode *p = pFd->pInode->pShmNode;
++ assert( unixMutexHeld() );
++ if( p && p->nRef==0 ){
++ int i;
++ assert( p->pInode==pFd->pInode );
++ sqlite3_mutex_free(p->mutex);
++ for(i=0; i<p->nRegion; i++){
++ if( p->h>=0 ){
++ osMunmap(p->apRegion[i], p->szRegion);
++ }else{
++ sqlite3_free(p->apRegion[i]);
++ }
++ }
++ sqlite3_free(p->apRegion);
++ if( p->h>=0 ){
++ robust_close(pFd, p->h, __LINE__);
++ p->h = -1;
++ }
++ p->pInode->pShmNode = 0;
++ sqlite3_free(p);
+ }
+- unixLeaveMutex();
+-}
+-static void (*unixDlSym(sqlite3_vfs *NotUsed, void *p, const char*zSym))(void){
+- /*
+- ** GCC with -pedantic-errors says that C90 does not allow a void* to be
+- ** cast into a pointer to a function. And yet the library dlsym() routine
+- ** returns a void* which is really a pointer to a function. So how do we
+- ** use dlsym() with -pedantic-errors?
+- **
+- ** Variable x below is defined to be a pointer to a function taking
+- ** parameters void* and const char* and returning a pointer to a function.
+- ** We initialize x by assigning it a pointer to the dlsym() function.
+- ** (That assignment requires a cast.) Then we call the function that
+- ** x points to.
+- **
+- ** This work-around is unlikely to work correctly on any system where
+- ** you really cannot cast a function pointer into void*. But then, on the
+- ** other hand, dlsym() will not work on such a system either, so we have
+- ** not really lost anything.
+- */
+- void (*(*x)(void*,const char*))(void);
+- UNUSED_PARAMETER(NotUsed);
+- x = (void(*(*)(void*,const char*))(void))dlsym;
+- return (*x)(p, zSym);
+-}
+-static void unixDlClose(sqlite3_vfs *NotUsed, void *pHandle){
+- UNUSED_PARAMETER(NotUsed);
+- dlclose(pHandle);
+ }
+-#else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */
+- #define unixDlOpen 0
+- #define unixDlError 0
+- #define unixDlSym 0
+- #define unixDlClose 0
+-#endif
+
+ /*
+-** Write nBuf bytes of random data to the supplied buffer zBuf.
++** Open a shared-memory area associated with open database file pDbFd.
++** This particular implementation uses mmapped files.
++**
++** The file used to implement shared-memory is in the same directory
++** as the open database file and has the same name as the open database
++** file with the "-shm" suffix added. For example, if the database file
++** is "/home/user1/config.db" then the file that is created and mmapped
++** for shared memory will be called "/home/user1/config.db-shm".
++**
++** Another approach to is to use files in /dev/shm or /dev/tmp or an
++** some other tmpfs mount. But if a file in a different directory
++** from the database file is used, then differing access permissions
++** or a chroot() might cause two different processes on the same
++** database to end up using different files for shared memory -
++** meaning that their memory would not really be shared - resulting
++** in database corruption. Nevertheless, this tmpfs file usage
++** can be enabled at compile-time using -DSQLITE_SHM_DIRECTORY="/dev/shm"
++** or the equivalent. The use of the SQLITE_SHM_DIRECTORY compile-time
++** option results in an incompatible build of SQLite; builds of SQLite
++** that with differing SQLITE_SHM_DIRECTORY settings attempt to use the
++** same database file at the same time, database corruption will likely
++** result. The SQLITE_SHM_DIRECTORY compile-time option is considered
++** "unsupported" and may go away in a future SQLite release.
++**
++** 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.
++**
++** If the original database file (pDbFd) is using the "unix-excl" VFS
++** that means that an exclusive lock is held on the database file and
++** that no other processes are able to read or write the database. In
++** that case, we do not really need shared memory. No shared memory
++** file is created. The shared memory will be simulated with heap memory.
+ */
+-static int unixRandomness(sqlite3_vfs *NotUsed, int nBuf, char *zBuf){
+- UNUSED_PARAMETER(NotUsed);
+- assert((size_t)nBuf>=(sizeof(time_t)+sizeof(int)));
++static int unixOpenSharedMemory(unixFile *pDbFd){
++ struct unixShm *p = 0; /* The connection to be opened */
++ struct unixShmNode *pShmNode; /* The underlying mmapped file */
++ int rc; /* Result code */
++ unixInodeInfo *pInode; /* The inode of fd */
++ char *zShmFilename; /* Name of the file used for SHM */
++ int nShmFilename; /* Size of the SHM filename in bytes */
+
+- /* We have to initialize zBuf to prevent valgrind from reporting
+- ** errors. The reports issued by valgrind are incorrect - we would
+- ** prefer that the randomness be increased by making use of the
+- ** uninitialized space in zBuf - but valgrind errors tend to worry
+- ** some users. Rather than argue, it seems easier just to initialize
+- ** the whole array and silence valgrind, even if that means less randomness
+- ** in the random seed.
+- **
+- ** When testing, initializing zBuf[] to zero is all we do. That means
+- ** that we always use the same random number sequence. This makes the
+- ** tests repeatable.
+- */
+- memset(zBuf, 0, nBuf);
+-#if !defined(SQLITE_TEST)
+- {
+- int pid, fd, got;
+- fd = robust_open("/dev/urandom", O_RDONLY, 0);
+- if( fd<0 ){
+- time_t t;
+- time(&t);
+- memcpy(zBuf, &t, sizeof(t));
+- pid = getpid();
+- memcpy(&zBuf[sizeof(t)], &pid, sizeof(pid));
+- assert( sizeof(t)+sizeof(pid)<=(size_t)nBuf );
+- nBuf = sizeof(t) + sizeof(pid);
+- }else{
+- do{ got = osRead(fd, zBuf, nBuf); }while( got<0 && errno==EINTR );
+- robust_close(0, fd, __LINE__);
+- }
+- }
+-#endif
+- return nBuf;
+-}
++ /* Allocate space for the new unixShm object. */
++ p = sqlite3_malloc( sizeof(*p) );
++ if( p==0 ) return SQLITE_NOMEM;
++ memset(p, 0, sizeof(*p));
++ assert( pDbFd->pShm==0 );
+
++ /* Check to see if a unixShmNode object already exists. Reuse an existing
++ ** one if present. Create a new one if necessary.
++ */
++ unixEnterMutex();
++ pInode = pDbFd->pInode;
++ pShmNode = pInode->pShmNode;
++ if( pShmNode==0 ){
++ struct stat sStat; /* fstat() info for database file */
+
+-/*
+-** Sleep for a little while. Return the amount of time slept.
+-** The argument is the number of microseconds we want to sleep.
+-** The return value is the number of microseconds of sleep actually
+-** requested from the underlying operating system, a number which
+-** might be greater than or equal to the argument, but not less
+-** than the argument.
+-*/
+-static int unixSleep(sqlite3_vfs *NotUsed, int microseconds){
+-#if OS_VXWORKS
+- struct timespec sp;
++ /* 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
++ ** with the same permissions.
++ */
++ if( osFstat(pDbFd->h, &sStat) && pInode->bProcessLock==0 ){
++ rc = SQLITE_IOERR_FSTAT;
++ goto shm_open_err;
++ }
+
+- sp.tv_sec = microseconds / 1000000;
+- sp.tv_nsec = (microseconds % 1000000) * 1000;
+- nanosleep(&sp, NULL);
+- UNUSED_PARAMETER(NotUsed);
+- return microseconds;
+-#elif defined(HAVE_USLEEP) && HAVE_USLEEP
+- usleep(microseconds);
+- UNUSED_PARAMETER(NotUsed);
+- return microseconds;
++#ifdef SQLITE_SHM_DIRECTORY
++ nShmFilename = sizeof(SQLITE_SHM_DIRECTORY) + 31;
+ #else
+- int seconds = (microseconds+999999)/1000000;
+- sleep(seconds);
+- UNUSED_PARAMETER(NotUsed);
+- return seconds*1000000;
++ nShmFilename = 6 + (int)strlen(pDbFd->zPath);
+ #endif
+-}
++ pShmNode = sqlite3_malloc( sizeof(*pShmNode) + nShmFilename );
++ if( pShmNode==0 ){
++ rc = SQLITE_NOMEM;
++ goto shm_open_err;
++ }
++ memset(pShmNode, 0, sizeof(*pShmNode)+nShmFilename);
++ zShmFilename = pShmNode->zFilename = (char*)&pShmNode[1];
++#ifdef SQLITE_SHM_DIRECTORY
++ sqlite3_snprintf(nShmFilename, zShmFilename,
++ SQLITE_SHM_DIRECTORY "/sqlite-shm-%x-%x",
++ (u32)sStat.st_ino, (u32)sStat.st_dev);
++#else
++ sqlite3_snprintf(nShmFilename, zShmFilename, "%s-shm", pDbFd->zPath);
++ sqlite3FileSuffix3(pDbFd->zPath, zShmFilename);
++#endif
++ pShmNode->h = -1;
++ pDbFd->pInode->pShmNode = pShmNode;
++ pShmNode->pInode = pDbFd->pInode;
++ pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
++ if( pShmNode->mutex==0 ){
++ rc = SQLITE_NOMEM;
++ goto shm_open_err;
++ }
++
++ if( pInode->bProcessLock==0 ){
++ int openFlags = O_RDWR | O_CREAT;
++ if( sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){
++ openFlags = O_RDONLY;
++ pShmNode->isReadonly = 1;
++ }
++ pShmNode->h = robust_open(zShmFilename, openFlags, (sStat.st_mode&0777));
++ if( pShmNode->h<0 ){
++ rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename);
++ goto shm_open_err;
++ }
++
++ /* If this process is running as root, make sure that the SHM file
++ ** is owned by the same user that owns the original database. Otherwise,
++ ** the original owner will not be able to connect.
++ */
++ osFchown(pShmNode->h, sStat.st_uid, sStat.st_gid);
++
++ /* Check to see if another process is holding the dead-man switch.
++ ** If not, truncate the file to zero length.
++ */
++ rc = SQLITE_OK;
++ if( unixShmSystemLock(pShmNode, 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);
++ }
++ if( rc ) goto shm_open_err;
++ }
++ }
+
+-/*
+-** 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. */
++ /* Make the new connection a child of the unixShmNode */
++ p->pShmNode = pShmNode;
++#ifdef SQLITE_DEBUG
++ p->id = pShmNode->nextShmId++;
+ #endif
++ pShmNode->nRef++;
++ pDbFd->pShm = p;
++ unixLeaveMutex();
++
++ /* The reference count on pShmNode has already been incremented under
++ ** the cover of the unixEnterMutex() mutex and the pointer from the
++ ** new (struct unixShm) 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:
++ unixShmPurge(pDbFd); /* This call frees pShmNode if required */
++ sqlite3_free(p);
++ unixLeaveMutex();
++ return rc;
++}
+
+ /*
+-** 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.
++** 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.
+ **
+-** On success, return SQLITE_OK. Return SQLITE_ERROR if the time and date
+-** cannot be found.
++** If an error occurs, an error code is returned and *pp is set to NULL.
++**
++** Otherwise, if the bExtend 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
++** bExtend 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 unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){
+- static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
++static int unixShmMap(
++ sqlite3_file *fd, /* Handle open on database file */
++ int iRegion, /* Region to retrieve */
++ int szRegion, /* Size of regions */
++ int bExtend, /* True to extend file if necessary */
++ void volatile **pp /* OUT: Mapped memory */
++){
++ unixFile *pDbFd = (unixFile*)fd;
++ unixShm *p;
++ unixShmNode *pShmNode;
+ int rc = SQLITE_OK;
+-#if defined(NO_GETTOD)
+- time_t t;
+- time(&t);
+- *piNow = ((sqlite3_int64)t)*1000 + unixEpoch;
+-#elif OS_VXWORKS
+- struct timespec sNow;
+- clock_gettime(CLOCK_REALTIME, &sNow);
+- *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_nsec/1000000;
+-#else
+- struct timeval sNow;
+- if( gettimeofday(&sNow, 0)==0 ){
+- *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000;
+- }else{
+- rc = SQLITE_ERROR;
++
++ /* If the shared-memory file has not yet been opened, open it now. */
++ if( pDbFd->pShm==0 ){
++ rc = unixOpenSharedMemory(pDbFd);
++ if( rc!=SQLITE_OK ) return rc;
+ }
+-#endif
+
+-#ifdef SQLITE_TEST
+- if( sqlite3_current_time ){
+- *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch;
++ p = pDbFd->pShm;
++ pShmNode = p->pShmNode;
++ sqlite3_mutex_enter(pShmNode->mutex);
++ assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
++ assert( pShmNode->pInode==pDbFd->pInode );
++ assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 );
++ assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 );
++
++ if( pShmNode->nRegion<=iRegion ){
++ char **apNew; /* New apRegion[] array */
++ int nByte = (iRegion+1)*szRegion; /* Minimum required file size */
++ struct stat sStat; /* Used by fstat() */
++
++ pShmNode->szRegion = szRegion;
++
++ if( pShmNode->h>=0 ){
++ /* 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).
++ */
++ if( osFstat(pShmNode->h, &sStat) ){
++ rc = SQLITE_IOERR_SHMSIZE;
++ goto shmpage_out;
++ }
++
++ if( sStat.st_size<nByte ){
++ /* The requested memory region does not exist. If bExtend is set to
++ ** false, exit early. *pp will be set to NULL and SQLITE_OK returned.
++ */
++ if( !bExtend ){
++ goto shmpage_out;
++ }
++
++ /* Alternatively, if bExtend is true, extend the file. Do this by
++ ** writing a single byte to the end of each (OS) page being
++ ** allocated or extended. Technically, we need only write to the
++ ** last page in order to extend the file. But writing to all new
++ ** pages forces the OS to allocate them immediately, which reduces
++ ** the chances of SIGBUS while accessing the mapped region later on.
++ */
++ else{
++ static const int pgsz = 4096;
++ int iPg;
++
++ /* Write to the last byte of each newly allocated or extended page */
++ assert( (nByte % pgsz)==0 );
++ for(iPg=(sStat.st_size/pgsz); iPg<(nByte/pgsz); iPg++){
++ if( seekAndWriteFd(pShmNode->h, iPg*pgsz + pgsz-1, "", 1, 0)!=1 ){
++ const char *zFile = pShmNode->zFilename;
++ rc = unixLogError(SQLITE_IOERR_SHMSIZE, "write", zFile);
++ goto shmpage_out;
++ }
++ }
++ }
++ }
++ }
++
++ /* Map the requested memory region into this processes address space. */
++ apNew = (char **)sqlite3_realloc(
++ pShmNode->apRegion, (iRegion+1)*sizeof(char *)
++ );
++ if( !apNew ){
++ rc = SQLITE_IOERR_NOMEM;
++ goto shmpage_out;
++ }
++ pShmNode->apRegion = apNew;
++ while(pShmNode->nRegion<=iRegion){
++ void *pMem;
++ if( pShmNode->h>=0 ){
++ pMem = osMmap(0, szRegion,
++ pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE,
++ MAP_SHARED, pShmNode->h, szRegion*(i64)pShmNode->nRegion
++ );
++ if( pMem==MAP_FAILED ){
++ rc = unixLogError(SQLITE_IOERR_SHMMAP, "mmap", pShmNode->zFilename);
++ goto shmpage_out;
++ }
++ }else{
++ pMem = sqlite3_malloc(szRegion);
++ if( pMem==0 ){
++ rc = SQLITE_NOMEM;
++ goto shmpage_out;
++ }
++ memset(pMem, 0, szRegion);
++ }
++ pShmNode->apRegion[pShmNode->nRegion] = pMem;
++ pShmNode->nRegion++;
++ }
+ }
+-#endif
+- UNUSED_PARAMETER(NotUsed);
+- return rc;
+-}
+
+-/*
+-** 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.
+-*/
+-static int unixCurrentTime(sqlite3_vfs *NotUsed, double *prNow){
+- sqlite3_int64 i = 0;
+- int rc;
+- UNUSED_PARAMETER(NotUsed);
+- rc = unixCurrentTimeInt64(0, &i);
+- *prNow = i/86400000.0;
++shmpage_out:
++ if( pShmNode->nRegion>iRegion ){
++ *pp = pShmNode->apRegion[iRegion];
++ }else{
++ *pp = 0;
++ }
++ if( pShmNode->isReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY;
++ sqlite3_mutex_leave(pShmNode->mutex);
+ return rc;
+ }
+
+ /*
+-** We added the xGetLastError() method with the intention of providing
+-** better low-level error messages when operating-system problems come up
+-** during SQLite operation. But so far, none of that has been implemented
+-** in the core. So this routine is never called. For now, it is merely
+-** a place-holder.
+-*/
+-static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
+- UNUSED_PARAMETER(NotUsed);
+- UNUSED_PARAMETER(NotUsed2);
+- UNUSED_PARAMETER(NotUsed3);
+- return 0;
+-}
+-
+-
+-/*
+-************************ End of sqlite3_vfs methods ***************************
+-******************************************************************************/
+-
+-/******************************************************************************
+-************************** Begin Proxy Locking ********************************
+-**
+-** Proxy locking is a "uber-locking-method" in this sense: It uses the
+-** other locking methods on secondary lock files. Proxy locking is a
+-** meta-layer over top of the primitive locking implemented above. For
+-** this reason, the division that implements of proxy locking is deferred
+-** until late in the file (here) after all of the other I/O methods have
+-** been defined - so that the primitive locking methods are available
+-** as services to help with the implementation of proxy locking.
+-**
+-****
+-**
+-** The default locking schemes in SQLite use byte-range locks on the
+-** database file to coordinate safe, concurrent access by multiple readers
+-** and writers [http://sqlite.org/lockingv3.html]. The five file locking
+-** states (UNLOCKED, PENDING, SHARED, RESERVED, EXCLUSIVE) are implemented
+-** as POSIX read & write locks over fixed set of locations (via fsctl),
+-** on AFP and SMB only exclusive byte-range locks are available via fsctl
+-** with _IOWR('z', 23, struct ByteRangeLockPB2) to track the same 5 states.
+-** To simulate a F_RDLCK on the shared range, on AFP a randomly selected
+-** address in the shared range is taken for a SHARED lock, the entire
+-** shared range is taken for an EXCLUSIVE lock):
+-**
+-** PENDING_BYTE 0x40000000
+-** RESERVED_BYTE 0x40000001
+-** SHARED_RANGE 0x40000002 -> 0x40000200
+-**
+-** This works well on the local file system, but shows a nearly 100x
+-** slowdown in read performance on AFP because the AFP client disables
+-** the read cache when byte-range locks are present. Enabling the read
+-** cache exposes a cache coherency problem that is present on all OS X
+-** supported network file systems. NFS and AFP both observe the
+-** close-to-open semantics for ensuring cache coherency
+-** [http://nfs.sourceforge.net/#faq_a8], which does not effectively
+-** address the requirements for concurrent database access by multiple
+-** readers and writers
+-** [http://www.nabble.com/SQLite-on-NFS-cache-coherency-td15655701.html].
+-**
+-** To address the performance and cache coherency issues, proxy file locking
+-** changes the way database access is controlled by limiting access to a
+-** single host at a time and moving file locks off of the database file
+-** and onto a proxy file on the local file system.
+-**
+-**
+-** Using proxy locks
+-** -----------------
+-**
+-** C APIs
+-**
+-** sqlite3_file_control(db, dbname, SQLITE_SET_LOCKPROXYFILE,
+-** <proxy_path> | ":auto:");
+-** sqlite3_file_control(db, dbname, SQLITE_GET_LOCKPROXYFILE, &<proxy_path>);
+-**
+-**
+-** SQL pragmas
+-**
+-** PRAGMA [database.]lock_proxy_file=<proxy_path> | :auto:
+-** PRAGMA [database.]lock_proxy_file
+-**
+-** Specifying ":auto:" means that if there is a conch file with a matching
+-** host ID in it, the proxy path in the conch file will be used, otherwise
+-** a proxy path based on the user's temp dir
+-** (via confstr(_CS_DARWIN_USER_TEMP_DIR,...)) will be used and the
+-** actual proxy file name is generated from the name and path of the
+-** database file. For example:
+-**
+-** For database path "/Users/me/foo.db"
+-** The lock path will be "<tmpdir>/sqliteplocks/_Users_me_foo.db:auto:")
+-**
+-** Once a lock proxy is configured for a database connection, it can not
+-** be removed, however it may be switched to a different proxy path via
+-** the above APIs (assuming the conch file is not being held by another
+-** connection or process).
+-**
+-**
+-** How proxy locking works
+-** -----------------------
+-**
+-** Proxy file locking relies primarily on two new supporting files:
+-**
+-** * conch file to limit access to the database file to a single host
+-** at a time
+-**
+-** * proxy file to act as a proxy for the advisory locks normally
+-** taken on the database
+-**
+-** The conch file - to use a proxy file, sqlite must first "hold the conch"
+-** by taking an sqlite-style shared lock on the conch file, reading the
+-** contents and comparing the host's unique host ID (see below) and lock
+-** 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
+-** 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
+-** is held by another process (with a shared lock), the exclusive lock
+-** will fail and SQLITE_BUSY is returned.
+-**
+-** The proxy file - a single-byte file used for all advisory file locks
+-** normally taken on the database file. This allows for safe sharing
+-** of the database file for multiple readers and writers on the same
+-** host (the conch ensures that they all use the same local lock file).
+-**
+-** Requesting the lock proxy does not immediately take the conch, it is
+-** only taken when the first request to lock database file is made.
+-** This matches the semantics of the traditional locking behavior, where
+-** opening a connection to a database file does not take a lock on it.
+-** The shared lock and an open file descriptor are maintained until
+-** the connection to the database is closed.
+-**
+-** The proxy file and the lock file are never deleted so they only need
+-** to be created the first time they are used.
+-**
+-** Configuration options
+-** ---------------------
+-**
+-** SQLITE_PREFER_PROXY_LOCKING
+-**
+-** Database files accessed on non-local file systems are
+-** automatically configured for proxy locking, lock files are
+-** named automatically using the same logic as
+-** PRAGMA lock_proxy_file=":auto:"
+-**
+-** SQLITE_PROXY_DEBUG
+-**
+-** Enables the logging of error messages during host id file
+-** retrieval and creation
+-**
+-** LOCKPROXYDIR
+-**
+-** Overrides the default directory used for lock proxy files that
+-** are named automatically via the ":auto:" setting
+-**
+-** SQLITE_DEFAULT_PROXYDIR_PERMISSIONS
++** Change the lock state for a shared-memory segment.
+ **
+-** Permissions to use when creating a directory for storing the
+-** lock proxy files, only used when LOCKPROXYDIR is not set.
+-**
+-**
+-** As mentioned above, when compiled with SQLITE_PREFER_PROXY_LOCKING,
+-** 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
+-** sqlite_file_control API is not affected by SQLITE_FORCE_PROXY_LOCKING).
++** Note that the relationship between SHAREd and EXCLUSIVE locks is a little
++** different here than in posix. In xShmLock(), one can go from unlocked
++** to shared and back or from unlocked to exclusive and back. But one may
++** not go from shared to exclusive or from exclusive to shared.
+ */
++static int unixShmLock(
++ 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 */
++){
++ unixFile *pDbFd = (unixFile*)fd; /* Connection holding shared memory */
++ unixShm *p = pDbFd->pShm; /* The shared memory being locked */
++ unixShm *pX; /* For looping over all siblings */
++ unixShmNode *pShmNode = p->pShmNode; /* The underlying file iNode */
++ int rc = SQLITE_OK; /* Result code */
++ u16 mask; /* Mask of locks to take or release */
+
+-/*
+-** Proxy locking is only available on MacOSX
+-*/
+-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
++ assert( pShmNode==pDbFd->pInode->pShmNode );
++ assert( pShmNode->pInode==pDbFd->pInode );
++ 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 );
++ assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 );
++ assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 );
+
+-/*
+-** The proxyLockingContext has the path and file structures for the remote
+-** and local proxy files in it
+-*/
+-typedef struct proxyLockingContext proxyLockingContext;
+-struct proxyLockingContext {
+- unixFile *conchFile; /* Open conch file */
+- char *conchFilePath; /* Name of the conch file */
+- unixFile *lockProxy; /* Open proxy lock file */
+- 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 */
+- void *oldLockingContext; /* Original lockingcontext to restore on close */
+- sqlite3_io_methods const *pOldMethod; /* Original I/O methods for close */
+-};
++ mask = (1<<(ofst+n)) - (1<<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 */
+
+-/*
+-** The proxy lock file path for the database at dbPath is written into lPath,
+-** which must point to valid, writable memory large enough for a maxLen length
+-** file path.
+-*/
+-static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){
+- int len;
+- int dbLen;
+- int i;
++ /* 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;
++ }
+
+-#ifdef LOCKPROXYDIR
+- len = strlcpy(lPath, LOCKPROXYDIR, maxLen);
+-#else
+-# ifdef _CS_DARWIN_USER_TEMP_DIR
+- {
+- if( !confstr(_CS_DARWIN_USER_TEMP_DIR, lPath, maxLen) ){
+- OSTRACE(("GETLOCKPATH failed %s errno=%d pid=%d\n",
+- lPath, errno, getpid()));
+- return SQLITE_IOERR_LOCK;
++ /* Unlock the system-level locks */
++ if( (mask & allMask)==0 ){
++ rc = unixShmSystemLock(pShmNode, F_UNLCK, ofst+UNIX_SHM_BASE, n);
++ }else{
++ rc = SQLITE_OK;
+ }
+- len = strlcat(lPath, "sqliteplocks", maxLen);
+- }
+-# else
+- len = strlcpy(lPath, "/tmp/", maxLen);
+-# endif
+-#endif
+
+- if( lPath[len-1]!='/' ){
+- len = strlcat(lPath, "/", maxLen);
+- }
+-
+- /* transform the db path to a unique cache name */
+- dbLen = (int)strlen(dbPath);
+- for( i=0; i<dbLen && (i+len+7)<(int)maxLen; i++){
+- char c = dbPath[i];
+- lPath[i+len] = (c=='/')?'_':c;
+- }
+- lPath[i+len]='\0';
+- strlcat(lPath, ":auto:", maxLen);
+- OSTRACE(("GETLOCKPATH proxy lock path=%s pid=%d\n", lPath, getpid()));
+- return SQLITE_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" */
+
+-/*
+- ** Creates the lock file and any missing directories in lockPath
+- */
+-static int proxyCreateLockPath(const char *lockPath){
+- int i, len;
+- char buf[MAXPATHLEN];
+- int start = 0;
+-
+- assert(lockPath!=NULL);
+- /* try to create all the intermediate directories */
+- len = (int)strlen(lockPath);
+- buf[0] = lockPath[0];
+- for( i=1; i<len; i++ ){
+- if( lockPath[i] == '/' && (i - start > 0) ){
+- /* only mkdir if leaf dir != "." or "/" or ".." */
+- if( i-start>2 || (i-start==1 && buf[start] != '.' && buf[start] != '/')
+- || (i-start==2 && buf[start] != '.' && buf[start+1] != '.') ){
+- buf[i]='\0';
+- if( osMkdir(buf, SQLITE_DEFAULT_PROXYDIR_PERMISSIONS) ){
+- int err=errno;
+- if( err!=EEXIST ) {
+- OSTRACE(("CREATELOCKPATH FAILED creating %s, "
+- "'%s' proxy lock path=%s pid=%d\n",
+- buf, strerror(err), lockPath, getpid()));
+- return err;
+- }
+- }
++ /* 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;
+ }
+- start=i+1;
++ allShared |= pX->sharedMask;
+ }
+- buf[i] = lockPath[i];
+- }
+- OSTRACE(("CREATELOCKPATH proxy lock path=%s pid=%d\n", lockPath, getpid()));
+- return 0;
+-}
+-
+-/*
+-** Create a new VFS file descriptor (stored in memory obtained from
+-** sqlite3_malloc) and open the file named "path" in the file descriptor.
+-**
+-** The caller is responsible not only for closing the file descriptor
+-** but also for freeing the memory associated with the file descriptor.
+-*/
+-static int proxyCreateUnixFile(
+- const char *path, /* path for the new unixFile */
+- unixFile **ppFile, /* unixFile created and returned by ref */
+- int islockfile /* if non zero missing dirs will be created */
+-) {
+- int fd = -1;
+- unixFile *pNew;
+- int rc = SQLITE_OK;
+- int openFlags = O_RDWR | O_CREAT;
+- sqlite3_vfs dummyVfs;
+- int terrno = 0;
+- UnixUnusedFd *pUnused = NULL;
+
+- /* 1. first try to open/create the file
+- ** 2. if that fails, and this is a lock file (not-conch), try creating
+- ** the parent directories and then try again.
+- ** 3. if that fails, try to open the file read-only
+- ** otherwise return BUSY (if lock file) or CANTOPEN for the conch file
+- */
+- pUnused = findReusableFd(path, openFlags);
+- if( pUnused ){
+- fd = pUnused->fd;
+- }else{
+- pUnused = sqlite3_malloc(sizeof(*pUnused));
+- if( !pUnused ){
+- return SQLITE_NOMEM;
+- }
+- }
+- if( fd<0 ){
+- fd = robust_open(path, openFlags, 0);
+- terrno = errno;
+- if( fd<0 && errno==ENOENT && islockfile ){
+- if( proxyCreateLockPath(path) == SQLITE_OK ){
+- fd = robust_open(path, openFlags, 0);
++ /* 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);
++ }else{
++ rc = SQLITE_OK;
+ }
+ }
+- }
+- if( fd<0 ){
+- openFlags = O_RDONLY;
+- fd = robust_open(path, openFlags, 0);
+- terrno = errno;
+- }
+- if( fd<0 ){
+- if( islockfile ){
+- return SQLITE_BUSY;
++
++ /* Get the local shared locks */
++ if( rc==SQLITE_OK ){
++ p->sharedMask |= mask;
+ }
+- switch (terrno) {
+- case EACCES:
+- return SQLITE_PERM;
+- case EIO:
+- return SQLITE_IOERR_LOCK; /* even though it is the conch */
+- default:
+- return SQLITE_CANTOPEN_BKPT;
++ }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;
++ }
+ }
+- }
+-
+- pNew = (unixFile *)sqlite3_malloc(sizeof(*pNew));
+- if( pNew==NULL ){
+- rc = SQLITE_NOMEM;
+- goto end_create_proxy;
+- }
+- memset(pNew, 0, sizeof(unixFile));
+- pNew->openFlags = openFlags;
+- memset(&dummyVfs, 0, sizeof(dummyVfs));
+- dummyVfs.pAppData = (void*)&autolockIoFinder;
+- dummyVfs.zName = "dummy";
+- pUnused->fd = fd;
+- pUnused->flags = openFlags;
+- pNew->pUnused = pUnused;
+
+- rc = fillInUnixFile(&dummyVfs, fd, (sqlite3_file*)pNew, path, 0);
+- if( rc==SQLITE_OK ){
+- *ppFile = pNew;
+- return SQLITE_OK;
++ /* Get the exclusive locks at the system level. Then if successful
++ ** also mark the local connection as being locked.
++ */
++ if( rc==SQLITE_OK ){
++ rc = unixShmSystemLock(pShmNode, F_WRLCK, ofst+UNIX_SHM_BASE, n);
++ if( rc==SQLITE_OK ){
++ assert( (p->sharedMask & mask)==0 );
++ p->exclMask |= mask;
++ }
++ }
+ }
+-end_create_proxy:
+- robust_close(pNew, fd, __LINE__);
+- sqlite3_free(pNew);
+- sqlite3_free(pUnused);
++ sqlite3_mutex_leave(pShmNode->mutex);
++ OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n",
++ p->id, getpid(), p->sharedMask, p->exclMask));
+ return rc;
+ }
+
+-#ifdef SQLITE_TEST
+-/* simulate multiple hosts by creating unique hostid file paths */
+-SQLITE_API int sqlite3_hostid_num = 0;
+-#endif
++/*
++** 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.
++*/
++static void unixShmBarrier(
++ sqlite3_file *fd /* Database file holding the shared memory */
++){
++ UNUSED_PARAMETER(fd);
++ unixEnterMutex();
++ unixLeaveMutex();
++}
+
+-#define PROXY_HOSTIDLEN 16 /* conch file host id length */
++/*
++** Close a connection to shared-memory. Delete the underlying
++** storage if deleteFlag is true.
++**
++** If there is no shared memory associated with the connection then this
++** routine is a harmless no-op.
++*/
++static int unixShmUnmap(
++ sqlite3_file *fd, /* The underlying database file */
++ int deleteFlag /* Delete shared-memory if true */
++){
++ unixShm *p; /* The connection to be closed */
++ unixShmNode *pShmNode; /* The underlying shared-memory file */
++ unixShm **pp; /* For looping over sibling connections */
++ unixFile *pDbFd; /* The underlying database file */
+
+-/* Not always defined in the headers as it ought to be */
+-extern int gethostuuid(uuid_t id, const struct timespec *wait);
++ pDbFd = (unixFile*)fd;
++ p = pDbFd->pShm;
++ if( p==0 ) return SQLITE_OK;
++ pShmNode = p->pShmNode;
+
+-/* get the host ID via gethostuuid(), pHostID must point to PROXY_HOSTIDLEN
+-** bytes of writable memory.
+-*/
+-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
+- {
+- static const struct timespec timeout = {1, 0}; /* 1 sec timeout */
+- if( gethostuuid(pHostID, &timeout) ){
+- int err = errno;
+- if( pError ){
+- *pError = err;
+- }
+- return SQLITE_IOERR;
+- }
++ assert( pShmNode==pDbFd->pInode->pShmNode );
++ assert( pShmNode->pInode==pDbFd->pInode );
++
++ /* 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;
++
++ /* 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 */
++ unixEnterMutex();
++ assert( pShmNode->nRef>0 );
++ pShmNode->nRef--;
++ if( pShmNode->nRef==0 ){
++ if( deleteFlag && pShmNode->h>=0 ) osUnlink(pShmNode->zFilename);
++ unixShmPurge(pDbFd);
+ }
++ unixLeaveMutex();
++
++ return SQLITE_OK;
++}
++
++
+ #else
+- UNUSED_PARAMETER(pError);
+-#endif
+-#ifdef SQLITE_TEST
+- /* simulate multiple hosts by creating unique hostid file paths */
+- if( sqlite3_hostid_num != 0){
+- pHostID[0] = (char)(pHostID[0] + (char)(sqlite3_hostid_num & 0xFF));
++# define unixShmMap 0
++# define unixShmLock 0
++# define unixShmBarrier 0
++# define unixShmUnmap 0
++#endif /* #ifndef SQLITE_OMIT_WAL */
++
++/*
++** If it is currently memory mapped, unmap file pFd.
++*/
++static void unixUnmapfile(unixFile *pFd){
++ assert( pFd->nFetchOut==0 );
++#if SQLITE_MAX_MMAP_SIZE>0
++ if( pFd->pMapRegion ){
++ osMunmap(pFd->pMapRegion, pFd->mmapSizeActual);
++ pFd->pMapRegion = 0;
++ pFd->mmapSize = 0;
++ pFd->mmapSizeActual = 0;
+ }
+ #endif
+-
+- return SQLITE_OK;
+ }
+
+-/* The conch file contains the header, host id and lock file path
+- */
+-#define PROXY_CONCHVERSION 2 /* 1-byte header, 16-byte host id, path */
+-#define PROXY_HEADERLEN 1 /* conch file header length */
+-#define PROXY_PATHINDEX (PROXY_HEADERLEN+PROXY_HOSTIDLEN)
+-#define PROXY_MAXCONCHLEN (PROXY_HEADERLEN+PROXY_HOSTIDLEN+MAXPATHLEN)
++#if SQLITE_MAX_MMAP_SIZE>0
++/*
++** Return the system page size.
++*/
++static int unixGetPagesize(void){
++#if HAVE_MREMAP
++ return 512;
++#elif defined(_BSD_SOURCE)
++ return getpagesize();
++#else
++ return (int)sysconf(_SC_PAGESIZE);
++#endif
++}
++#endif /* SQLITE_MAX_MMAP_SIZE>0 */
+
+-/*
+-** Takes an open conch file, copies the contents to a new path and then moves
+-** it back. The newly created file's file descriptor is assigned to the
+-** conch file structure and finally the original conch file descriptor is
+-** closed. Returns zero if successful.
++#if SQLITE_MAX_MMAP_SIZE>0
++/*
++** Attempt to set the size of the memory mapping maintained by file
++** descriptor pFd to nNew bytes. Any existing mapping is discarded.
++**
++** If successful, this function sets the following variables:
++**
++** unixFile.pMapRegion
++** unixFile.mmapSize
++** unixFile.mmapSizeActual
++**
++** If unsuccessful, an error message is logged via sqlite3_log() and
++** the three variables above are zeroed. In this case SQLite should
++** continue accessing the database using the xRead() and xWrite()
++** methods.
+ */
+-static int proxyBreakConchLock(unixFile *pFile, uuid_t myHostID){
+- proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
+- unixFile *conchFile = pCtx->conchFile;
+- char tPath[MAXPATHLEN];
+- char buf[PROXY_MAXCONCHLEN];
+- char *cPath = pCtx->conchFilePath;
+- size_t readLen = 0;
+- size_t pathLen = 0;
+- char errmsg[64] = "";
+- int fd = -1;
+- int rc = -1;
+- UNUSED_PARAMETER(myHostID);
++static void unixRemapfile(
++ unixFile *pFd, /* File descriptor object */
++ i64 nNew /* Required mapping size */
++){
++ const char *zErr = "mmap";
++ int h = pFd->h; /* File descriptor open on db file */
++ u8 *pOrig = (u8 *)pFd->pMapRegion; /* Pointer to current file mapping */
++ i64 nOrig = pFd->mmapSizeActual; /* Size of pOrig region in bytes */
++ u8 *pNew = 0; /* Location of new mapping */
++ int flags = PROT_READ; /* Flags to pass to mmap() */
+
+- /* create a new path by replace the trailing '-conch' with '-break' */
+- pathLen = strlcpy(tPath, cPath, MAXPATHLEN);
+- if( pathLen>MAXPATHLEN || pathLen<6 ||
+- (strlcpy(&tPath[pathLen-5], "break", 6) != 5) ){
+- sqlite3_snprintf(sizeof(errmsg),errmsg,"path error (len %d)",(int)pathLen);
+- goto end_breaklock;
+- }
+- /* read the conch content */
+- readLen = osPread(conchFile->h, buf, PROXY_MAXCONCHLEN, 0);
+- if( readLen<PROXY_PATHINDEX ){
+- sqlite3_snprintf(sizeof(errmsg),errmsg,"read error (len %d)",(int)readLen);
+- goto end_breaklock;
+- }
+- /* write it out to the temporary break file */
+- fd = robust_open(tPath, (O_RDWR|O_CREAT|O_EXCL), 0);
+- if( fd<0 ){
+- sqlite3_snprintf(sizeof(errmsg), errmsg, "create failed (%d)", errno);
+- goto end_breaklock;
+- }
+- if( osPwrite(fd, buf, readLen, 0) != (ssize_t)readLen ){
+- sqlite3_snprintf(sizeof(errmsg), errmsg, "write failed (%d)", errno);
+- goto end_breaklock;
+- }
+- if( rename(tPath, cPath) ){
+- sqlite3_snprintf(sizeof(errmsg), errmsg, "rename failed (%d)", errno);
+- goto end_breaklock;
+- }
+- rc = 0;
+- fprintf(stderr, "broke stale lock on %s\n", cPath);
+- robust_close(pFile, conchFile->h, __LINE__);
+- conchFile->h = fd;
+- conchFile->openFlags = O_RDWR | O_CREAT;
++ assert( pFd->nFetchOut==0 );
++ assert( nNew>pFd->mmapSize );
++ assert( nNew<=pFd->mmapSizeMax );
++ assert( nNew>0 );
++ assert( pFd->mmapSizeActual>=pFd->mmapSize );
++ assert( MAP_FAILED!=0 );
+
+-end_breaklock:
+- if( rc ){
+- if( fd>=0 ){
+- osUnlink(tPath);
+- robust_close(pFile, fd, __LINE__);
++ if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE;
++
++ if( pOrig ){
++ const int szSyspage = unixGetPagesize();
++ i64 nReuse = (pFd->mmapSize & ~(szSyspage-1));
++ u8 *pReq = &pOrig[nReuse];
++
++ /* Unmap any pages of the existing mapping that cannot be reused. */
++ if( nReuse!=nOrig ){
++ osMunmap(pReq, nOrig-nReuse);
+ }
+- fprintf(stderr, "failed to break stale lock on %s, %s\n", cPath, errmsg);
+- }
+- return rc;
+-}
+
+-/* Take the requested lock on the conch file and break a stale lock if the
+-** host id matches.
+-*/
+-static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){
+- proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
+- unixFile *conchFile = pCtx->conchFile;
+- int rc = SQLITE_OK;
+- int nTries = 0;
+- struct timespec conchModTime;
+-
+- memset(&conchModTime, 0, sizeof(conchModTime));
+- do {
+- rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType);
+- nTries ++;
+- if( rc==SQLITE_BUSY ){
+- /* If the lock failed (busy):
+- * 1st try: get the mod time of the conch, wait 0.5s and try again.
+- * 2nd try: fail if the mod time changed or host id is different, wait
+- * 10 sec and try again
+- * 3rd try: break the lock unless the mod time has changed.
+- */
+- struct stat buf;
+- if( osFstat(conchFile->h, &buf) ){
+- pFile->lastErrno = errno;
+- return SQLITE_IOERR_LOCK;
+- }
+-
+- if( nTries==1 ){
+- conchModTime = buf.st_mtimespec;
+- usleep(500000); /* wait 0.5 sec and try the lock again*/
+- continue;
++#if HAVE_MREMAP
++ pNew = osMremap(pOrig, nReuse, nNew, MREMAP_MAYMOVE);
++ zErr = "mremap";
++#else
++ pNew = osMmap(pReq, nNew-nReuse, flags, MAP_SHARED, h, nReuse);
++ if( pNew!=MAP_FAILED ){
++ if( pNew!=pReq ){
++ osMunmap(pNew, nNew - nReuse);
++ pNew = 0;
++ }else{
++ pNew = pOrig;
+ }
++ }
++#endif
+
+- assert( nTries>1 );
+- if( conchModTime.tv_sec != buf.st_mtimespec.tv_sec ||
+- conchModTime.tv_nsec != buf.st_mtimespec.tv_nsec ){
+- return SQLITE_BUSY;
+- }
+-
+- if( nTries==2 ){
+- char tBuf[PROXY_MAXCONCHLEN];
+- int len = osPread(conchFile->h, tBuf, PROXY_MAXCONCHLEN, 0);
+- if( len<0 ){
+- pFile->lastErrno = errno;
+- return SQLITE_IOERR_LOCK;
+- }
+- if( len>PROXY_PATHINDEX && tBuf[0]==(char)PROXY_CONCHVERSION){
+- /* don't break the lock if the host id doesn't match */
+- if( 0!=memcmp(&tBuf[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN) ){
+- return SQLITE_BUSY;
+- }
+- }else{
+- /* don't break the lock on short read or a version mismatch */
+- return SQLITE_BUSY;
+- }
+- usleep(10000000); /* wait 10 sec and try the lock again */
+- continue;
+- }
+-
+- assert( nTries==3 );
+- if( 0==proxyBreakConchLock(pFile, myHostID) ){
+- rc = SQLITE_OK;
+- if( lockType==EXCLUSIVE_LOCK ){
+- rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, SHARED_LOCK);
+- }
+- if( !rc ){
+- rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType);
+- }
+- }
++ /* The attempt to extend the existing mapping failed. Free it. */
++ if( pNew==MAP_FAILED || pNew==0 ){
++ osMunmap(pOrig, nReuse);
+ }
+- } while( rc==SQLITE_BUSY && nTries<3 );
+-
+- return rc;
++ }
++
++ /* If pNew is still NULL, try to create an entirely new mapping. */
++ if( pNew==0 ){
++ pNew = osMmap(0, nNew, flags, MAP_SHARED, h, 0);
++ }
++
++ if( pNew==MAP_FAILED ){
++ pNew = 0;
++ nNew = 0;
++ unixLogError(SQLITE_OK, zErr, pFd->zPath);
++
++ /* If the mmap() above failed, assume that all subsequent mmap() calls
++ ** will probably fail too. Fall back to using xRead/xWrite exclusively
++ ** in this case. */
++ pFd->mmapSizeMax = 0;
++ }
++ pFd->pMapRegion = (void *)pNew;
++ pFd->mmapSize = pFd->mmapSizeActual = nNew;
+ }
++#endif
+
+-/* Takes the conch by taking a shared lock and read the contents conch, if
+-** lockPath is non-NULL, the host ID and lock file path must match. A NULL
+-** lockPath means that the lockPath in the conch file will be used if the
+-** host IDs match, or a new lock path will be generated automatically
+-** and written to the conch file.
++/*
++** 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_LIMIT, 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 int proxyTakeConch(unixFile *pFile){
+- proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
+-
+- if( pCtx->conchHeld!=0 ){
+- return SQLITE_OK;
+- }else{
+- unixFile *conchFile = pCtx->conchFile;
+- uuid_t myHostID;
+- int pError = 0;
+- char readBuf[PROXY_MAXCONCHLEN];
+- char lockPath[MAXPATHLEN];
+- char *tempLockPath = NULL;
+- int rc = SQLITE_OK;
+- int createConch = 0;
+- int hostIdMatch = 0;
+- int readLen = 0;
+- int tryOldLockPath = 0;
+- int forceNewLockPath = 0;
+-
+- OSTRACE(("TAKECONCH %d for %s pid=%d\n", conchFile->h,
+- (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), getpid()));
+-
+- rc = proxyGetHostID(myHostID, &pError);
+- if( (rc&0xff)==SQLITE_IOERR ){
+- pFile->lastErrno = pError;
+- goto end_takeconch;
+- }
+- rc = proxyConchLock(pFile, myHostID, SHARED_LOCK);
++static int unixMapfile(unixFile *pFd, i64 nByte){
++#if SQLITE_MAX_MMAP_SIZE>0
++ i64 nMap = nByte;
++ int rc;
++
++ assert( nMap>=0 || pFd->nFetchOut==0 );
++ if( pFd->nFetchOut>0 ) return SQLITE_OK;
++
++ if( nMap<0 ){
++ struct stat statbuf; /* Low-level file information */
++ rc = osFstat(pFd->h, &statbuf);
+ if( rc!=SQLITE_OK ){
+- goto end_takeconch;
++ return SQLITE_IOERR_FSTAT;
+ }
+- /* read the existing conch file */
+- readLen = seekAndRead((unixFile*)conchFile, 0, readBuf, PROXY_MAXCONCHLEN);
+- if( readLen<0 ){
+- /* I/O error: lastErrno set by seekAndRead */
+- pFile->lastErrno = conchFile->lastErrno;
+- rc = SQLITE_IOERR_READ;
+- goto end_takeconch;
+- }else if( readLen<=(PROXY_HEADERLEN+PROXY_HOSTIDLEN) ||
+- readBuf[0]!=(char)PROXY_CONCHVERSION ){
+- /* a short read or version format mismatch means we need to create a new
+- ** conch file.
+- */
+- createConch = 1;
++ nMap = statbuf.st_size;
++ }
++ if( nMap>pFd->mmapSizeMax ){
++ nMap = pFd->mmapSizeMax;
++ }
++
++ if( nMap!=pFd->mmapSize ){
++ if( nMap>0 ){
++ unixRemapfile(pFd, nMap);
++ }else{
++ unixUnmapfile(pFd);
+ }
+- /* if the host id matches and the lock path already exists in the conch
+- ** we'll try to use the path there, if we can't open that path, we'll
+- ** retry with a new auto-generated path
+- */
+- do { /* in case we need to try again for an :auto: named lock file */
++ }
++#endif
+
+- if( !createConch && !forceNewLockPath ){
+- hostIdMatch = !memcmp(&readBuf[PROXY_HEADERLEN], myHostID,
+- PROXY_HOSTIDLEN);
+- /* if the conch has data compare the contents */
+- if( !pCtx->lockProxyPath ){
+- /* for auto-named local lock file, just check the host ID and we'll
+- ** use the local lock file path that's already in there
+- */
+- if( hostIdMatch ){
+- size_t pathLen = (readLen - PROXY_PATHINDEX);
+-
+- if( pathLen>=MAXPATHLEN ){
+- pathLen=MAXPATHLEN-1;
+- }
+- memcpy(lockPath, &readBuf[PROXY_PATHINDEX], pathLen);
+- lockPath[pathLen] = 0;
+- tempLockPath = lockPath;
+- tryOldLockPath = 1;
+- /* create a copy of the lock path if the conch is taken */
+- goto end_takeconch;
+- }
+- }else if( hostIdMatch
+- && !strncmp(pCtx->lockProxyPath, &readBuf[PROXY_PATHINDEX],
+- readLen-PROXY_PATHINDEX)
+- ){
+- /* conch host and lock path match */
+- goto end_takeconch;
+- }
+- }
+-
+- /* if the conch isn't writable and doesn't match, we can't take it */
+- if( (conchFile->openFlags&O_RDWR) == 0 ){
+- rc = SQLITE_BUSY;
+- goto end_takeconch;
+- }
+-
+- /* either the conch didn't match or we need to create a new one */
+- if( !pCtx->lockProxyPath ){
+- proxyGetLockPath(pCtx->dbPath, lockPath, MAXPATHLEN);
+- tempLockPath = lockPath;
+- /* create a copy of the lock path _only_ if the conch is taken */
+- }
+-
+- /* update conch with host and path (this will fail if other process
+- ** has a shared lock already), if the host id matches, use the big
+- ** stick.
+- */
+- futimes(conchFile->h, NULL);
+- if( hostIdMatch && !createConch ){
+- if( conchFile->pInode && conchFile->pInode->nShared>1 ){
+- /* We are trying for an exclusive lock but another thread in this
+- ** same process is still holding a shared lock. */
+- rc = SQLITE_BUSY;
+- } else {
+- rc = proxyConchLock(pFile, myHostID, EXCLUSIVE_LOCK);
+- }
+- }else{
+- rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, EXCLUSIVE_LOCK);
+- }
+- if( rc==SQLITE_OK ){
+- char writeBuffer[PROXY_MAXCONCHLEN];
+- int writeSize = 0;
+-
+- writeBuffer[0] = (char)PROXY_CONCHVERSION;
+- memcpy(&writeBuffer[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN);
+- if( pCtx->lockProxyPath!=NULL ){
+- strlcpy(&writeBuffer[PROXY_PATHINDEX], pCtx->lockProxyPath, MAXPATHLEN);
+- }else{
+- strlcpy(&writeBuffer[PROXY_PATHINDEX], tempLockPath, MAXPATHLEN);
+- }
+- writeSize = PROXY_PATHINDEX + strlen(&writeBuffer[PROXY_PATHINDEX]);
+- robust_ftruncate(conchFile->h, writeSize);
+- rc = unixWrite((sqlite3_file *)conchFile, writeBuffer, writeSize, 0);
+- fsync(conchFile->h);
+- /* If we created a new conch file (not just updated the contents of a
+- ** valid conch file), try to match the permissions of the database
+- */
+- if( rc==SQLITE_OK && createConch ){
+- struct stat buf;
+- int err = osFstat(pFile->h, &buf);
+- if( err==0 ){
+- mode_t cmode = buf.st_mode&(S_IRUSR|S_IWUSR | S_IRGRP|S_IWGRP |
+- S_IROTH|S_IWOTH);
+- /* try to match the database file R/W permissions, ignore failure */
+-#ifndef SQLITE_PROXY_DEBUG
+- osFchmod(conchFile->h, cmode);
+-#else
+- do{
+- rc = osFchmod(conchFile->h, cmode);
+- }while( rc==(-1) && errno==EINTR );
+- if( rc!=0 ){
+- int code = errno;
+- fprintf(stderr, "fchmod %o FAILED with %d %s\n",
+- cmode, code, strerror(code));
+- } else {
+- fprintf(stderr, "fchmod %o SUCCEDED\n",cmode);
+- }
+- }else{
+- int code = errno;
+- fprintf(stderr, "STAT FAILED[%d] with %d %s\n",
+- err, code, strerror(code));
++ return SQLITE_OK;
++}
++
++/*
++** 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 unixUnfetch().
++*/
++static int unixFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
++#if SQLITE_MAX_MMAP_SIZE>0
++ unixFile *pFd = (unixFile *)fd; /* The underlying database file */
#endif
+- }
+- }
+- }
+- conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, SHARED_LOCK);
+-
+- end_takeconch:
+- OSTRACE(("TRANSPROXY: CLOSE %d\n", pFile->h));
+- if( rc==SQLITE_OK && pFile->openFlags ){
+- int fd;
+- if( pFile->h>=0 ){
+- robust_close(pFile, pFile->h, __LINE__);
+- }
+- pFile->h = -1;
+- fd = robust_open(pCtx->dbPath, pFile->openFlags, 0);
+- OSTRACE(("TRANSPROXY: OPEN %d\n", fd));
+- if( fd>=0 ){
+- pFile->h = fd;
+- }else{
+- rc=SQLITE_CANTOPEN_BKPT; /* SQLITE_BUSY? proxyTakeConch called
+- during locking */
+- }
+- }
+- if( rc==SQLITE_OK && !pCtx->lockProxy ){
+- char *path = tempLockPath ? tempLockPath : pCtx->lockProxyPath;
+- rc = proxyCreateUnixFile(path, &pCtx->lockProxy, 1);
+- if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM && tryOldLockPath ){
+- /* we couldn't create the proxy lock file with the old lock file path
+- ** so try again via auto-naming
+- */
+- forceNewLockPath = 1;
+- tryOldLockPath = 0;
+- continue; /* go back to the do {} while start point, try again */
+- }
+- }
+- if( rc==SQLITE_OK ){
+- /* Need to make a copy of path if we extracted the value
+- ** from the conch file or the path was allocated on the stack
+- */
+- if( tempLockPath ){
+- pCtx->lockProxyPath = sqlite3DbStrDup(0, tempLockPath);
+- if( !pCtx->lockProxyPath ){
+- rc = SQLITE_NOMEM;
+- }
+- }
+- }
+- if( rc==SQLITE_OK ){
+- pCtx->conchHeld = 1;
+-
+- if( pCtx->lockProxy->pMethod == &afpIoMethods ){
+- afpLockingContext *afpCtx;
+- afpCtx = (afpLockingContext *)pCtx->lockProxy->lockingContext;
+- afpCtx->dbPath = pCtx->lockProxyPath;
+- }
+- } else {
+- conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, NO_LOCK);
+- }
+- OSTRACE(("TAKECONCH %d %s\n", conchFile->h,
+- rc==SQLITE_OK?"ok":"failed"));
+- return rc;
+- } while (1); /* in case we need to retry the :auto: lock file -
+- ** we should never get here except via the 'continue' call. */
++ *pp = 0;
++
++#if SQLITE_MAX_MMAP_SIZE>0
++ if( pFd->mmapSizeMax>0 ){
++ if( pFd->pMapRegion==0 ){
++ int rc = unixMapfile(pFd, -1);
++ if( rc!=SQLITE_OK ) return rc;
++ }
++ if( pFd->mmapSize >= iOff+nAmt ){
++ *pp = &((u8 *)pFd->pMapRegion)[iOff];
++ pFd->nFetchOut++;
++ }
+ }
++#endif
++ return SQLITE_OK;
+ }
+
+ /*
+-** If pFile holds a lock on a conch file, then release that lock.
++** If the third argument is non-NULL, then this function releases a
++** reference obtained by an earlier call to unixFetch(). The second
++** argument passed to this function must be the same as the corresponding
++** argument that was passed to the unixFetch() 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 proxyReleaseConch(unixFile *pFile){
+- int rc = SQLITE_OK; /* Subroutine return code */
+- proxyLockingContext *pCtx; /* The locking context for the proxy lock */
+- unixFile *conchFile; /* Name of the conch file */
++static int unixUnfetch(sqlite3_file *fd, i64 iOff, void *p){
++ unixFile *pFd = (unixFile *)fd; /* The underlying database file */
++ UNUSED_PARAMETER(iOff);
+
+- pCtx = (proxyLockingContext *)pFile->lockingContext;
+- conchFile = pCtx->conchFile;
+- OSTRACE(("RELEASECONCH %d for %s pid=%d\n", conchFile->h,
+- (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"),
+- getpid()));
+- if( pCtx->conchHeld>0 ){
+- rc = conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, NO_LOCK);
++ /* 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] );
++
++ if( p ){
++ pFd->nFetchOut--;
++ }else{
++ unixUnmapfile(pFd);
+ }
+- pCtx->conchHeld = 0;
+- OSTRACE(("RELEASECONCH %d %s\n", conchFile->h,
+- (rc==SQLITE_OK ? "ok" : "failed")));
+- return rc;
++
++ assert( pFd->nFetchOut>=0 );
++ return SQLITE_OK;
+ }
+
+ /*
+-** Given the name of a database file, compute the name of its conch file.
+-** Store the conch filename in memory obtained from sqlite3_malloc().
+-** Make *pConchPath point to the new name. Return SQLITE_OK on success
+-** or SQLITE_NOMEM if unable to obtain memory.
++** Here ends the implementation of all sqlite3_file methods.
+ **
+-** The caller is responsible for ensuring that the allocated memory
+-** space is eventually freed.
++********************** End sqlite3_file Methods *******************************
++******************************************************************************/
++
++/*
++** This division contains definitions of sqlite3_io_methods objects that
++** implement various file locking strategies. It also contains definitions
++** of "finder" functions. A finder-function is used to locate the appropriate
++** sqlite3_io_methods object for a particular database file. The pAppData
++** field of the sqlite3_vfs VFS objects are initialized to be pointers to
++** the correct finder-function for that VFS.
+ **
+-** *pConchPath is set to NULL if a memory allocation error occurs.
++** Most finder functions return a pointer to a fixed sqlite3_io_methods
++** object. The only interesting finder-function is autolockIoFinder, which
++** looks at the filesystem type and tries to guess the best locking
++** strategy from that.
++**
++** For finder-funtion F, two objects are created:
++**
++** (1) The real finder-function named "FImpt()".
++**
++** (2) A constant pointer to this function named just "F".
++**
++**
++** A pointer to the F pointer is used as the pAppData value for VFS
++** objects. We have to do this instead of letting pAppData point
++** directly at the finder-function since C90 rules prevent a void*
++** from be cast into a function pointer.
++**
++**
++** Each instance of this macro generates two objects:
++**
++** * A constant sqlite3_io_methods object call METHOD that has locking
++** methods CLOSE, LOCK, UNLOCK, CKRESLOCK.
++**
++** * An I/O method finder function called FINDER that returns a pointer
++** to the METHOD object in the previous bullet.
+ */
+-static int proxyCreateConchPathname(char *dbPath, char **pConchPath){
+- int i; /* Loop counter */
+- int len = (int)strlen(dbPath); /* Length of database filename - dbPath */
+- char *conchPath; /* buffer in which to construct conch name */
++#define IOMETHODS(FINDER, METHOD, VERSION, CLOSE, LOCK, UNLOCK, CKLOCK) \
++static const sqlite3_io_methods METHOD = { \
++ VERSION, /* iVersion */ \
++ CLOSE, /* xClose */ \
++ unixRead, /* xRead */ \
++ unixWrite, /* xWrite */ \
++ unixTruncate, /* xTruncate */ \
++ unixSync, /* xSync */ \
++ unixFileSize, /* xFileSize */ \
++ LOCK, /* xLock */ \
++ UNLOCK, /* xUnlock */ \
++ CKLOCK, /* xCheckReservedLock */ \
++ unixFileControl, /* xFileControl */ \
++ unixSectorSize, /* xSectorSize */ \
++ unixDeviceCharacteristics, /* xDeviceCapabilities */ \
++ unixShmMap, /* xShmMap */ \
++ unixShmLock, /* xShmLock */ \
++ unixShmBarrier, /* xShmBarrier */ \
++ unixShmUnmap, /* xShmUnmap */ \
++ unixFetch, /* xFetch */ \
++ unixUnfetch, /* xUnfetch */ \
++}; \
++static const sqlite3_io_methods *FINDER##Impl(const char *z, unixFile *p){ \
++ UNUSED_PARAMETER(z); UNUSED_PARAMETER(p); \
++ return &METHOD; \
++} \
++static const sqlite3_io_methods *(*const FINDER)(const char*,unixFile *p) \
++ = FINDER##Impl;
+
+- /* 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);
+- if( conchPath==0 ){
+- return SQLITE_NOMEM;
++/*
++** Here are all of the sqlite3_io_methods objects for each of the
++** locking strategies. Functions that return pointers to these methods
++** are also created.
++*/
++IOMETHODS(
++ posixIoFinder, /* Finder function name */
++ posixIoMethods, /* sqlite3_io_methods object name */
++ 3, /* shared memory and mmap are enabled */
++ unixClose, /* xClose method */
++ unixLock, /* xLock method */
++ unixUnlock, /* xUnlock method */
++ unixCheckReservedLock /* xCheckReservedLock method */
++)
++IOMETHODS(
++ nolockIoFinder, /* Finder function name */
++ nolockIoMethods, /* sqlite3_io_methods object name */
++ 1, /* shared memory is disabled */
++ nolockClose, /* xClose method */
++ nolockLock, /* xLock method */
++ nolockUnlock, /* xUnlock method */
++ nolockCheckReservedLock /* xCheckReservedLock method */
++)
++IOMETHODS(
++ dotlockIoFinder, /* Finder function name */
++ dotlockIoMethods, /* sqlite3_io_methods object name */
++ 1, /* shared memory is disabled */
++ dotlockClose, /* xClose method */
++ dotlockLock, /* xLock method */
++ dotlockUnlock, /* xUnlock method */
++ dotlockCheckReservedLock /* xCheckReservedLock method */
++)
++
++#if SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS
++IOMETHODS(
++ flockIoFinder, /* Finder function name */
++ flockIoMethods, /* sqlite3_io_methods object name */
++ 1, /* shared memory is disabled */
++ flockClose, /* xClose method */
++ flockLock, /* xLock method */
++ flockUnlock, /* xUnlock method */
++ flockCheckReservedLock /* xCheckReservedLock method */
++)
++#endif
++
++#if OS_VXWORKS
++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 */
++)
++#endif
++
++#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
++IOMETHODS(
++ afpIoFinder, /* Finder function name */
++ afpIoMethods, /* sqlite3_io_methods object name */
++ 1, /* shared memory is disabled */
++ afpClose, /* xClose method */
++ afpLock, /* xLock method */
++ afpUnlock, /* xUnlock method */
++ afpCheckReservedLock /* xCheckReservedLock method */
++)
++#endif
++
++/*
++** The proxy locking method is a "super-method" in the sense that it
++** opens secondary file descriptors for the conch and lock files and
++** it uses proxy, dot-file, AFP, and flock() locking methods on those
++** secondary files. For this reason, the division that implements
++** proxy locking is located much further down in the file. But we need
++** to go ahead and define the sqlite3_io_methods and finder function
++** for proxy locking here. So we forward declare the I/O methods.
++*/
++#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
++static int proxyClose(sqlite3_file*);
++static int proxyLock(sqlite3_file*, int);
++static int proxyUnlock(sqlite3_file*, int);
++static int proxyCheckReservedLock(sqlite3_file*, int*);
++IOMETHODS(
++ proxyIoFinder, /* Finder function name */
++ proxyIoMethods, /* sqlite3_io_methods object name */
++ 1, /* shared memory is disabled */
++ proxyClose, /* xClose method */
++ proxyLock, /* xLock method */
++ proxyUnlock, /* xUnlock method */
++ proxyCheckReservedLock /* xCheckReservedLock method */
++)
++#endif
++
++/* nfs lockd on OSX 10.3+ doesn't clear write locks when a read lock is set */
++#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
++IOMETHODS(
++ nfsIoFinder, /* Finder function name */
++ nfsIoMethods, /* sqlite3_io_methods object name */
++ 1, /* shared memory is disabled */
++ unixClose, /* xClose method */
++ unixLock, /* xLock method */
++ nfsUnlock, /* xUnlock method */
++ unixCheckReservedLock /* xCheckReservedLock method */
++)
++#endif
++
++#if defined(__APPLE__) && 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 MacOSX only.
++*/
++static const sqlite3_io_methods *autolockIoFinderImpl(
++ const char *filePath, /* name of the database file */
++ unixFile *pNew /* open file object for the database file */
++){
++ static const struct Mapping {
++ const char *zFilesystem; /* Filesystem type name */
++ const sqlite3_io_methods *pMethods; /* Appropriate locking method */
++ } aMap[] = {
++ { "hfs", &posixIoMethods },
++ { "ufs", &posixIoMethods },
++ { "afpfs", &afpIoMethods },
++ { "smbfs", &afpIoMethods },
++ { "webdav", &nolockIoMethods },
++ { 0, 0 }
++ };
++ int i;
++ struct statfs fsInfo;
++ struct flock lockInfo;
++
++ if( !filePath ){
++ /* If filePath==NULL that means we are dealing with a transient file
++ ** that does not need to be locked. */
++ return &nolockIoMethods;
+ }
+- memcpy(conchPath, dbPath, len+1);
+-
+- /* now insert a "." before the last / character */
+- for( i=(len-1); i>=0; i-- ){
+- if( conchPath[i]=='/' ){
+- i++;
+- break;
++ if( statfs(filePath, &fsInfo) != -1 ){
++ if( fsInfo.f_flags & MNT_RDONLY ){
++ return &nolockIoMethods;
++ }
++ for(i=0; aMap[i].zFilesystem; i++){
++ if( strcmp(fsInfo.f_fstypename, aMap[i].zFilesystem)==0 ){
++ return aMap[i].pMethods;
++ }
+ }
+ }
+- conchPath[i]='.';
+- while ( i<len ){
+- conchPath[i+1]=dbPath[i];
+- i++;
+- }
+-
+- /* append the "-conch" suffix to the file */
+- memcpy(&conchPath[i+1], "-conch", 7);
+- assert( (int)strlen(conchPath) == len+7 );
+
+- return SQLITE_OK;
++ /* Default case. Handles, amongst others, "nfs".
++ ** Test byte-range lock using fcntl(). If the call succeeds,
++ ** assume that the file-system supports POSIX style locks.
++ */
++ lockInfo.l_len = 1;
++ lockInfo.l_start = 0;
++ lockInfo.l_whence = SEEK_SET;
++ lockInfo.l_type = F_RDLCK;
++ if( osFcntl(pNew->h, F_GETLK, &lockInfo)!=-1 ) {
++ if( strcmp(fsInfo.f_fstypename, "nfs")==0 ){
++ return &nfsIoMethods;
++ } else {
++ return &posixIoMethods;
++ }
++ }else{
++ return &dotlockIoMethods;
++ }
+ }
++static const sqlite3_io_methods
++ *(*const autolockIoFinder)(const char*,unixFile*) = autolockIoFinderImpl;
+
++#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
+
+-/* Takes a fully configured proxy locking-style unix file and switches
+-** the local lock file path
++#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.
+ */
+-static int switchLockProxyPath(unixFile *pFile, const char *path) {
+- proxyLockingContext *pCtx = (proxyLockingContext*)pFile->lockingContext;
+- char *oldPath = pCtx->lockProxyPath;
+- int rc = SQLITE_OK;
++static const sqlite3_io_methods *autolockIoFinderImpl(
++ const char *filePath, /* name of the database file */
++ unixFile *pNew /* the open file object */
++){
++ struct flock lockInfo;
+
+- if( pFile->eFileLock!=NO_LOCK ){
+- return SQLITE_BUSY;
+- }
++ if( !filePath ){
++ /* If filePath==NULL that means we are dealing with a transient file
++ ** that does not need to be locked. */
++ return &nolockIoMethods;
++ }
+
+- /* nothing to do if the path is NULL, :auto: or matches the existing path */
+- if( !path || path[0]=='\0' || !strcmp(path, ":auto:") ||
+- (oldPath && !strncmp(oldPath, path, MAXPATHLEN)) ){
+- return SQLITE_OK;
++ /* Test if fcntl() is supported and use POSIX style locks.
++ ** Otherwise fall back to the named semaphore method.
++ */
++ lockInfo.l_len = 1;
++ lockInfo.l_start = 0;
++ lockInfo.l_whence = SEEK_SET;
++ lockInfo.l_type = F_RDLCK;
++ if( osFcntl(pNew->h, F_GETLK, &lockInfo)!=-1 ) {
++ return &posixIoMethods;
+ }else{
+- unixFile *lockProxy = pCtx->lockProxy;
+- pCtx->lockProxy=NULL;
+- pCtx->conchHeld = 0;
+- if( lockProxy!=NULL ){
+- rc=lockProxy->pMethod->xClose((sqlite3_file *)lockProxy);
+- if( rc ) return rc;
+- sqlite3_free(lockProxy);
+- }
+- sqlite3_free(oldPath);
+- pCtx->lockProxyPath = sqlite3DbStrDup(0, path);
++ return &semIoMethods;
+ }
+-
+- return rc;
+ }
++static const sqlite3_io_methods
++ *(*const autolockIoFinder)(const char*,unixFile*) = autolockIoFinderImpl;
++
++#endif /* OS_VXWORKS && SQLITE_ENABLE_LOCKING_STYLE */
+
+ /*
+-** pFile is a file that has been opened by a prior xOpen call. dbPath
+-** is a string buffer at least MAXPATHLEN+1 characters in size.
++** An abstract type for a pointer to a IO method finder function:
++*/
++typedef const sqlite3_io_methods *(*finder_type)(const char*,unixFile*);
++
++
++/****************************************************************************
++**************************** sqlite3_vfs methods ****************************
+ **
+-** This routine find the filename associated with pFile and writes it
+-** int dbPath.
++** This division contains the implementation of methods on the
++** sqlite3_vfs object.
+ */
+-static int proxyGetDbPathForUnixFile(unixFile *pFile, char *dbPath){
+-#if defined(__APPLE__)
+- if( pFile->pMethod == &afpIoMethods ){
+- /* 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);
+- } else
+-#endif
+- if( pFile->pMethod == &dotlockIoMethods ){
+- /* dot lock style uses the locking context to store the dot lock
+- ** file path */
+- int len = strlen((char *)pFile->lockingContext) - strlen(DOTLOCK_SUFFIX);
+- memcpy(dbPath, (char *)pFile->lockingContext, len + 1);
+- }else{
+- /* all other styles use the locking context to store the db file path */
+- assert( strlen((char*)pFile->lockingContext)<=MAXPATHLEN );
+- strlcpy(dbPath, (char *)pFile->lockingContext, MAXPATHLEN);
+- }
+- return SQLITE_OK;
+-}
+
+ /*
+-** Takes an already filled in unix file and alters it so all file locking
+-** will be performed on the local proxy lock file. The following fields
+-** are preserved in the locking context so that they can be restored and
+-** the unix structure properly cleaned up at close time:
+-** ->lockingContext
+-** ->pMethod
++** Initialize the contents of the unixFile structure pointed to by pId.
+ */
+-static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
+- proxyLockingContext *pCtx;
+- char dbPath[MAXPATHLEN+1]; /* Name of the database file */
+- char *lockPath=NULL;
++static int fillInUnixFile(
++ sqlite3_vfs *pVfs, /* Pointer to vfs object */
++ int h, /* Open file descriptor of file being opened */
++ sqlite3_file *pId, /* Write to the unixFile structure here */
++ const char *zFilename, /* Name of the file being opened */
++ int ctrlFlags /* Zero or more UNIXFILE_* values */
++){
++ const sqlite3_io_methods *pLockingStyle;
++ unixFile *pNew = (unixFile *)pId;
+ int rc = SQLITE_OK;
+-
+- if( pFile->eFileLock!=NO_LOCK ){
+- return SQLITE_BUSY;
++
++ assert( pNew->pInode==NULL );
++
++ /* Usually the path zFilename should not be a relative pathname. The
++ ** exception is when opening the proxy "conch" file in builds that
++ ** include the special Apple locking styles.
++ */
++#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
++ assert( zFilename==0 || zFilename[0]=='/'
++ || pVfs->pAppData==(void*)&autolockIoFinder );
++#else
++ assert( zFilename==0 || zFilename[0]=='/' );
++#endif
++
++ /* No locking occurs in temporary files */
++ assert( zFilename!=0 || (ctrlFlags & UNIXFILE_NOLOCK)!=0 );
++
++ OSTRACE(("OPEN %-3d %s\n", h, zFilename));
++ pNew->h = h;
++ pNew->pVfs = pVfs;
++ pNew->zPath = zFilename;
++ pNew->ctrlFlags = (u8)ctrlFlags;
++ pNew->mmapSizeMax = sqlite3GlobalConfig.szMmap;
++ if( sqlite3_uri_boolean(((ctrlFlags & UNIXFILE_URI) ? zFilename : 0),
++ "psow", SQLITE_POWERSAFE_OVERWRITE) ){
++ pNew->ctrlFlags |= UNIXFILE_PSOW;
+ }
+- proxyGetDbPathForUnixFile(pFile, dbPath);
+- if( !path || path[0]=='\0' || !strcmp(path, ":auto:") ){
+- lockPath=NULL;
+- }else{
+- lockPath=(char *)path;
++ if( strcmp(pVfs->zName,"unix-excl")==0 ){
++ pNew->ctrlFlags |= UNIXFILE_EXCL;
+ }
+-
+- OSTRACE(("TRANSPROXY %d for %s pid=%d\n", pFile->h,
+- (lockPath ? lockPath : ":auto:"), getpid()));
+
+- pCtx = sqlite3_malloc( sizeof(*pCtx) );
+- if( pCtx==0 ){
+- return SQLITE_NOMEM;
++#if OS_VXWORKS
++ pNew->pId = vxworksFindFileId(zFilename);
++ if( pNew->pId==0 ){
++ ctrlFlags |= UNIXFILE_NOLOCK;
++ rc = SQLITE_NOMEM;
+ }
+- memset(pCtx, 0, sizeof(*pCtx));
++#endif
+
+- rc = proxyCreateConchPathname(dbPath, &pCtx->conchFilePath);
+- if( rc==SQLITE_OK ){
+- rc = proxyCreateUnixFile(pCtx->conchFilePath, &pCtx->conchFile, 0);
+- if( rc==SQLITE_CANTOPEN && ((pFile->openFlags&O_RDWR) == 0) ){
+- /* if (a) the open flags are not O_RDWR, (b) the conch isn't there, and
+- ** (c) the file system is read-only, then enable no-locking access.
+- ** Ugh, since O_RDONLY==0x0000 we test for !O_RDWR since unixOpen asserts
+- ** that openFlags will have only one of O_RDONLY or O_RDWR.
++ if( ctrlFlags & UNIXFILE_NOLOCK ){
++ pLockingStyle = &nolockIoMethods;
++ }else{
++ pLockingStyle = (**(finder_type*)pVfs->pAppData)(zFilename, pNew);
++#if SQLITE_ENABLE_LOCKING_STYLE
++ /* Cache zFilename in the locking context (AFP and dotlock override) for
++ ** proxyLock activation is possible (remote proxy is based on db name)
++ ** zFilename remains valid until file is closed, to support */
++ pNew->lockingContext = (void*)zFilename;
++#endif
++ }
++
++ if( pLockingStyle == &posixIoMethods
++#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
++ || pLockingStyle == &nfsIoMethods
++#endif
++ ){
++ unixEnterMutex();
++ rc = findInodeInfo(pNew, &pNew->pInode);
++ if( rc!=SQLITE_OK ){
++ /* If an error occurred in findInodeInfo(), close the file descriptor
++ ** immediately, before releasing the mutex. findInodeInfo() may fail
++ ** in two scenarios:
++ **
++ ** (a) A call to fstat() failed.
++ ** (b) A malloc failed.
++ **
++ ** Scenario (b) may only occur if the process is holding no other
++ ** file descriptors open on the same file. If there were other file
++ ** descriptors on this file, then no malloc would be required by
++ ** findInodeInfo(). If this is the case, it is quite safe to close
++ ** handle h - as it is guaranteed that no posix locks will be released
++ ** by doing so.
++ **
++ ** If scenario (a) caused the error then things are not so safe. The
++ ** implicit assumption here is that if fstat() fails, things are in
++ ** such bad shape that dropping a lock or two doesn't matter much.
+ */
+- struct statfs fsInfo;
+- struct stat conchInfo;
+- int goLockless = 0;
++ robust_close(pNew, h, __LINE__);
++ h = -1;
++ }
++ unixLeaveMutex();
++ }
+
+- if( osStat(pCtx->conchFilePath, &conchInfo) == -1 ) {
+- int err = errno;
+- if( (err==ENOENT) && (statfs(dbPath, &fsInfo) != -1) ){
+- goLockless = (fsInfo.f_flags&MNT_RDONLY) == MNT_RDONLY;
+- }
+- }
+- if( goLockless ){
+- pCtx->conchHeld = -1; /* read only FS/ lockless */
+- rc = SQLITE_OK;
++#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
++ else if( pLockingStyle == &afpIoMethods ){
++ /* AFP locking uses the file path so it needs to be included in
++ ** the afpLockingContext.
++ */
++ afpLockingContext *pCtx;
++ pNew->lockingContext = pCtx = sqlite3_malloc( sizeof(*pCtx) );
++ if( pCtx==0 ){
++ rc = SQLITE_NOMEM;
++ }else{
++ /* NB: zFilename exists and remains valid until the file is closed
++ ** according to requirement F11141. So we do not need to make a
++ ** copy of the filename. */
++ pCtx->dbPath = zFilename;
++ pCtx->reserved = 0;
++ srandomdev();
++ unixEnterMutex();
++ rc = findInodeInfo(pNew, &pNew->pInode);
++ if( rc!=SQLITE_OK ){
++ sqlite3_free(pNew->lockingContext);
++ robust_close(pNew, h, __LINE__);
++ h = -1;
+ }
++ unixLeaveMutex();
+ }
+- }
+- if( rc==SQLITE_OK && lockPath ){
+- pCtx->lockProxyPath = sqlite3DbStrDup(0, lockPath);
+ }
++#endif
+
+- if( rc==SQLITE_OK ){
+- pCtx->dbPath = sqlite3DbStrDup(0, dbPath);
+- if( pCtx->dbPath==NULL ){
++ else if( pLockingStyle == &dotlockIoMethods ){
++ /* Dotfile locking uses the file path so it needs to be included in
++ ** the dotlockLockingContext
++ */
++ char *zLockFile;
++ int nFilename;
++ assert( zFilename!=0 );
++ nFilename = (int)strlen(zFilename) + 6;
++ zLockFile = (char *)sqlite3_malloc(nFilename);
++ if( zLockFile==0 ){
+ rc = SQLITE_NOMEM;
++ }else{
++ sqlite3_snprintf(nFilename, zLockFile, "%s" DOTLOCK_SUFFIX, zFilename);
+ }
++ pNew->lockingContext = zLockFile;
+ }
+- if( rc==SQLITE_OK ){
+- /* all memory is allocated, proxys are created and assigned,
+- ** switch the locking context and pMethod then return.
++
++#if OS_VXWORKS
++ else if( pLockingStyle == &semIoMethods ){
++ /* Named semaphore locking uses the file path so it needs to be
++ ** included in the semLockingContext
+ */
+- pCtx->oldLockingContext = pFile->lockingContext;
+- pFile->lockingContext = pCtx;
+- pCtx->pOldMethod = pFile->pMethod;
+- pFile->pMethod = &proxyIoMethods;
+- }else{
+- if( pCtx->conchFile ){
+- pCtx->conchFile->pMethod->xClose((sqlite3_file *)pCtx->conchFile);
+- sqlite3_free(pCtx->conchFile);
++ unixEnterMutex();
++ rc = findInodeInfo(pNew, &pNew->pInode);
++ if( (rc==SQLITE_OK) && (pNew->pInode->pSem==NULL) ){
++ char *zSemName = pNew->pInode->aSemName;
++ int n;
++ sqlite3_snprintf(MAX_PATHNAME, zSemName, "/%s.sem",
++ pNew->pId->zCanonicalName);
++ for( n=1; zSemName[n]; n++ )
++ if( zSemName[n]=='/' ) zSemName[n] = '_';
++ pNew->pInode->pSem = sem_open(zSemName, O_CREAT, 0666, 1);
++ if( pNew->pInode->pSem == SEM_FAILED ){
++ rc = SQLITE_NOMEM;
++ pNew->pInode->aSemName[0] = '\0';
++ }
+ }
+- sqlite3DbFree(0, pCtx->lockProxyPath);
+- sqlite3_free(pCtx->conchFilePath);
+- sqlite3_free(pCtx);
++ unixLeaveMutex();
++ }
++#endif
++
++ pNew->lastErrno = 0;
++#if OS_VXWORKS
++ if( rc!=SQLITE_OK ){
++ if( h>=0 ) robust_close(pNew, h, __LINE__);
++ h = -1;
++ osUnlink(zFilename);
++ pNew->ctrlFlags |= UNIXFILE_DELETE;
++ }
++#endif
++ if( rc!=SQLITE_OK ){
++ if( h>=0 ) robust_close(pNew, h, __LINE__);
++ }else{
++ pNew->pMethod = pLockingStyle;
++ OpenCounter(+1);
++ verifyDbFile(pNew);
+ }
+- OSTRACE(("TRANSPROXY %d %s\n", pFile->h,
+- (rc==SQLITE_OK ? "ok" : "failed")));
+ return rc;
+ }
+
++/*
++** Return the name of a directory in which to put temporary files.
++** If no suitable temporary file directory can be found, return NULL.
++*/
++static const char *unixTempFileDir(void){
++ static const char *azDirs[] = {
++ 0,
++ 0,
++ "/var/tmp",
++ "/usr/tmp",
++ "/tmp",
++ 0 /* List terminator */
++ };
++ unsigned int i;
++ struct stat buf;
++ const char *zDir = 0;
++
++ azDirs[0] = sqlite3_temp_directory;
++ if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR");
++ for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); zDir=azDirs[i++]){
++ if( zDir==0 ) continue;
++ if( osStat(zDir, &buf) ) continue;
++ if( !S_ISDIR(buf.st_mode) ) continue;
++ if( osAccess(zDir, 07) ) continue;
++ break;
++ }
++ return zDir;
++}
+
+ /*
+-** This routine handles sqlite3_file_control() calls that are specific
+-** to proxy locking.
++** Create a temporary file name in zBuf. zBuf must be allocated
++** by the calling process and must be big enough to hold at least
++** pVfs->mxPathname bytes.
+ */
+-static int proxyFileControl(sqlite3_file *id, int op, void *pArg){
+- switch( op ){
+- case SQLITE_GET_LOCKPROXYFILE: {
+- unixFile *pFile = (unixFile*)id;
+- if( pFile->pMethod == &proxyIoMethods ){
+- proxyLockingContext *pCtx = (proxyLockingContext*)pFile->lockingContext;
+- proxyTakeConch(pFile);
+- if( pCtx->lockProxyPath ){
+- *(const char **)pArg = pCtx->lockProxyPath;
+- }else{
+- *(const char **)pArg = ":auto: (not held)";
+- }
+- } else {
+- *(const char **)pArg = NULL;
+- }
+- return SQLITE_OK;
++static int unixGetTempname(int nBuf, char *zBuf){
++ static const unsigned char zChars[] =
++ "abcdefghijklmnopqrstuvwxyz"
++ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
++ "0123456789";
++ unsigned int i, j;
++ const char *zDir;
++
++ /* 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 );
++
++ zDir = unixTempFileDir();
++ if( zDir==0 ) zDir = ".";
++
++ /* Check that the output buffer is large enough for the temporary file
++ ** name. If it is not, return SQLITE_ERROR.
++ */
++ if( (strlen(zDir) + strlen(SQLITE_TEMP_FILE_PREFIX) + 18) >= (size_t)nBuf ){
++ return SQLITE_ERROR;
++ }
++
++ do{
++ sqlite3_snprintf(nBuf-18, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX, zDir);
++ j = (int)strlen(zBuf);
++ sqlite3_randomness(15, &zBuf[j]);
++ for(i=0; i<15; i++, j++){
++ zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
+ }
+- case SQLITE_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 */
+- rc = SQLITE_ERROR /*SQLITE_PROTOCOL? SQLITE_MISUSE?*/;
+- }else{
+- /* turn off proxy locking - already off - NOOP */
+- rc = SQLITE_OK;
+- }
+- }else{
+- const char *proxyPath = (const char *)pArg;
+- if( isProxyStyle ){
+- proxyLockingContext *pCtx =
+- (proxyLockingContext*)pFile->lockingContext;
+- if( !strcmp(pArg, ":auto:")
+- || (pCtx->lockProxyPath &&
+- !strncmp(pCtx->lockProxyPath, proxyPath, MAXPATHLEN))
+- ){
+- rc = SQLITE_OK;
+- }else{
+- rc = switchLockProxyPath(pFile, proxyPath);
+- }
+- }else{
+- /* turn on proxy file locking */
+- rc = proxyTransformUnixFile(pFile, proxyPath);
+- }
+- }
+- return rc;
++ zBuf[j] = 0;
++ zBuf[j+1] = 0;
++ }while( osAccess(zBuf,0)==0 );
++ return SQLITE_OK;
++}
++
++#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
++/*
++** Routine to transform a unixFile into a proxy-locking unixFile.
++** Implementation in the proxy-lock division, but used by unixOpen()
++** if SQLITE_PREFER_PROXY_LOCKING is defined.
++*/
++static int proxyTransformUnixFile(unixFile*, const char*);
++#endif
++
++/*
++** Search for an unused file descriptor that was opened on the database
++** file (not a journal or master-journal file) identified by pathname
++** zPath with SQLITE_OPEN_XXX flags matching those passed as the second
++** argument to this function.
++**
++** Such a file descriptor may exist if a database connection was closed
++** but the associated file descriptor could not be closed because some
++** other file descriptor open on the same file is holding a file-lock.
++** Refer to comments in the unixClose() function and the lengthy comment
++** describing "Posix Advisory Locking" at the start of this file for
++** further details. Also, ticket #4018.
++**
++** If a suitable file descriptor is found, then it is returned. If no
++** such file descriptor is located, -1 is returned.
++*/
++static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
++ UnixUnusedFd *pUnused = 0;
++
++ /* Do not search for an unused file descriptor on vxworks. Not because
++ ** vxworks would not benefit from the change (it might, we're not sure),
++ ** but because no way to test it is currently available. It is better
++ ** not to risk breaking vxworks support for the sake of such an obscure
++ ** feature. */
++#if !OS_VXWORKS
++ struct stat sStat; /* Results of stat() call */
++
++ /* A stat() call may fail for various reasons. If this happens, it is
++ ** almost certain that an open() call on the same path will also fail.
++ ** For this reason, if an error occurs in the stat() call here, it is
++ ** ignored and -1 is returned. The caller will try to open a new file
++ ** 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. */
++ if( 0==osStat(zPath, &sStat) ){
++ unixInodeInfo *pInode;
++
++ unixEnterMutex();
++ pInode = inodeList;
++ while( pInode && (pInode->fileId.dev!=sStat.st_dev
++ || pInode->fileId.ino!=sStat.st_ino) ){
++ pInode = pInode->pNext;
+ }
+- default: {
+- assert( 0 ); /* The call assures that only valid opcodes are sent */
++ if( pInode ){
++ UnixUnusedFd **pp;
++ for(pp=&pInode->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext));
++ pUnused = *pp;
++ if( pUnused ){
++ *pp = pUnused->pNext;
++ }
+ }
++ unixLeaveMutex();
+ }
+- /*NOTREACHED*/
+- return SQLITE_ERROR;
++#endif /* if !OS_VXWORKS */
++ return pUnused;
+ }
+ /*
+-** Within this division (the proxying locking implementation) the procedures
+-** above this point are all utilities. The lock-related methods of the
+-** proxy-locking sqlite3_io_method object follow.
++** This function is called by unixOpen() to determine the unix permissions
++** to create new files with. If no error occurs, then SQLITE_OK is returned
++** and a value suitable for passing as the third argument to open(2) is
++** 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
++** 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
++** this function queries the file-system for the permissions on the
++** corresponding database file and sets *pMode to this value. Whenever
++** possible, WAL and journal files are created using the same permissions
++** as the associated database file.
++**
++** If the SQLITE_ENABLE_8_3_NAMES option is enabled, then the
++** original filename is unavailable. But 8_3_NAMES is only used for
++** FAT filesystems and permissions do not matter there, so just use
++** the default permissions.
+ */
++static int findCreateFileMode(
++ const char *zPath, /* Path of file (possibly) being created */
++ int flags, /* Flags passed as 4th argument to xOpen() */
++ mode_t *pMode, /* OUT: Permissions to open file with */
++ uid_t *pUid, /* OUT: uid to set on the file */
++ gid_t *pGid /* OUT: gid to set on the file */
++){
++ int rc = SQLITE_OK; /* Return Code */
++ *pMode = 0;
++ *pUid = 0;
++ *pGid = 0;
++ if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){
++ char zDb[MAX_PATHNAME+1]; /* Database file path */
++ int nDb; /* Number of valid bytes in zDb */
++ struct stat sStat; /* Output of stat() on database file */
-@@ -43883,6 +46197,38 @@
++ /* zPath is a path to a WAL or journal file. The following block derives
++ ** the path to the associated database file from zPath. This block handles
++ ** the following naming conventions:
++ **
++ ** "<path to db>-journal"
++ ** "<path to db>-wal"
++ ** "<path to db>-journalNN"
++ ** "<path to db>-walNN"
++ **
++ ** where NN is a decimal number. The NN naming schemes are
++ ** used by the test_multiplex.c module.
++ */
++ nDb = sqlite3Strlen30(zPath) - 1;
++#ifdef SQLITE_ENABLE_8_3_NAMES
++ while( nDb>0 && sqlite3Isalnum(zPath[nDb]) ) nDb--;
++ if( nDb==0 || zPath[nDb]!='-' ) return SQLITE_OK;
++#else
++ while( zPath[nDb]!='-' ){
++ assert( nDb>0 );
++ assert( zPath[nDb]!='\n' );
++ nDb--;
++ }
++#endif
++ memcpy(zDb, zPath, nDb);
++ zDb[nDb] = '\0';
- #endif /* SQLITE_OMIT_DISKIO */
+-/*
+-** 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, set *pResOut
+-** 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 proxyCheckReservedLock(sqlite3_file *id, int *pResOut) {
+- unixFile *pFile = (unixFile*)id;
+- int rc = proxyTakeConch(pFile);
+- if( rc==SQLITE_OK ){
+- proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
+- if( pCtx->conchHeld>0 ){
+- unixFile *proxy = pCtx->lockProxy;
+- return proxy->pMethod->xCheckReservedLock((sqlite3_file*)proxy, pResOut);
+- }else{ /* conchHeld < 0 is lockless */
+- pResOut=0;
++ if( 0==osStat(zDb, &sStat) ){
++ *pMode = sStat.st_mode & 0777;
++ *pUid = sStat.st_uid;
++ *pGid = sStat.st_gid;
++ }else{
++ rc = SQLITE_IOERR_FSTAT;
+ }
++ }else if( flags & SQLITE_OPEN_DELETEONCLOSE ){
++ *pMode = 0600;
+ }
+ return rc;
+ }
+
+ /*
+-** Lock the file with the lock specified by parameter eFileLock - one
+-** of the following:
++** Open the file zPath.
++**
++** Previously, the SQLite OS layer used three functions in place of this
++** one:
+ **
+-** (1) SHARED_LOCK
+-** (2) RESERVED_LOCK
+-** (3) PENDING_LOCK
+-** (4) EXCLUSIVE_LOCK
++** sqlite3OsOpenReadWrite();
++** sqlite3OsOpenReadOnly();
++** sqlite3OsOpenExclusive();
+ **
+-** 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:
++** These calls correspond to the following combinations of flags:
+ **
+-** UNLOCKED -> SHARED
+-** SHARED -> RESERVED
+-** SHARED -> (PENDING) -> EXCLUSIVE
+-** RESERVED -> (PENDING) -> EXCLUSIVE
+-** PENDING -> EXCLUSIVE
++** ReadWrite() -> (READWRITE | CREATE)
++** ReadOnly() -> (READONLY)
++** OpenExclusive() -> (READWRITE | CREATE | EXCLUSIVE)
+ **
+-** This routine will only increase a lock. Use the sqlite3OsUnlock()
+-** routine to lower a locking level.
++** The old OpenExclusive() accepted a boolean argument - "delFlag". If
++** true, the file was configured to be automatically deleted when the
++** file handle closed. To achieve the same effect using this new
++** interface, add the DELETEONCLOSE flag to those specified above for
++** OpenExclusive().
+ */
+-static int proxyLock(sqlite3_file *id, int eFileLock) {
+- unixFile *pFile = (unixFile*)id;
+- int rc = proxyTakeConch(pFile);
+- if( rc==SQLITE_OK ){
+- proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
+- if( pCtx->conchHeld>0 ){
+- unixFile *proxy = pCtx->lockProxy;
+- rc = proxy->pMethod->xLock((sqlite3_file*)proxy, eFileLock);
+- pFile->eFileLock = proxy->eFileLock;
+- }else{
+- /* conchHeld < 0 is lockless */
+- }
+- }
+- return rc;
+-}
++static int unixOpen(
++ sqlite3_vfs *pVfs, /* The VFS for which this is the xOpen method */
++ const char *zPath, /* Pathname of file to be opened */
++ sqlite3_file *pFile, /* The file descriptor to be filled in */
++ int flags, /* Input flags to control the opening */
++ int *pOutFlags /* Output flags returned to SQLite core */
++){
++ unixFile *p = (unixFile *)pFile;
++ int fd = -1; /* File descriptor returned by open() */
++ int openFlags = 0; /* Flags to pass to open() */
++ int eType = flags&0xFFFFFF00; /* Type of file to open */
++ int noLock; /* True to omit locking primitives */
++ int rc = SQLITE_OK; /* Function Return Code */
++ int ctrlFlags = 0; /* UNIXFILE_* flags */
-+/* BEGIN CRYPTO */
++ 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 SQLITE_ENABLE_LOCKING_STYLE
++ int isAutoProxy = (flags & SQLITE_OPEN_AUTOPROXY);
++#endif
++#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
++ struct statfs fsInfo;
++#endif
+
+-/*
+-** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
+-** 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.
+-*/
+-static int proxyUnlock(sqlite3_file *id, int eFileLock) {
+- unixFile *pFile = (unixFile*)id;
+- int rc = proxyTakeConch(pFile);
+- if( rc==SQLITE_OK ){
+- proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
+- if( pCtx->conchHeld>0 ){
+- unixFile *proxy = pCtx->lockProxy;
+- rc = proxy->pMethod->xUnlock((sqlite3_file*)proxy, eFileLock);
+- pFile->eFileLock = proxy->eFileLock;
++ /* If creating a master or main-file journal, this function will open
++ ** a file-descriptor on the directory too. The first time unixSync()
++ ** is called the directory file descriptor will be fsync()ed and close()d.
++ */
++ int syncDir = (isCreate && (
++ eType==SQLITE_OPEN_MASTER_JOURNAL
++ || eType==SQLITE_OPEN_MAIN_JOURNAL
++ || eType==SQLITE_OPEN_WAL
++ ));
++
++ /* 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[MAX_PATHNAME+2];
++ const char *zName = zPath;
++
++ /* 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
++ );
++
++ memset(p, 0, sizeof(unixFile));
++
++ if( eType==SQLITE_OPEN_MAIN_DB ){
++ UnixUnusedFd *pUnused;
++ pUnused = findReusableFd(zName, flags);
++ if( pUnused ){
++ fd = pUnused->fd;
+ }else{
+- /* conchHeld < 0 is lockless */
++ pUnused = sqlite3_malloc(sizeof(*pUnused));
++ if( !pUnused ){
++ return SQLITE_NOMEM;
++ }
+ }
+- }
+- return rc;
+-}
++ p->pUnused = pUnused;
+
+-/*
+-** Close a file that uses proxy locks.
+-*/
+-static int proxyClose(sqlite3_file *id) {
+- if( id ){
+- unixFile *pFile = (unixFile*)id;
+- proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
+- unixFile *lockProxy = pCtx->lockProxy;
+- unixFile *conchFile = pCtx->conchFile;
+- int rc = SQLITE_OK;
+-
+- if( lockProxy ){
+- rc = lockProxy->pMethod->xUnlock((sqlite3_file*)lockProxy, NO_LOCK);
+- if( rc ) return rc;
+- rc = lockProxy->pMethod->xClose((sqlite3_file*)lockProxy);
+- if( rc ) return rc;
+- sqlite3_free(lockProxy);
+- pCtx->lockProxy = 0;
+- }
+- if( conchFile ){
+- if( pCtx->conchHeld ){
+- rc = proxyReleaseConch(pFile);
+- if( rc ) return rc;
+- }
+- rc = conchFile->pMethod->xClose((sqlite3_file*)conchFile);
+- if( rc ) return rc;
+- sqlite3_free(conchFile);
++ /* Database filenames are double-zero terminated if they are not
++ ** URIs with parameters. Hence, they can always be passed into
++ ** sqlite3_uri_parameter(). */
++ assert( (flags & SQLITE_OPEN_URI) || zName[strlen(zName)+1]==0 );
++
++ }else if( !zName ){
++ /* If zName is NULL, the upper layer is requesting a temp file. */
++ assert(isDelete && !syncDir);
++ rc = unixGetTempname(MAX_PATHNAME+2, zTmpname);
++ if( rc!=SQLITE_OK ){
++ return rc;
+ }
+- sqlite3DbFree(0, pCtx->lockProxyPath);
+- sqlite3_free(pCtx->conchFilePath);
+- sqlite3DbFree(0, pCtx->dbPath);
+- /* restore the original locking context and pMethod then close it */
+- pFile->lockingContext = pCtx->oldLockingContext;
+- pFile->pMethod = pCtx->pOldMethod;
+- sqlite3_free(pCtx);
+- return pFile->pMethod->xClose(id);
++ zName = zTmpname;
++
++ /* Generated temporary filenames are always double-zero terminated
++ ** for use by sqlite3_uri_parameter(). */
++ assert( zName[strlen(zName)+1]==0 );
+ }
+- return SQLITE_OK;
+-}
+
++ /* Determine the value of the flags parameter passed to POSIX function
++ ** open(). These must be calculated even if open() is not called, as
++ ** they may be stored as part of the file handle and used by the
++ ** 'conch file' locking functions later on. */
++ if( isReadonly ) openFlags |= O_RDONLY;
++ if( isReadWrite ) openFlags |= O_RDWR;
++ if( isCreate ) openFlags |= O_CREAT;
++ if( isExclusive ) openFlags |= (O_EXCL|O_NOFOLLOW);
++ openFlags |= (O_LARGEFILE|O_BINARY);
+
++ if( fd<0 ){
++ mode_t openMode; /* Permissions to create file with */
++ uid_t uid; /* Userid for the file */
++ gid_t gid; /* Groupid for the file */
++ rc = findCreateFileMode(zName, flags, &openMode, &uid, &gid);
++ if( rc!=SQLITE_OK ){
++ assert( !p->pUnused );
++ assert( eType==SQLITE_OPEN_WAL || eType==SQLITE_OPEN_MAIN_JOURNAL );
++ return rc;
++ }
++ fd = robust_open(zName, openFlags, openMode);
++ OSTRACE(("OPENX %-3d %s 0%o\n", fd, zName, openFlags));
++ if( fd<0 && errno!=EISDIR && isReadWrite && !isExclusive ){
++ /* Failed to open the file for read/write access. Try read-only. */
++ flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
++ openFlags &= ~(O_RDWR|O_CREAT);
++ flags |= SQLITE_OPEN_READONLY;
++ openFlags |= O_RDONLY;
++ isReadonly = 1;
++ fd = robust_open(zName, openFlags, openMode);
++ }
++ if( fd<0 ){
++ rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
++ goto open_finished;
++ }
+
+-#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
+-/*
+-** The proxy locking style is intended for use with AFP filesystems.
+-** And since AFP is only supported on MacOSX, the proxy locking is also
+-** restricted to MacOSX.
+-**
+-**
+-******************* End of the proxy lock implementation **********************
+-******************************************************************************/
++ /* If this process is running as root and if creating a new rollback
++ ** journal or WAL file, set the ownership of the journal or WAL to be
++ ** the same as the original database.
++ */
++ if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){
++ osFchown(fd, uid, gid);
++ }
++ }
++ assert( fd>=0 );
++ if( pOutFlags ){
++ *pOutFlags = flags;
++ }
+
+-/*
+-** Initialize the operating system interface.
+-**
+-** This routine registers all VFS implementations for unix-like operating
+-** systems. This routine, and the sqlite3_os_end() routine that follows,
+-** should be the only routines in this file that are visible from other
+-** files.
+-**
+-** This routine is called once during SQLite initialization and by a
+-** single thread. The memory allocation and mutex subsystems have not
+-** necessarily been initialized when this routine is called, and so they
+-** should not be used.
+-*/
+-SQLITE_API int 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
+- ** to the "finder" function. (pAppData is a pointer to a pointer because
+- ** silly C90 rules prohibit a void* from being cast to a function pointer
+- ** and so we have to go through the intermediate pointer to avoid problems
+- ** when compiling with -pedantic-errors on GCC.)
+- **
+- ** The FINDER parameter to this macro is the name of the pointer to the
+- ** finder-function. The finder-function returns a pointer to the
+- ** sqlite_io_methods object that implements the desired locking
+- ** behaviors. See the division above that contains the IOMETHODS
+- ** macro for addition information on finder-functions.
+- **
+- ** Most finders simply return a pointer to a fixed sqlite3_io_methods
+- ** object. But the "autolockIoFinder" available on MacOSX does a little
+- ** more than that; it looks at the filesystem type that hosts the
+- ** database file and tries to choose an locking method appropriate for
+- ** that filesystem time.
+- */
+- #define UNIXVFS(VFSNAME, FINDER) { \
+- 3, /* iVersion */ \
+- sizeof(unixFile), /* szOsFile */ \
+- MAX_PATHNAME, /* mxPathname */ \
+- 0, /* pNext */ \
+- VFSNAME, /* zName */ \
+- (void*)&FINDER, /* pAppData */ \
+- unixOpen, /* xOpen */ \
+- unixDelete, /* xDelete */ \
+- unixAccess, /* xAccess */ \
+- unixFullPathname, /* xFullPathname */ \
+- unixDlOpen, /* xDlOpen */ \
+- unixDlError, /* xDlError */ \
+- unixDlSym, /* xDlSym */ \
+- unixDlClose, /* xDlClose */ \
+- unixRandomness, /* xRandomness */ \
+- unixSleep, /* xSleep */ \
+- unixCurrentTime, /* xCurrentTime */ \
+- unixGetLastError, /* xGetLastError */ \
+- unixCurrentTimeInt64, /* xCurrentTimeInt64 */ \
+- unixSetSystemCall, /* xSetSystemCall */ \
+- unixGetSystemCall, /* xGetSystemCall */ \
+- unixNextSystemCall, /* xNextSystemCall */ \
++ if( p->pUnused ){
++ p->pUnused->fd = fd;
++ p->pUnused->flags = flags;
+ }
+
+- /*
+- ** All default VFSes for unix are contained in the following array.
+- **
+- ** Note that the sqlite3_vfs.pNext field of the VFS object is modified
+- ** by the SQLite core when the VFS is registered. So the following
+- ** array cannot be const.
+- */
+- static sqlite3_vfs aVfs[] = {
+-#if SQLITE_ENABLE_LOCKING_STYLE && (OS_VXWORKS || defined(__APPLE__))
+- UNIXVFS("unix", autolockIoFinder ),
+-#else
+- UNIXVFS("unix", posixIoFinder ),
+-#endif
+- UNIXVFS("unix-none", nolockIoFinder ),
+- UNIXVFS("unix-dotfile", dotlockIoFinder ),
+- UNIXVFS("unix-excl", posixIoFinder ),
++ if( isDelete ){
+ #if OS_VXWORKS
+- UNIXVFS("unix-namedsem", semIoFinder ),
++ zPath = zName;
++#else
++ osUnlink(zName);
+ #endif
++ }
+ #if SQLITE_ENABLE_LOCKING_STYLE
+- UNIXVFS("unix-posix", posixIoFinder ),
+-#if !OS_VXWORKS
+- UNIXVFS("unix-flock", flockIoFinder ),
++ else{
++ p->openFlags = openFlags;
++ }
++#endif
++
++ noLock = eType!=SQLITE_OPEN_MAIN_DB;
++
++
++#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
++ if( fstatfs(fd, &fsInfo) == -1 ){
++ ((unixFile*)pFile)->lastErrno = 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;
++ }
+ #endif
++
++ /* Set up appropriate ctrlFlags */
++ if( isDelete ) ctrlFlags |= UNIXFILE_DELETE;
++ if( isReadonly ) ctrlFlags |= UNIXFILE_RDONLY;
++ if( noLock ) ctrlFlags |= UNIXFILE_NOLOCK;
++ if( syncDir ) ctrlFlags |= UNIXFILE_DIRSYNC;
++ if( flags & SQLITE_OPEN_URI ) ctrlFlags |= UNIXFILE_URI;
++
++#if SQLITE_ENABLE_LOCKING_STYLE
++#if SQLITE_PREFER_PROXY_LOCKING
++ isAutoProxy = 1;
+ #endif
+-#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
+- UNIXVFS("unix-afp", afpIoFinder ),
+- UNIXVFS("unix-nfs", nfsIoFinder ),
+- UNIXVFS("unix-proxy", proxyIoFinder ),
++ if( isAutoProxy && (zPath!=NULL) && (!noLock) && pVfs->xOpen ){
++ char *envforce = getenv("SQLITE_FORCE_PROXY_LOCKING");
++ int useProxy = 0;
++
++ /* SQLITE_FORCE_PROXY_LOCKING==1 means force always use proxy, 0 means
++ ** never use proxy, NULL means use proxy for non-local files only. */
++ 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 ){
++ rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
++ if( rc==SQLITE_OK ){
++ rc = proxyTransformUnixFile((unixFile*)pFile, ":auto:");
++ if( rc!=SQLITE_OK ){
++ /* Use unixClose to clean up the resources added in fillInUnixFile
++ ** and clear all the structure's references. Specifically,
++ ** pFile->pMethods will be NULL so sqlite3OsClose will be a no-op
++ */
++ unixClose(pFile);
++ return rc;
++ }
++ }
++ goto open_finished;
++ }
++ }
+ #endif
+- };
+- unsigned int i; /* Loop counter */
+-
+- /* Double-check that the aSyscall[] array has been constructed
+- ** correctly. See ticket [bb3a86e890c8e96ab] */
+- assert( ArraySize(aSyscall)==24 );
++
++ rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
+
+- /* Register all VFSes defined in the aVfs[] array */
+- for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
+- sqlite3_vfs_register(&aVfs[i], i==0);
++open_finished:
++ if( rc!=SQLITE_OK ){
++ sqlite3_free(p->pUnused);
+ }
+- return SQLITE_OK;
+-}
+-
+-/*
+-** Shutdown the operating system interface.
+-**
+-** Some operating systems might need to do some cleanup in this routine,
+-** to release dynamically allocated objects. But not on unix.
+-** This routine is a no-op for unix.
+-*/
+-SQLITE_API int sqlite3_os_end(void){
+- return SQLITE_OK;
++ return rc;
+ }
+-
+-#endif /* SQLITE_OS_UNIX */
+
+-/************** End of os_unix.c *********************************************/
+-/************** Begin file os_win.c ******************************************/
+-/*
+-** 2004 May 22
+-**
+-** 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 Windows.
+-*/
+-#if SQLITE_OS_WIN /* This file is used for Windows only */
+-
+-#ifdef __CYGWIN__
+-# include <sys/cygwin.h>
+-#endif
+-
+-/*
+-** Include code that is common to all os_*.c files
+-*/
+-/************** Include os_common.h in the middle of os_win.c ****************/
+-/************** Begin file os_common.h ***************************************/
+-/*
+-** 2004 May 22
+-**
+-** 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 macros and a little bit of code that is common to
+-** all of the platform-specific files (os_*.c) and is #included into those
+-** files.
+-**
+-** This file should be #included by the os_*.c files only. It is not a
+-** general purpose header file.
+-*/
+-#ifndef _OS_COMMON_H_
+-#define _OS_COMMON_H_
+
+ /*
+-** At least two bugs have slipped in because we changed the MEMORY_DEBUG
+-** macro to SQLITE_DEBUG and some older makefiles have not yet made the
+-** switch. The following code should catch this problem at compile-time.
++** Delete the file at zPath. If the dirSync argument is true, fsync()
++** the directory after deleting the file.
+ */
+-#ifdef MEMORY_DEBUG
+-# 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
++static int unixDelete(
++ sqlite3_vfs *NotUsed, /* VFS containing this as the xDelete method */
++ const char *zPath, /* Name of file to be deleted */
++ int dirSync /* If true, fsync() directory after deleting file */
++){
++ int rc = SQLITE_OK;
++ UNUSED_PARAMETER(NotUsed);
++ SimulateIOError(return SQLITE_IOERR_DELETE);
++ if( osUnlink(zPath)==(-1) ){
++ if( errno==ENOENT ){
++ rc = SQLITE_IOERR_DELETE_NOENT;
++ }else{
++ rc = unixLogError(SQLITE_IOERR_DELETE, "unlink", zPath);
++ }
++ return rc;
++ }
++#ifndef SQLITE_DISABLE_DIRSYNC
++ if( (dirSync & 1)!=0 ){
++ int fd;
++ rc = osOpenDirectory(zPath, &fd);
++ if( rc==SQLITE_OK ){
++#if OS_VXWORKS
++ if( fsync(fd)==-1 )
+ #else
+-# define OSTRACE(X)
++ if( fsync(fd) )
+ #endif
++ {
++ rc = unixLogError(SQLITE_IOERR_DIR_FSYNC, "fsync", zPath);
++ }
++ robust_close(0, fd, __LINE__);
++ }else if( rc==SQLITE_CANTOPEN ){
++ rc = SQLITE_OK;
++ }
++ }
++#endif
++ return rc;
++}
+
+ /*
+-** Macros for performance tracing. Normally turned off. Only works
+-** on i486 hardware.
+-*/
+-#ifdef SQLITE_PERFORMANCE_TRACE
+-
+-/*
+-** hwtime.h contains inline assembler code for implementing
+-** high-performance timing routines.
+-*/
+-/************** Include hwtime.h in the middle of os_common.h ****************/
+-/************** Begin file hwtime.h ******************************************/
+-/*
+-** 2008 May 27
+-**
+-** The author disclaims copyright to this source code. In place of
+-** a legal notice, here is a blessing:
+-**
+-** May you do good and not evil.
+-** May you find forgiveness for yourself and forgive others.
+-** May you share freely, never taking more than you give.
++** Test the existence of or access permissions of file zPath. The
++** test performed depends on the value of flags:
+ **
+-******************************************************************************
++** SQLITE_ACCESS_EXISTS: Return 1 if the file exists
++** SQLITE_ACCESS_READWRITE: Return 1 if the file is read and writable.
++** SQLITE_ACCESS_READONLY: Return 1 if the file is readable.
+ **
+-** This file contains inline asm code for retrieving "high-performance"
+-** counters for x86 class CPUs.
+-*/
+-#ifndef _HWTIME_H_
+-#define _HWTIME_H_
+-
+-/*
+-** The following routine only works on pentium-class (or newer) processors.
+-** It uses the RDTSC opcode to read the cycle count value out of the
+-** processor and returns that value. This can be used for high-res
+-** profiling.
++** Otherwise return 0.
+ */
+-#if (defined(__GNUC__) || defined(_MSC_VER)) && \
+- (defined(i386) || defined(__i386__) || defined(_M_IX86))
+-
+- #if defined(__GNUC__)
+-
+- __inline__ sqlite_uint64 sqlite3Hwtime(void){
+- unsigned int lo, hi;
+- __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
+- return (sqlite_uint64)hi << 32 | lo;
+- }
+-
+- #elif defined(_MSC_VER)
+-
+- __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){
+- __asm {
+- rdtsc
+- ret ; return value at EDX:EAX
+- }
+- }
+-
+- #endif
+-
+-#elif (defined(__GNUC__) && defined(__x86_64__))
++static int unixAccess(
++ sqlite3_vfs *NotUsed, /* The VFS containing this xAccess method */
++ const char *zPath, /* Path of the file to examine */
++ int flags, /* What do we want to learn about the zPath file? */
++ int *pResOut /* Write result boolean here */
++){
++ int amode = 0;
++ UNUSED_PARAMETER(NotUsed);
++ SimulateIOError( return SQLITE_IOERR_ACCESS; );
++ switch( flags ){
++ case SQLITE_ACCESS_EXISTS:
++ amode = F_OK;
++ break;
++ case SQLITE_ACCESS_READWRITE:
++ amode = W_OK|R_OK;
++ break;
++ case SQLITE_ACCESS_READ:
++ amode = R_OK;
++ break;
+
+- __inline__ sqlite_uint64 sqlite3Hwtime(void){
+- unsigned long val;
+- __asm__ __volatile__ ("rdtsc" : "=A" (val));
+- return val;
++ default:
++ assert(!"Invalid flags argument");
+ }
+-
+-#elif (defined(__GNUC__) && defined(__ppc__))
+-
+- __inline__ sqlite_uint64 sqlite3Hwtime(void){
+- unsigned long long retval;
+- unsigned long junk;
+- __asm__ __volatile__ ("\n\
+- 1: mftbu %1\n\
+- mftb %L0\n\
+- mftbu %0\n\
+- cmpw %0,%1\n\
+- bne 1b"
+- : "=r" (retval), "=r" (junk));
+- return retval;
++ *pResOut = (osAccess(zPath, amode)==0);
++ if( flags==SQLITE_ACCESS_EXISTS && *pResOut ){
++ struct stat buf;
++ if( 0==osStat(zPath, &buf) && buf.st_size==0 ){
++ *pResOut = 0;
++ }
+ }
++ return SQLITE_OK;
++}
+
+-#else
+
+- #error Need implementation of sqlite3Hwtime() for your platform.
++/*
++** Turn a relative pathname into a full pathname. The relative path
++** is stored as a nul-terminated string in the buffer pointed to by
++** zPath.
++**
++** zOut points to a buffer of at least sqlite3_vfs.mxPathname bytes
++** (in this case, MAX_PATHNAME bytes). The full-path is written to
++** this buffer before returning.
++*/
++static int unixFullPathname(
++ sqlite3_vfs *pVfs, /* Pointer to vfs object */
++ const char *zPath, /* Possibly relative input path */
++ int nOut, /* Size of output buffer in bytes */
++ char *zOut /* Output buffer */
++){
+
+- /*
+- ** To compile without implementing sqlite3Hwtime() for your platform,
+- ** you can remove the above #error and use the following
+- ** stub function. You will lose timing support for many
+- ** of the debugging and testing utilities, but it should at
+- ** least compile and run.
++ /* 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.
+ */
+-SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
+-
+-#endif
++ SimulateIOError( return SQLITE_ERROR );
+
+-#endif /* !defined(_HWTIME_H_) */
++ assert( pVfs->mxPathname==MAX_PATHNAME );
++ UNUSED_PARAMETER(pVfs);
+
+-/************** End of hwtime.h **********************************************/
+-/************** Continuing where we left off in os_common.h ******************/
++ zOut[nOut-1] = '\0';
++ if( zPath[0]=='/' ){
++ sqlite3_snprintf(nOut, zOut, "%s", zPath);
++ }else{
++ int nCwd;
++ if( osGetcwd(zOut, nOut-1)==0 ){
++ return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath);
++ }
++ nCwd = (int)strlen(zOut);
++ sqlite3_snprintf(nOut-nCwd, &zOut[nCwd], "/%s", zPath);
++ }
++ return SQLITE_OK;
++}
+
+-static sqlite_uint64 g_start;
+-static sqlite_uint64 g_elapsed;
+-#define TIMER_START g_start=sqlite3Hwtime()
+-#define TIMER_END g_elapsed=sqlite3Hwtime()-g_start
+-#define TIMER_ELAPSED g_elapsed
+-#else
+-#define TIMER_START
+-#define TIMER_END
+-#define TIMER_ELAPSED ((sqlite_uint64)0)
+-#endif
+
++#ifndef SQLITE_OMIT_LOAD_EXTENSION
+ /*
+-** If we compile with the SQLITE_TEST macro set, then the following block
+-** of code will give us the ability to simulate a disk I/O error. This
+-** is used for testing the I/O recovery logic.
++** Interfaces for opening a shared library, finding entry points
++** within the shared library, and closing the shared library.
+ */
+-#ifdef SQLITE_TEST
+-SQLITE_API int sqlite3_io_error_hit = 0; /* Total number of I/O Errors */
+-SQLITE_API int sqlite3_io_error_hardhit = 0; /* Number of non-benign errors */
+-SQLITE_API int sqlite3_io_error_pending = 0; /* Count down to first I/O error */
+-SQLITE_API int sqlite3_io_error_persist = 0; /* True if I/O errors persist */
+-SQLITE_API int sqlite3_io_error_benign = 0; /* True if errors are benign */
+-SQLITE_API int sqlite3_diskfull_pending = 0;
+-SQLITE_API int sqlite3_diskfull = 0;
+-#define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X)
+-#define SimulateIOError(CODE) \
+- if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \
+- || sqlite3_io_error_pending-- == 1 ) \
+- { local_ioerr(); CODE; }
+-static void local_ioerr(){
+- IOTRACE(("IOERR\n"));
+- sqlite3_io_error_hit++;
+- if( !sqlite3_io_error_benign ) sqlite3_io_error_hardhit++;
++#include <dlfcn.h>
++static void *unixDlOpen(sqlite3_vfs *NotUsed, const char *zFilename){
++ UNUSED_PARAMETER(NotUsed);
++ return dlopen(zFilename, RTLD_NOW | RTLD_GLOBAL);
+ }
+-#define SimulateDiskfullError(CODE) \
+- if( sqlite3_diskfull_pending ){ \
+- if( sqlite3_diskfull_pending == 1 ){ \
+- local_ioerr(); \
+- sqlite3_diskfull = 1; \
+- sqlite3_io_error_hit = 1; \
+- CODE; \
+- }else{ \
+- sqlite3_diskfull_pending--; \
+- } \
+- }
+-#else
+-#define SimulateIOErrorBenign(X)
+-#define SimulateIOError(A)
+-#define SimulateDiskfullError(A)
+-#endif
+
+ /*
+-** When testing, keep a count of the number of open files.
++** SQLite calls this function immediately after a call to unixDlSym() or
++** unixDlOpen() fails (returns a null pointer). If a more detailed error
++** message is available, it is written to zBufOut. If no error message
++** is available, zBufOut is left unmodified and SQLite uses a default
++** error message.
+ */
+-#ifdef SQLITE_TEST
+-SQLITE_API int sqlite3_open_file_count = 0;
+-#define OpenCounter(X) sqlite3_open_file_count+=(X)
+-#else
+-#define OpenCounter(X)
++static void unixDlError(sqlite3_vfs *NotUsed, int nBuf, char *zBufOut){
++ const char *zErr;
++ UNUSED_PARAMETER(NotUsed);
++ unixEnterMutex();
++ zErr = dlerror();
++ if( zErr ){
++ sqlite3_snprintf(nBuf, zBufOut, "%s", zErr);
++ }
++ unixLeaveMutex();
++}
++static void (*unixDlSym(sqlite3_vfs *NotUsed, void *p, const char*zSym))(void){
++ /*
++ ** GCC with -pedantic-errors says that C90 does not allow a void* to be
++ ** cast into a pointer to a function. And yet the library dlsym() routine
++ ** returns a void* which is really a pointer to a function. So how do we
++ ** use dlsym() with -pedantic-errors?
++ **
++ ** Variable x below is defined to be a pointer to a function taking
++ ** parameters void* and const char* and returning a pointer to a function.
++ ** We initialize x by assigning it a pointer to the dlsym() function.
++ ** (That assignment requires a cast.) Then we call the function that
++ ** x points to.
++ **
++ ** This work-around is unlikely to work correctly on any system where
++ ** you really cannot cast a function pointer into void*. But then, on the
++ ** other hand, dlsym() will not work on such a system either, so we have
++ ** not really lost anything.
++ */
++ void (*(*x)(void*,const char*))(void);
++ UNUSED_PARAMETER(NotUsed);
++ x = (void(*(*)(void*,const char*))(void))dlsym;
++ return (*x)(p, zSym);
++}
++static void unixDlClose(sqlite3_vfs *NotUsed, void *pHandle){
++ UNUSED_PARAMETER(NotUsed);
++ dlclose(pHandle);
++}
++#else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */
++ #define unixDlOpen 0
++ #define unixDlError 0
++ #define unixDlSym 0
++ #define unixDlClose 0
+ #endif
+
+-#endif /* !defined(_OS_COMMON_H_) */
+-
+-/************** End of os_common.h *******************************************/
+-/************** Continuing where we left off in os_win.c *********************/
+-
+ /*
+-** Compiling and using WAL mode requires several APIs that are only
+-** available in Windows platforms based on the NT kernel.
++** Write nBuf bytes of random data to the supplied buffer zBuf.
+ */
+-#if !SQLITE_OS_WINNT && !defined(SQLITE_OMIT_WAL)
+-# error "WAL mode requires support from the Windows NT kernel, compile\
+- with SQLITE_OMIT_WAL."
++static int unixRandomness(sqlite3_vfs *NotUsed, int nBuf, char *zBuf){
++ UNUSED_PARAMETER(NotUsed);
++ assert((size_t)nBuf>=(sizeof(time_t)+sizeof(int)));
++
++ /* We have to initialize zBuf to prevent valgrind from reporting
++ ** errors. The reports issued by valgrind are incorrect - we would
++ ** prefer that the randomness be increased by making use of the
++ ** uninitialized space in zBuf - but valgrind errors tend to worry
++ ** some users. Rather than argue, it seems easier just to initialize
++ ** the whole array and silence valgrind, even if that means less randomness
++ ** in the random seed.
++ **
++ ** When testing, initializing zBuf[] to zero is all we do. That means
++ ** that we always use the same random number sequence. This makes the
++ ** tests repeatable.
++ */
++ memset(zBuf, 0, nBuf);
++#if !defined(SQLITE_TEST)
++ {
++ int pid, fd, got;
++ fd = robust_open("/dev/urandom", O_RDONLY, 0);
++ if( fd<0 ){
++ time_t t;
++ time(&t);
++ memcpy(zBuf, &t, sizeof(t));
++ pid = getpid();
++ memcpy(&zBuf[sizeof(t)], &pid, sizeof(pid));
++ assert( sizeof(t)+sizeof(pid)<=(size_t)nBuf );
++ nBuf = sizeof(t) + sizeof(pid);
++ }else{
++ do{ got = osRead(fd, zBuf, nBuf); }while( got<0 && errno==EINTR );
++ robust_close(0, fd, __LINE__);
++ }
++ }
+ #endif
++ return nBuf;
++}
++
+
+ /*
+-** Are most of the Win32 ANSI APIs available (i.e. with certain exceptions
+-** based on the sub-platform)?
++** Sleep for a little while. Return the amount of time slept.
++** The argument is the number of microseconds we want to sleep.
++** The return value is the number of microseconds of sleep actually
++** requested from the underlying operating system, a number which
++** might be greater than or equal to the argument, but not less
++** than the argument.
+ */
+-#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
+-# define SQLITE_WIN32_HAS_ANSI
++static int unixSleep(sqlite3_vfs *NotUsed, int microseconds){
++#if OS_VXWORKS
++ struct timespec sp;
++
++ sp.tv_sec = microseconds / 1000000;
++ sp.tv_nsec = (microseconds % 1000000) * 1000;
++ nanosleep(&sp, NULL);
++ UNUSED_PARAMETER(NotUsed);
++ return microseconds;
++#elif defined(HAVE_USLEEP) && HAVE_USLEEP
++ usleep(microseconds);
++ UNUSED_PARAMETER(NotUsed);
++ return microseconds;
++#else
++ int seconds = (microseconds+999999)/1000000;
++ sleep(seconds);
++ UNUSED_PARAMETER(NotUsed);
++ return seconds*1000000;
+ #endif
++}
+
+ /*
+-** Are most of the Win32 Unicode APIs available (i.e. with certain exceptions
+-** based on the sub-platform)?
++** 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.
+ */
+-#if SQLITE_OS_WINCE || SQLITE_OS_WINNT || SQLITE_OS_WINRT
+-# define SQLITE_WIN32_HAS_WIDE
++#ifdef SQLITE_TEST
++SQLITE_API int sqlite3_current_time = 0; /* Fake system time in seconds since 1970. */
+ #endif
+
+ /*
+-** 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)?
+-*/
+-#if SQLITE_WIN32_FILEMAPPING_API && !defined(SQLITE_OMIT_WAL)
+-/*
+-** Two of the file mapping APIs are different under WinRT. Figure out which
+-** set we need.
++** 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.
+ */
+-#if SQLITE_OS_WINRT
+-WINBASEAPI HANDLE WINAPI CreateFileMappingFromApp(HANDLE, \
+- LPSECURITY_ATTRIBUTES, ULONG, ULONG64, LPCWSTR);
+-
+-WINBASEAPI LPVOID WINAPI MapViewOfFileFromApp(HANDLE, ULONG, ULONG64, SIZE_T);
++static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){
++ static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
++ int rc = SQLITE_OK;
++#if defined(NO_GETTOD)
++ time_t t;
++ time(&t);
++ *piNow = ((sqlite3_int64)t)*1000 + unixEpoch;
++#elif OS_VXWORKS
++ struct timespec sNow;
++ clock_gettime(CLOCK_REALTIME, &sNow);
++ *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_nsec/1000000;
+ #else
+-#if defined(SQLITE_WIN32_HAS_ANSI)
+-WINBASEAPI HANDLE WINAPI CreateFileMappingA(HANDLE, LPSECURITY_ATTRIBUTES, \
+- DWORD, DWORD, DWORD, LPCSTR);
+-#endif /* defined(SQLITE_WIN32_HAS_ANSI) */
+-
+-#if defined(SQLITE_WIN32_HAS_WIDE)
+-WINBASEAPI HANDLE WINAPI CreateFileMappingW(HANDLE, LPSECURITY_ATTRIBUTES, \
+- DWORD, DWORD, DWORD, LPCWSTR);
+-#endif /* defined(SQLITE_WIN32_HAS_WIDE) */
+-
+-WINBASEAPI LPVOID WINAPI MapViewOfFile(HANDLE, DWORD, DWORD, DWORD, SIZE_T);
+-#endif /* SQLITE_OS_WINRT */
++ struct timeval sNow;
++ if( gettimeofday(&sNow, 0)==0 ){
++ *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000;
++ }else{
++ rc = SQLITE_ERROR;
++ }
++#endif
+
+-/*
+-** This file mapping API is common to both Win32 and WinRT.
+-*/
+-WINBASEAPI BOOL WINAPI UnmapViewOfFile(LPCVOID);
+-#endif /* SQLITE_WIN32_FILEMAPPING_API && !defined(SQLITE_OMIT_WAL) */
++#ifdef SQLITE_TEST
++ if( sqlite3_current_time ){
++ *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch;
++ }
++#endif
++ UNUSED_PARAMETER(NotUsed);
++ return rc;
++}
+
+ /*
+-** Macro to find the minimum of two numeric values.
++** 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.
+ */
+-#ifndef MIN
+-# define MIN(x,y) ((x)<(y)?(x):(y))
+-#endif
++static int unixCurrentTime(sqlite3_vfs *NotUsed, double *prNow){
++ sqlite3_int64 i = 0;
++ int rc;
++ UNUSED_PARAMETER(NotUsed);
++ rc = unixCurrentTimeInt64(0, &i);
++ *prNow = i/86400000.0;
++ return rc;
++}
+
+ /*
+-** Some Microsoft compilers lack this definition.
++** We added the xGetLastError() method with the intention of providing
++** better low-level error messages when operating-system problems come up
++** during SQLite operation. But so far, none of that has been implemented
++** in the core. So this routine is never called. For now, it is merely
++** a place-holder.
+ */
+-#ifndef INVALID_FILE_ATTRIBUTES
+-# define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
+-#endif
++static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
++ UNUSED_PARAMETER(NotUsed);
++ UNUSED_PARAMETER(NotUsed2);
++ UNUSED_PARAMETER(NotUsed3);
++ return 0;
++}
+
+-#ifndef FILE_FLAG_MASK
+-# define FILE_FLAG_MASK (0xFF3C0000)
+-#endif
+
+-#ifndef FILE_ATTRIBUTE_MASK
+-# define FILE_ATTRIBUTE_MASK (0x0003FFF7)
+-#endif
++/*
++************************ End of sqlite3_vfs methods ***************************
++******************************************************************************/
+
+-#ifndef SQLITE_OMIT_WAL
+-/* Forward references */
+-typedef struct winShm winShm; /* A connection to shared-memory */
+-typedef struct winShmNode winShmNode; /* A region of shared-memory */
+-#endif
++/******************************************************************************
++************************** Begin Proxy Locking ********************************
++**
++** Proxy locking is a "uber-locking-method" in this sense: It uses the
++** other locking methods on secondary lock files. Proxy locking is a
++** meta-layer over top of the primitive locking implemented above. For
++** this reason, the division that implements of proxy locking is deferred
++** until late in the file (here) after all of the other I/O methods have
++** been defined - so that the primitive locking methods are available
++** as services to help with the implementation of proxy locking.
++**
++****
++**
++** The default locking schemes in SQLite use byte-range locks on the
++** database file to coordinate safe, concurrent access by multiple readers
++** and writers [http://sqlite.org/lockingv3.html]. The five file locking
++** states (UNLOCKED, PENDING, SHARED, RESERVED, EXCLUSIVE) are implemented
++** as POSIX read & write locks over fixed set of locations (via fsctl),
++** on AFP and SMB only exclusive byte-range locks are available via fsctl
++** with _IOWR('z', 23, struct ByteRangeLockPB2) to track the same 5 states.
++** To simulate a F_RDLCK on the shared range, on AFP a randomly selected
++** address in the shared range is taken for a SHARED lock, the entire
++** shared range is taken for an EXCLUSIVE lock):
++**
++** PENDING_BYTE 0x40000000
++** RESERVED_BYTE 0x40000001
++** SHARED_RANGE 0x40000002 -> 0x40000200
++**
++** This works well on the local file system, but shows a nearly 100x
++** slowdown in read performance on AFP because the AFP client disables
++** the read cache when byte-range locks are present. Enabling the read
++** cache exposes a cache coherency problem that is present on all OS X
++** supported network file systems. NFS and AFP both observe the
++** close-to-open semantics for ensuring cache coherency
++** [http://nfs.sourceforge.net/#faq_a8], which does not effectively
++** address the requirements for concurrent database access by multiple
++** readers and writers
++** [http://www.nabble.com/SQLite-on-NFS-cache-coherency-td15655701.html].
++**
++** To address the performance and cache coherency issues, proxy file locking
++** changes the way database access is controlled by limiting access to a
++** single host at a time and moving file locks off of the database file
++** and onto a proxy file on the local file system.
++**
++**
++** Using proxy locks
++** -----------------
++**
++** C APIs
++**
++** sqlite3_file_control(db, dbname, SQLITE_SET_LOCKPROXYFILE,
++** <proxy_path> | ":auto:");
++** sqlite3_file_control(db, dbname, SQLITE_GET_LOCKPROXYFILE, &<proxy_path>);
++**
++**
++** SQL pragmas
++**
++** PRAGMA [database.]lock_proxy_file=<proxy_path> | :auto:
++** PRAGMA [database.]lock_proxy_file
++**
++** Specifying ":auto:" means that if there is a conch file with a matching
++** host ID in it, the proxy path in the conch file will be used, otherwise
++** a proxy path based on the user's temp dir
++** (via confstr(_CS_DARWIN_USER_TEMP_DIR,...)) will be used and the
++** actual proxy file name is generated from the name and path of the
++** database file. For example:
++**
++** For database path "/Users/me/foo.db"
++** The lock path will be "<tmpdir>/sqliteplocks/_Users_me_foo.db:auto:")
++**
++** Once a lock proxy is configured for a database connection, it can not
++** be removed, however it may be switched to a different proxy path via
++** the above APIs (assuming the conch file is not being held by another
++** connection or process).
++**
++**
++** How proxy locking works
++** -----------------------
++**
++** Proxy file locking relies primarily on two new supporting files:
++**
++** * conch file to limit access to the database file to a single host
++** at a time
++**
++** * proxy file to act as a proxy for the advisory locks normally
++** taken on the database
++**
++** The conch file - to use a proxy file, sqlite must first "hold the conch"
++** by taking an sqlite-style shared lock on the conch file, reading the
++** contents and comparing the host's unique host ID (see below) and lock
++** 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
++** 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
++** is held by another process (with a shared lock), the exclusive lock
++** will fail and SQLITE_BUSY is returned.
++**
++** The proxy file - a single-byte file used for all advisory file locks
++** normally taken on the database file. This allows for safe sharing
++** of the database file for multiple readers and writers on the same
++** host (the conch ensures that they all use the same local lock file).
++**
++** Requesting the lock proxy does not immediately take the conch, it is
++** only taken when the first request to lock database file is made.
++** This matches the semantics of the traditional locking behavior, where
++** opening a connection to a database file does not take a lock on it.
++** The shared lock and an open file descriptor are maintained until
++** the connection to the database is closed.
++**
++** The proxy file and the lock file are never deleted so they only need
++** to be created the first time they are used.
++**
++** Configuration options
++** ---------------------
++**
++** SQLITE_PREFER_PROXY_LOCKING
++**
++** Database files accessed on non-local file systems are
++** automatically configured for proxy locking, lock files are
++** named automatically using the same logic as
++** PRAGMA lock_proxy_file=":auto:"
++**
++** SQLITE_PROXY_DEBUG
++**
++** Enables the logging of error messages during host id file
++** retrieval and creation
++**
++** LOCKPROXYDIR
++**
++** Overrides the default directory used for lock proxy files that
++** are named automatically via the ":auto:" setting
++**
++** SQLITE_DEFAULT_PROXYDIR_PERMISSIONS
++**
++** Permissions to use when creating a directory for storing the
++** lock proxy files, only used when LOCKPROXYDIR is not set.
++**
++**
++** As mentioned above, when compiled with SQLITE_PREFER_PROXY_LOCKING,
++** 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
++** sqlite_file_control API is not affected by SQLITE_FORCE_PROXY_LOCKING).
++*/
+
+ /*
+-** WinCE lacks native support for file locking so we have to fake it
+-** with some code of our own.
++** Proxy locking is only available on MacOSX
+ */
+-#if SQLITE_OS_WINCE
+-typedef struct winceLock {
+- int nReaders; /* Number of reader locks obtained */
+- BOOL bPending; /* Indicates a pending lock has been obtained */
+- BOOL bReserved; /* Indicates a reserved lock has been obtained */
+- BOOL bExclusive; /* Indicates an exclusive lock has been obtained */
+-} winceLock;
+-#endif
++#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
+
+ /*
+-** The winFile structure is a subclass of sqlite3_file* specific to the win32
+-** portability layer.
++** The proxyLockingContext has the path and file structures for the remote
++** and local proxy files in it
+ */
+-typedef struct winFile winFile;
+-struct winFile {
+- const sqlite3_io_methods *pMethod; /*** Must be first ***/
+- sqlite3_vfs *pVfs; /* The VFS used to open this file */
+- HANDLE h; /* Handle for accessing the file */
+- u8 locktype; /* Type of lock currently held on this file */
+- short sharedLockByte; /* Randomly chosen byte used as a shared lock */
+- u8 ctrlFlags; /* Flags. See WINFILE_* below */
+- DWORD lastErrno; /* The Windows errno from the last I/O error */
+-#ifndef SQLITE_OMIT_WAL
+- winShm *pShm; /* Instance of shared memory on this file */
+-#endif
+- const char *zPath; /* Full pathname of this file */
+- int szChunk; /* Chunk size configured by FCNTL_CHUNK_SIZE */
+-#if SQLITE_OS_WINCE
+- LPWSTR zDeleteOnClose; /* Name of file to delete when closing */
+- HANDLE hMutex; /* Mutex used to control access to shared lock */
+- HANDLE hShared; /* Shared memory segment used for locking */
+- winceLock local; /* Locks obtained by this instance of winFile */
+- winceLock *shared; /* Global shared lock memory for the file */
+-#endif
+-#if SQLITE_MAX_MMAP_SIZE>0
+- int nFetchOut; /* Number of outstanding xFetch references */
+- HANDLE hMap; /* Handle for accessing memory mapping */
+- void *pMapRegion; /* Area memory mapped */
+- sqlite3_int64 mmapSize; /* Usable size of mapped region */
+- sqlite3_int64 mmapSizeActual; /* Actual size of mapped region */
+- sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */
+-#endif
++typedef struct proxyLockingContext proxyLockingContext;
++struct proxyLockingContext {
++ unixFile *conchFile; /* Open conch file */
++ char *conchFilePath; /* Name of the conch file */
++ unixFile *lockProxy; /* Open proxy lock file */
++ 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 */
++ void *oldLockingContext; /* Original lockingcontext to restore on close */
++ sqlite3_io_methods const *pOldMethod; /* Original I/O methods for close */
+ };
+
+-/*
+-** Allowed values for winFile.ctrlFlags
++/*
++** The proxy lock file path for the database at dbPath is written into lPath,
++** which must point to valid, writable memory large enough for a maxLen length
++** file path.
+ */
+-#define WINFILE_RDONLY 0x02 /* Connection is read only */
+-#define WINFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */
+-#define WINFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */
++static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){
++ int len;
++ int dbLen;
++ int i;
+
+-/*
+- * The size of the buffer used by sqlite3_win32_write_debug().
+- */
+-#ifndef SQLITE_WIN32_DBG_BUF_SIZE
+-# define SQLITE_WIN32_DBG_BUF_SIZE ((int)(4096-sizeof(DWORD)))
++#ifdef LOCKPROXYDIR
++ len = strlcpy(lPath, LOCKPROXYDIR, maxLen);
++#else
++# ifdef _CS_DARWIN_USER_TEMP_DIR
++ {
++ if( !confstr(_CS_DARWIN_USER_TEMP_DIR, lPath, maxLen) ){
++ OSTRACE(("GETLOCKPATH failed %s errno=%d pid=%d\n",
++ lPath, errno, getpid()));
++ return SQLITE_IOERR_LOCK;
++ }
++ len = strlcat(lPath, "sqliteplocks", maxLen);
++ }
++# else
++ len = strlcpy(lPath, "/tmp/", maxLen);
++# endif
+ #endif
+
+-/*
+- * The value used with sqlite3_win32_set_directory() to specify that
+- * the data directory should be changed.
+- */
+-#ifndef SQLITE_WIN32_DATA_DIRECTORY_TYPE
+-# define SQLITE_WIN32_DATA_DIRECTORY_TYPE (1)
+-#endif
++ if( lPath[len-1]!='/' ){
++ len = strlcat(lPath, "/", maxLen);
++ }
++
++ /* transform the db path to a unique cache name */
++ dbLen = (int)strlen(dbPath);
++ for( i=0; i<dbLen && (i+len+7)<(int)maxLen; i++){
++ char c = dbPath[i];
++ lPath[i+len] = (c=='/')?'_':c;
++ }
++ lPath[i+len]='\0';
++ strlcat(lPath, ":auto:", maxLen);
++ OSTRACE(("GETLOCKPATH proxy lock path=%s pid=%d\n", lPath, getpid()));
++ return SQLITE_OK;
++}
+
+-/*
+- * The value used with sqlite3_win32_set_directory() to specify that
+- * the temporary directory should be changed.
++/*
++ ** Creates the lock file and any missing directories in lockPath
+ */
+-#ifndef SQLITE_WIN32_TEMP_DIRECTORY_TYPE
+-# define SQLITE_WIN32_TEMP_DIRECTORY_TYPE (2)
+-#endif
++static int proxyCreateLockPath(const char *lockPath){
++ int i, len;
++ char buf[MAXPATHLEN];
++ int start = 0;
++
++ assert(lockPath!=NULL);
++ /* try to create all the intermediate directories */
++ len = (int)strlen(lockPath);
++ buf[0] = lockPath[0];
++ for( i=1; i<len; i++ ){
++ if( lockPath[i] == '/' && (i - start > 0) ){
++ /* only mkdir if leaf dir != "." or "/" or ".." */
++ if( i-start>2 || (i-start==1 && buf[start] != '.' && buf[start] != '/')
++ || (i-start==2 && buf[start] != '.' && buf[start+1] != '.') ){
++ buf[i]='\0';
++ if( osMkdir(buf, SQLITE_DEFAULT_PROXYDIR_PERMISSIONS) ){
++ int err=errno;
++ if( err!=EEXIST ) {
++ OSTRACE(("CREATELOCKPATH FAILED creating %s, "
++ "'%s' proxy lock path=%s pid=%d\n",
++ buf, strerror(err), lockPath, getpid()));
++ return err;
++ }
++ }
++ }
++ start=i+1;
++ }
++ buf[i] = lockPath[i];
++ }
++ OSTRACE(("CREATELOCKPATH proxy lock path=%s pid=%d\n", lockPath, getpid()));
++ return 0;
++}
+
+ /*
+- * If compiled with SQLITE_WIN32_MALLOC on Windows, we will use the
+- * various Win32 API heap functions instead of our own.
+- */
+-#ifdef SQLITE_WIN32_MALLOC
++** Create a new VFS file descriptor (stored in memory obtained from
++** sqlite3_malloc) and open the file named "path" in the file descriptor.
++**
++** The caller is responsible not only for closing the file descriptor
++** but also for freeing the memory associated with the file descriptor.
++*/
++static int proxyCreateUnixFile(
++ const char *path, /* path for the new unixFile */
++ unixFile **ppFile, /* unixFile created and returned by ref */
++ int islockfile /* if non zero missing dirs will be created */
++) {
++ int fd = -1;
++ unixFile *pNew;
++ int rc = SQLITE_OK;
++ int openFlags = O_RDWR | O_CREAT;
++ sqlite3_vfs dummyVfs;
++ int terrno = 0;
++ UnixUnusedFd *pUnused = NULL;
+
+-/*
+- * If this is non-zero, an isolated heap will be created by the native Win32
+- * allocator subsystem; otherwise, the default process heap will be used. This
+- * setting has no effect when compiling for WinRT. By default, this is enabled
+- * and an isolated heap will be created to store all allocated data.
+- *
+- ******************************************************************************
+- * WARNING: It is important to note that when this setting is non-zero and the
+- * winMemShutdown function is called (e.g. by the sqlite3_shutdown
+- * function), all data that was allocated using the isolated heap will
+- * be freed immediately and any attempt to access any of that freed
+- * data will almost certainly result in an immediate access violation.
+- ******************************************************************************
+- */
+-#ifndef SQLITE_WIN32_HEAP_CREATE
+-# define SQLITE_WIN32_HEAP_CREATE (TRUE)
++ /* 1. first try to open/create the file
++ ** 2. if that fails, and this is a lock file (not-conch), try creating
++ ** the parent directories and then try again.
++ ** 3. if that fails, try to open the file read-only
++ ** otherwise return BUSY (if lock file) or CANTOPEN for the conch file
++ */
++ pUnused = findReusableFd(path, openFlags);
++ if( pUnused ){
++ fd = pUnused->fd;
++ }else{
++ pUnused = sqlite3_malloc(sizeof(*pUnused));
++ if( !pUnused ){
++ return SQLITE_NOMEM;
++ }
++ }
++ if( fd<0 ){
++ fd = robust_open(path, openFlags, 0);
++ terrno = errno;
++ if( fd<0 && errno==ENOENT && islockfile ){
++ if( proxyCreateLockPath(path) == SQLITE_OK ){
++ fd = robust_open(path, openFlags, 0);
++ }
++ }
++ }
++ if( fd<0 ){
++ openFlags = O_RDONLY;
++ fd = robust_open(path, openFlags, 0);
++ terrno = errno;
++ }
++ if( fd<0 ){
++ if( islockfile ){
++ return SQLITE_BUSY;
++ }
++ switch (terrno) {
++ case EACCES:
++ return SQLITE_PERM;
++ case EIO:
++ return SQLITE_IOERR_LOCK; /* even though it is the conch */
++ default:
++ return SQLITE_CANTOPEN_BKPT;
++ }
++ }
++
++ pNew = (unixFile *)sqlite3_malloc(sizeof(*pNew));
++ if( pNew==NULL ){
++ rc = SQLITE_NOMEM;
++ goto end_create_proxy;
++ }
++ memset(pNew, 0, sizeof(unixFile));
++ pNew->openFlags = openFlags;
++ memset(&dummyVfs, 0, sizeof(dummyVfs));
++ dummyVfs.pAppData = (void*)&autolockIoFinder;
++ dummyVfs.zName = "dummy";
++ pUnused->fd = fd;
++ pUnused->flags = openFlags;
++ pNew->pUnused = pUnused;
++
++ rc = fillInUnixFile(&dummyVfs, fd, (sqlite3_file*)pNew, path, 0);
++ if( rc==SQLITE_OK ){
++ *ppFile = pNew;
++ return SQLITE_OK;
++ }
++end_create_proxy:
++ robust_close(pNew, fd, __LINE__);
++ sqlite3_free(pNew);
++ sqlite3_free(pUnused);
++ return rc;
++}
++
++#ifdef SQLITE_TEST
++/* simulate multiple hosts by creating unique hostid file paths */
++SQLITE_API int sqlite3_hostid_num = 0;
+ #endif
+
+-/*
+- * The initial size of the Win32-specific heap. This value may be zero.
+- */
+-#ifndef SQLITE_WIN32_HEAP_INIT_SIZE
+-# define SQLITE_WIN32_HEAP_INIT_SIZE ((SQLITE_DEFAULT_CACHE_SIZE) * \
+- (SQLITE_DEFAULT_PAGE_SIZE) + 4194304)
++#define PROXY_HOSTIDLEN 16 /* conch file host id length */
++
++/* Not always defined in the headers as it ought to be */
++extern int gethostuuid(uuid_t id, const struct timespec *wait);
++
++/* get the host ID via gethostuuid(), pHostID must point to PROXY_HOSTIDLEN
++** bytes of writable memory.
++*/
++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
++ {
++ static const struct timespec timeout = {1, 0}; /* 1 sec timeout */
++ if( gethostuuid(pHostID, &timeout) ){
++ int err = errno;
++ if( pError ){
++ *pError = err;
++ }
++ return SQLITE_IOERR;
++ }
++ }
++#else
++ UNUSED_PARAMETER(pError);
+ #endif
+-
+-/*
+- * The maximum size of the Win32-specific heap. This value may be zero.
+- */
+-#ifndef SQLITE_WIN32_HEAP_MAX_SIZE
+-# define SQLITE_WIN32_HEAP_MAX_SIZE (0)
++#ifdef SQLITE_TEST
++ /* simulate multiple hosts by creating unique hostid file paths */
++ if( sqlite3_hostid_num != 0){
++ pHostID[0] = (char)(pHostID[0] + (char)(sqlite3_hostid_num & 0xFF));
++ }
+ #endif
++
++ return SQLITE_OK;
++}
+
+-/*
+- * The extra flags to use in calls to the Win32 heap APIs. This value may be
+- * zero for the default behavior.
++/* The conch file contains the header, host id and lock file path
+ */
+-#ifndef SQLITE_WIN32_HEAP_FLAGS
+-# define SQLITE_WIN32_HEAP_FLAGS (0)
+-#endif
++#define PROXY_CONCHVERSION 2 /* 1-byte header, 16-byte host id, path */
++#define PROXY_HEADERLEN 1 /* conch file header length */
++#define PROXY_PATHINDEX (PROXY_HEADERLEN+PROXY_HOSTIDLEN)
++#define PROXY_MAXCONCHLEN (PROXY_HEADERLEN+PROXY_HOSTIDLEN+MAXPATHLEN)
+
+-/*
+-** The winMemData structure stores information required by the Win32-specific
+-** sqlite3_mem_methods implementation.
++/*
++** Takes an open conch file, copies the contents to a new path and then moves
++** it back. The newly created file's file descriptor is assigned to the
++** conch file structure and finally the original conch file descriptor is
++** closed. Returns zero if successful.
+ */
+-typedef struct winMemData winMemData;
+-struct winMemData {
+-#ifndef NDEBUG
+- u32 magic; /* Magic number to detect structure corruption. */
+-#endif
+- HANDLE hHeap; /* The handle to our heap. */
+- BOOL bOwned; /* Do we own the heap (i.e. destroy it on shutdown)? */
+-};
++static int proxyBreakConchLock(unixFile *pFile, uuid_t myHostID){
++ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
++ unixFile *conchFile = pCtx->conchFile;
++ char tPath[MAXPATHLEN];
++ char buf[PROXY_MAXCONCHLEN];
++ char *cPath = pCtx->conchFilePath;
++ size_t readLen = 0;
++ size_t pathLen = 0;
++ char errmsg[64] = "";
++ int fd = -1;
++ int rc = -1;
++ UNUSED_PARAMETER(myHostID);
+
+-#ifndef NDEBUG
+-#define WINMEM_MAGIC 0x42b2830b
+-#endif
++ /* create a new path by replace the trailing '-conch' with '-break' */
++ pathLen = strlcpy(tPath, cPath, MAXPATHLEN);
++ if( pathLen>MAXPATHLEN || pathLen<6 ||
++ (strlcpy(&tPath[pathLen-5], "break", 6) != 5) ){
++ sqlite3_snprintf(sizeof(errmsg),errmsg,"path error (len %d)",(int)pathLen);
++ goto end_breaklock;
++ }
++ /* read the conch content */
++ readLen = osPread(conchFile->h, buf, PROXY_MAXCONCHLEN, 0);
++ if( readLen<PROXY_PATHINDEX ){
++ sqlite3_snprintf(sizeof(errmsg),errmsg,"read error (len %d)",(int)readLen);
++ goto end_breaklock;
++ }
++ /* write it out to the temporary break file */
++ fd = robust_open(tPath, (O_RDWR|O_CREAT|O_EXCL), 0);
++ if( fd<0 ){
++ sqlite3_snprintf(sizeof(errmsg), errmsg, "create failed (%d)", errno);
++ goto end_breaklock;
++ }
++ if( osPwrite(fd, buf, readLen, 0) != (ssize_t)readLen ){
++ sqlite3_snprintf(sizeof(errmsg), errmsg, "write failed (%d)", errno);
++ goto end_breaklock;
++ }
++ if( rename(tPath, cPath) ){
++ sqlite3_snprintf(sizeof(errmsg), errmsg, "rename failed (%d)", errno);
++ goto end_breaklock;
++ }
++ rc = 0;
++ fprintf(stderr, "broke stale lock on %s\n", cPath);
++ robust_close(pFile, conchFile->h, __LINE__);
++ conchFile->h = fd;
++ conchFile->openFlags = O_RDWR | O_CREAT;
+
+-static struct winMemData win_mem_data = {
+-#ifndef NDEBUG
+- WINMEM_MAGIC,
+-#endif
+- NULL, FALSE
+-};
++end_breaklock:
++ if( rc ){
++ if( fd>=0 ){
++ osUnlink(tPath);
++ robust_close(pFile, fd, __LINE__);
++ }
++ fprintf(stderr, "failed to break stale lock on %s, %s\n", cPath, errmsg);
++ }
++ return rc;
++}
+
+-#ifndef NDEBUG
+-#define winMemAssertMagic() assert( win_mem_data.magic==WINMEM_MAGIC )
+-#else
+-#define winMemAssertMagic()
+-#endif
++/* Take the requested lock on the conch file and break a stale lock if the
++** host id matches.
++*/
++static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){
++ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
++ unixFile *conchFile = pCtx->conchFile;
++ int rc = SQLITE_OK;
++ int nTries = 0;
++ struct timespec conchModTime;
++
++ memset(&conchModTime, 0, sizeof(conchModTime));
++ do {
++ rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType);
++ nTries ++;
++ if( rc==SQLITE_BUSY ){
++ /* If the lock failed (busy):
++ * 1st try: get the mod time of the conch, wait 0.5s and try again.
++ * 2nd try: fail if the mod time changed or host id is different, wait
++ * 10 sec and try again
++ * 3rd try: break the lock unless the mod time has changed.
++ */
++ struct stat buf;
++ if( osFstat(conchFile->h, &buf) ){
++ pFile->lastErrno = errno;
++ return SQLITE_IOERR_LOCK;
++ }
++
++ if( nTries==1 ){
++ conchModTime = buf.st_mtimespec;
++ usleep(500000); /* wait 0.5 sec and try the lock again*/
++ continue;
++ }
+
+-#define winMemGetHeap() win_mem_data.hHeap
++ assert( nTries>1 );
++ if( conchModTime.tv_sec != buf.st_mtimespec.tv_sec ||
++ conchModTime.tv_nsec != buf.st_mtimespec.tv_nsec ){
++ return SQLITE_BUSY;
++ }
++
++ if( nTries==2 ){
++ char tBuf[PROXY_MAXCONCHLEN];
++ int len = osPread(conchFile->h, tBuf, PROXY_MAXCONCHLEN, 0);
++ if( len<0 ){
++ pFile->lastErrno = errno;
++ return SQLITE_IOERR_LOCK;
++ }
++ if( len>PROXY_PATHINDEX && tBuf[0]==(char)PROXY_CONCHVERSION){
++ /* don't break the lock if the host id doesn't match */
++ if( 0!=memcmp(&tBuf[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN) ){
++ return SQLITE_BUSY;
++ }
++ }else{
++ /* don't break the lock on short read or a version mismatch */
++ return SQLITE_BUSY;
++ }
++ usleep(10000000); /* wait 10 sec and try the lock again */
++ continue;
++ }
++
++ assert( nTries==3 );
++ if( 0==proxyBreakConchLock(pFile, myHostID) ){
++ rc = SQLITE_OK;
++ if( lockType==EXCLUSIVE_LOCK ){
++ rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, SHARED_LOCK);
++ }
++ if( !rc ){
++ rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType);
++ }
++ }
++ }
++ } while( rc==SQLITE_BUSY && nTries<3 );
++
++ return rc;
++}
+
+-static void *winMemMalloc(int nBytes);
+-static void winMemFree(void *pPrior);
+-static void *winMemRealloc(void *pPrior, int nBytes);
+-static int winMemSize(void *p);
+-static int winMemRoundup(int n);
+-static int winMemInit(void *pAppData);
+-static void winMemShutdown(void *pAppData);
++/* Takes the conch by taking a shared lock and read the contents conch, if
++** lockPath is non-NULL, the host ID and lock file path must match. A NULL
++** lockPath means that the lockPath in the conch file will be used if the
++** host IDs match, or a new lock path will be generated automatically
++** and written to the conch file.
++*/
++static int proxyTakeConch(unixFile *pFile){
++ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
++
++ if( pCtx->conchHeld!=0 ){
++ return SQLITE_OK;
++ }else{
++ unixFile *conchFile = pCtx->conchFile;
++ uuid_t myHostID;
++ int pError = 0;
++ char readBuf[PROXY_MAXCONCHLEN];
++ char lockPath[MAXPATHLEN];
++ char *tempLockPath = NULL;
++ int rc = SQLITE_OK;
++ int createConch = 0;
++ int hostIdMatch = 0;
++ int readLen = 0;
++ int tryOldLockPath = 0;
++ int forceNewLockPath = 0;
++
++ OSTRACE(("TAKECONCH %d for %s pid=%d\n", conchFile->h,
++ (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), getpid()));
+
+-SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetWin32(void);
+-#endif /* SQLITE_WIN32_MALLOC */
++ rc = proxyGetHostID(myHostID, &pError);
++ if( (rc&0xff)==SQLITE_IOERR ){
++ pFile->lastErrno = pError;
++ goto end_takeconch;
++ }
++ rc = proxyConchLock(pFile, myHostID, SHARED_LOCK);
++ if( rc!=SQLITE_OK ){
++ goto end_takeconch;
++ }
++ /* read the existing conch file */
++ readLen = seekAndRead((unixFile*)conchFile, 0, readBuf, PROXY_MAXCONCHLEN);
++ if( readLen<0 ){
++ /* I/O error: lastErrno set by seekAndRead */
++ pFile->lastErrno = conchFile->lastErrno;
++ rc = SQLITE_IOERR_READ;
++ goto end_takeconch;
++ }else if( readLen<=(PROXY_HEADERLEN+PROXY_HOSTIDLEN) ||
++ readBuf[0]!=(char)PROXY_CONCHVERSION ){
++ /* a short read or version format mismatch means we need to create a new
++ ** conch file.
++ */
++ createConch = 1;
++ }
++ /* if the host id matches and the lock path already exists in the conch
++ ** we'll try to use the path there, if we can't open that path, we'll
++ ** retry with a new auto-generated path
++ */
++ do { /* in case we need to try again for an :auto: named lock file */
+
+-/*
+-** The following variable is (normally) set once and never changes
+-** thereafter. It records whether the operating system is Win9x
+-** or WinNT.
+-**
+-** 0: Operating system unknown.
+-** 1: Operating system is Win9x.
+-** 2: Operating system is WinNT.
+-**
+-** In order to facilitate testing on a WinNT system, the test fixture
+-** can manually set this value to 1 to emulate Win98 behavior.
+-*/
+-#ifdef SQLITE_TEST
+-SQLITE_API int sqlite3_os_type = 0;
++ if( !createConch && !forceNewLockPath ){
++ hostIdMatch = !memcmp(&readBuf[PROXY_HEADERLEN], myHostID,
++ PROXY_HOSTIDLEN);
++ /* if the conch has data compare the contents */
++ if( !pCtx->lockProxyPath ){
++ /* for auto-named local lock file, just check the host ID and we'll
++ ** use the local lock file path that's already in there
++ */
++ if( hostIdMatch ){
++ size_t pathLen = (readLen - PROXY_PATHINDEX);
++
++ if( pathLen>=MAXPATHLEN ){
++ pathLen=MAXPATHLEN-1;
++ }
++ memcpy(lockPath, &readBuf[PROXY_PATHINDEX], pathLen);
++ lockPath[pathLen] = 0;
++ tempLockPath = lockPath;
++ tryOldLockPath = 1;
++ /* create a copy of the lock path if the conch is taken */
++ goto end_takeconch;
++ }
++ }else if( hostIdMatch
++ && !strncmp(pCtx->lockProxyPath, &readBuf[PROXY_PATHINDEX],
++ readLen-PROXY_PATHINDEX)
++ ){
++ /* conch host and lock path match */
++ goto end_takeconch;
++ }
++ }
++
++ /* if the conch isn't writable and doesn't match, we can't take it */
++ if( (conchFile->openFlags&O_RDWR) == 0 ){
++ rc = SQLITE_BUSY;
++ goto end_takeconch;
++ }
++
++ /* either the conch didn't match or we need to create a new one */
++ if( !pCtx->lockProxyPath ){
++ proxyGetLockPath(pCtx->dbPath, lockPath, MAXPATHLEN);
++ tempLockPath = lockPath;
++ /* create a copy of the lock path _only_ if the conch is taken */
++ }
++
++ /* update conch with host and path (this will fail if other process
++ ** has a shared lock already), if the host id matches, use the big
++ ** stick.
++ */
++ futimes(conchFile->h, NULL);
++ if( hostIdMatch && !createConch ){
++ if( conchFile->pInode && conchFile->pInode->nShared>1 ){
++ /* We are trying for an exclusive lock but another thread in this
++ ** same process is still holding a shared lock. */
++ rc = SQLITE_BUSY;
++ } else {
++ rc = proxyConchLock(pFile, myHostID, EXCLUSIVE_LOCK);
++ }
++ }else{
++ rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, EXCLUSIVE_LOCK);
++ }
++ if( rc==SQLITE_OK ){
++ char writeBuffer[PROXY_MAXCONCHLEN];
++ int writeSize = 0;
++
++ writeBuffer[0] = (char)PROXY_CONCHVERSION;
++ memcpy(&writeBuffer[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN);
++ if( pCtx->lockProxyPath!=NULL ){
++ strlcpy(&writeBuffer[PROXY_PATHINDEX], pCtx->lockProxyPath, MAXPATHLEN);
++ }else{
++ strlcpy(&writeBuffer[PROXY_PATHINDEX], tempLockPath, MAXPATHLEN);
++ }
++ writeSize = PROXY_PATHINDEX + strlen(&writeBuffer[PROXY_PATHINDEX]);
++ robust_ftruncate(conchFile->h, writeSize);
++ rc = unixWrite((sqlite3_file *)conchFile, writeBuffer, writeSize, 0);
++ fsync(conchFile->h);
++ /* If we created a new conch file (not just updated the contents of a
++ ** valid conch file), try to match the permissions of the database
++ */
++ if( rc==SQLITE_OK && createConch ){
++ struct stat buf;
++ int err = osFstat(pFile->h, &buf);
++ if( err==0 ){
++ mode_t cmode = buf.st_mode&(S_IRUSR|S_IWUSR | S_IRGRP|S_IWGRP |
++ S_IROTH|S_IWOTH);
++ /* try to match the database file R/W permissions, ignore failure */
++#ifndef SQLITE_PROXY_DEBUG
++ osFchmod(conchFile->h, cmode);
+ #else
+-static int sqlite3_os_type = 0;
+-#endif
+-
+-#ifndef SYSCALL
+-# define SYSCALL sqlite3_syscall_ptr
++ do{
++ rc = osFchmod(conchFile->h, cmode);
++ }while( rc==(-1) && errno==EINTR );
++ if( rc!=0 ){
++ int code = errno;
++ fprintf(stderr, "fchmod %o FAILED with %d %s\n",
++ cmode, code, strerror(code));
++ } else {
++ fprintf(stderr, "fchmod %o SUCCEDED\n",cmode);
++ }
++ }else{
++ int code = errno;
++ fprintf(stderr, "STAT FAILED[%d] with %d %s\n",
++ err, code, strerror(code));
+ #endif
++ }
++ }
++ }
++ conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, SHARED_LOCK);
++
++ end_takeconch:
++ OSTRACE(("TRANSPROXY: CLOSE %d\n", pFile->h));
++ if( rc==SQLITE_OK && pFile->openFlags ){
++ int fd;
++ if( pFile->h>=0 ){
++ robust_close(pFile, pFile->h, __LINE__);
++ }
++ pFile->h = -1;
++ fd = robust_open(pCtx->dbPath, pFile->openFlags, 0);
++ OSTRACE(("TRANSPROXY: OPEN %d\n", fd));
++ if( fd>=0 ){
++ pFile->h = fd;
++ }else{
++ rc=SQLITE_CANTOPEN_BKPT; /* SQLITE_BUSY? proxyTakeConch called
++ during locking */
++ }
++ }
++ if( rc==SQLITE_OK && !pCtx->lockProxy ){
++ char *path = tempLockPath ? tempLockPath : pCtx->lockProxyPath;
++ rc = proxyCreateUnixFile(path, &pCtx->lockProxy, 1);
++ if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM && tryOldLockPath ){
++ /* we couldn't create the proxy lock file with the old lock file path
++ ** so try again via auto-naming
++ */
++ forceNewLockPath = 1;
++ tryOldLockPath = 0;
++ continue; /* go back to the do {} while start point, try again */
++ }
++ }
++ if( rc==SQLITE_OK ){
++ /* Need to make a copy of path if we extracted the value
++ ** from the conch file or the path was allocated on the stack
++ */
++ if( tempLockPath ){
++ pCtx->lockProxyPath = sqlite3DbStrDup(0, tempLockPath);
++ if( !pCtx->lockProxyPath ){
++ rc = SQLITE_NOMEM;
++ }
++ }
++ }
++ if( rc==SQLITE_OK ){
++ pCtx->conchHeld = 1;
++
++ if( pCtx->lockProxy->pMethod == &afpIoMethods ){
++ afpLockingContext *afpCtx;
++ afpCtx = (afpLockingContext *)pCtx->lockProxy->lockingContext;
++ afpCtx->dbPath = pCtx->lockProxyPath;
++ }
++ } else {
++ conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, NO_LOCK);
++ }
++ OSTRACE(("TAKECONCH %d %s\n", conchFile->h,
++ rc==SQLITE_OK?"ok":"failed"));
++ return rc;
++ } while (1); /* in case we need to retry the :auto: lock file -
++ ** we should never get here except via the 'continue' call. */
++ }
++}
+
+ /*
+-** This function is not available on Windows CE or WinRT.
+- */
++** If pFile holds a lock on a conch file, then release that lock.
++*/
++static int proxyReleaseConch(unixFile *pFile){
++ int rc = SQLITE_OK; /* Subroutine return code */
++ proxyLockingContext *pCtx; /* The locking context for the proxy lock */
++ unixFile *conchFile; /* Name of the conch file */
+
+-#if SQLITE_OS_WINCE || SQLITE_OS_WINRT
+-# define osAreFileApisANSI() 1
+-#endif
++ pCtx = (proxyLockingContext *)pFile->lockingContext;
++ conchFile = pCtx->conchFile;
++ OSTRACE(("RELEASECONCH %d for %s pid=%d\n", conchFile->h,
++ (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"),
++ getpid()));
++ if( pCtx->conchHeld>0 ){
++ rc = conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, NO_LOCK);
++ }
++ pCtx->conchHeld = 0;
++ OSTRACE(("RELEASECONCH %d %s\n", conchFile->h,
++ (rc==SQLITE_OK ? "ok" : "failed")));
++ return rc;
++}
+
+ /*
+-** Many system calls are accessed through pointer-to-functions so that
+-** they may be overridden at runtime to facilitate fault injection during
+-** testing and sandboxing. The following array holds the names and pointers
+-** to all overrideable system calls.
++** Given the name of a database file, compute the name of its conch file.
++** Store the conch filename in memory obtained from sqlite3_malloc().
++** Make *pConchPath point to the new name. Return SQLITE_OK on success
++** or SQLITE_NOMEM if unable to obtain memory.
++**
++** The caller is responsible for ensuring that the allocated memory
++** space is eventually freed.
++**
++** *pConchPath is set to NULL if a memory allocation error occurs.
+ */
+-static struct win_syscall {
+- const char *zName; /* Name of the system call */
+- sqlite3_syscall_ptr pCurrent; /* Current value of the system call */
+- sqlite3_syscall_ptr pDefault; /* Default value */
+-} aSyscall[] = {
+-#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
++static int proxyCreateConchPathname(char *dbPath, char **pConchPath){
++ int i; /* Loop counter */
++ int len = (int)strlen(dbPath); /* Length of database filename - dbPath */
++ char *conchPath; /* buffer in which to construct conch name */
+
+-#define osCharLowerW ((LPWSTR(WINAPI*)(LPWSTR))aSyscall[1].pCurrent)
++ /* 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);
++ if( conchPath==0 ){
++ return SQLITE_NOMEM;
++ }
++ memcpy(conchPath, dbPath, len+1);
++
++ /* now insert a "." before the last / character */
++ for( i=(len-1); i>=0; i-- ){
++ if( conchPath[i]=='/' ){
++ i++;
++ break;
++ }
++ }
++ conchPath[i]='.';
++ while ( i<len ){
++ conchPath[i+1]=dbPath[i];
++ i++;
++ }
+
+-#if SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE)
+- { "CharUpperW", (SYSCALL)CharUpperW, 0 },
+-#else
+- { "CharUpperW", (SYSCALL)0, 0 },
+-#endif
++ /* append the "-conch" suffix to the file */
++ memcpy(&conchPath[i+1], "-conch", 7);
++ assert( (int)strlen(conchPath) == len+7 );
+
+-#define osCharUpperW ((LPWSTR(WINAPI*)(LPWSTR))aSyscall[2].pCurrent)
++ return SQLITE_OK;
++}
+
+- { "CloseHandle", (SYSCALL)CloseHandle, 0 },
+
+-#define osCloseHandle ((BOOL(WINAPI*)(HANDLE))aSyscall[3].pCurrent)
++/* Takes a fully configured proxy locking-style unix file and switches
++** the local lock file path
++*/
++static int switchLockProxyPath(unixFile *pFile, const char *path) {
++ proxyLockingContext *pCtx = (proxyLockingContext*)pFile->lockingContext;
++ char *oldPath = pCtx->lockProxyPath;
++ int rc = SQLITE_OK;
+
+-#if defined(SQLITE_WIN32_HAS_ANSI)
+- { "CreateFileA", (SYSCALL)CreateFileA, 0 },
+-#else
+- { "CreateFileA", (SYSCALL)0, 0 },
+-#endif
++ if( pFile->eFileLock!=NO_LOCK ){
++ return SQLITE_BUSY;
++ }
+
+-#define osCreateFileA ((HANDLE(WINAPI*)(LPCSTR,DWORD,DWORD, \
+- LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[4].pCurrent)
++ /* nothing to do if the path is NULL, :auto: or matches the existing path */
++ if( !path || path[0]=='\0' || !strcmp(path, ":auto:") ||
++ (oldPath && !strncmp(oldPath, path, MAXPATHLEN)) ){
++ return SQLITE_OK;
++ }else{
++ unixFile *lockProxy = pCtx->lockProxy;
++ pCtx->lockProxy=NULL;
++ pCtx->conchHeld = 0;
++ if( lockProxy!=NULL ){
++ rc=lockProxy->pMethod->xClose((sqlite3_file *)lockProxy);
++ if( rc ) return rc;
++ sqlite3_free(lockProxy);
++ }
++ sqlite3_free(oldPath);
++ pCtx->lockProxyPath = sqlite3DbStrDup(0, path);
++ }
++
++ return rc;
++}
+
+-#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
+- { "CreateFileW", (SYSCALL)CreateFileW, 0 },
+-#else
+- { "CreateFileW", (SYSCALL)0, 0 },
++/*
++** pFile is a file that has been opened by a prior xOpen call. dbPath
++** is a string buffer at least MAXPATHLEN+1 characters in size.
++**
++** This routine find the filename associated with pFile and writes it
++** int dbPath.
++*/
++static int proxyGetDbPathForUnixFile(unixFile *pFile, char *dbPath){
++#if defined(__APPLE__)
++ if( pFile->pMethod == &afpIoMethods ){
++ /* 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);
++ } else
+ #endif
++ if( pFile->pMethod == &dotlockIoMethods ){
++ /* dot lock style uses the locking context to store the dot lock
++ ** file path */
++ int len = strlen((char *)pFile->lockingContext) - strlen(DOTLOCK_SUFFIX);
++ memcpy(dbPath, (char *)pFile->lockingContext, len + 1);
++ }else{
++ /* all other styles use the locking context to store the db file path */
++ assert( strlen((char*)pFile->lockingContext)<=MAXPATHLEN );
++ strlcpy(dbPath, (char *)pFile->lockingContext, MAXPATHLEN);
++ }
++ return SQLITE_OK;
++}
+
+-#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))
+- { "CreateFileMappingA", (SYSCALL)CreateFileMappingA, 0 },
+-#else
+- { "CreateFileMappingA", (SYSCALL)0, 0 },
+-#endif
++/*
++** Takes an already filled in unix file and alters it so all file locking
++** will be performed on the local proxy lock file. The following fields
++** are preserved in the locking context so that they can be restored and
++** the unix structure properly cleaned up at close time:
++** ->lockingContext
++** ->pMethod
++*/
++static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
++ proxyLockingContext *pCtx;
++ char dbPath[MAXPATHLEN+1]; /* Name of the database file */
++ char *lockPath=NULL;
++ int rc = SQLITE_OK;
++
++ if( pFile->eFileLock!=NO_LOCK ){
++ return SQLITE_BUSY;
++ }
++ proxyGetDbPathForUnixFile(pFile, dbPath);
++ if( !path || path[0]=='\0' || !strcmp(path, ":auto:") ){
++ lockPath=NULL;
++ }else{
++ lockPath=(char *)path;
++ }
++
++ OSTRACE(("TRANSPROXY %d for %s pid=%d\n", pFile->h,
++ (lockPath ? lockPath : ":auto:"), getpid()));
+
+-#define osCreateFileMappingA ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \
+- DWORD,DWORD,DWORD,LPCSTR))aSyscall[6].pCurrent)
++ pCtx = sqlite3_malloc( sizeof(*pCtx) );
++ if( pCtx==0 ){
++ return SQLITE_NOMEM;
++ }
++ memset(pCtx, 0, sizeof(*pCtx));
+
+-#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \
+- !defined(SQLITE_OMIT_WAL))
+- { "CreateFileMappingW", (SYSCALL)CreateFileMappingW, 0 },
+-#else
+- { "CreateFileMappingW", (SYSCALL)0, 0 },
+-#endif
++ rc = proxyCreateConchPathname(dbPath, &pCtx->conchFilePath);
++ if( rc==SQLITE_OK ){
++ rc = proxyCreateUnixFile(pCtx->conchFilePath, &pCtx->conchFile, 0);
++ if( rc==SQLITE_CANTOPEN && ((pFile->openFlags&O_RDWR) == 0) ){
++ /* if (a) the open flags are not O_RDWR, (b) the conch isn't there, and
++ ** (c) the file system is read-only, then enable no-locking access.
++ ** Ugh, since O_RDONLY==0x0000 we test for !O_RDWR since unixOpen asserts
++ ** that openFlags will have only one of O_RDONLY or O_RDWR.
++ */
++ struct statfs fsInfo;
++ struct stat conchInfo;
++ int goLockless = 0;
+
+-#define osCreateFileMappingW ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \
+- DWORD,DWORD,DWORD,LPCWSTR))aSyscall[7].pCurrent)
++ if( osStat(pCtx->conchFilePath, &conchInfo) == -1 ) {
++ int err = errno;
++ if( (err==ENOENT) && (statfs(dbPath, &fsInfo) != -1) ){
++ goLockless = (fsInfo.f_flags&MNT_RDONLY) == MNT_RDONLY;
++ }
++ }
++ if( goLockless ){
++ pCtx->conchHeld = -1; /* read only FS/ lockless */
++ rc = SQLITE_OK;
++ }
++ }
++ }
++ if( rc==SQLITE_OK && lockPath ){
++ pCtx->lockProxyPath = sqlite3DbStrDup(0, lockPath);
++ }
+
+-#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
+- { "CreateMutexW", (SYSCALL)CreateMutexW, 0 },
+-#else
+- { "CreateMutexW", (SYSCALL)0, 0 },
+-#endif
++ if( rc==SQLITE_OK ){
++ pCtx->dbPath = sqlite3DbStrDup(0, dbPath);
++ if( pCtx->dbPath==NULL ){
++ rc = SQLITE_NOMEM;
++ }
++ }
++ if( rc==SQLITE_OK ){
++ /* all memory is allocated, proxys are created and assigned,
++ ** switch the locking context and pMethod then return.
++ */
++ pCtx->oldLockingContext = pFile->lockingContext;
++ pFile->lockingContext = pCtx;
++ pCtx->pOldMethod = pFile->pMethod;
++ pFile->pMethod = &proxyIoMethods;
++ }else{
++ if( pCtx->conchFile ){
++ pCtx->conchFile->pMethod->xClose((sqlite3_file *)pCtx->conchFile);
++ sqlite3_free(pCtx->conchFile);
++ }
++ sqlite3DbFree(0, pCtx->lockProxyPath);
++ sqlite3_free(pCtx->conchFilePath);
++ sqlite3_free(pCtx);
++ }
++ OSTRACE(("TRANSPROXY %d %s\n", pFile->h,
++ (rc==SQLITE_OK ? "ok" : "failed")));
++ return rc;
++}
+
+-#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
++/*
++** This routine handles sqlite3_file_control() calls that are specific
++** to proxy locking.
++*/
++static int proxyFileControl(sqlite3_file *id, int op, void *pArg){
++ switch( op ){
++ case SQLITE_GET_LOCKPROXYFILE: {
++ unixFile *pFile = (unixFile*)id;
++ if( pFile->pMethod == &proxyIoMethods ){
++ proxyLockingContext *pCtx = (proxyLockingContext*)pFile->lockingContext;
++ proxyTakeConch(pFile);
++ if( pCtx->lockProxyPath ){
++ *(const char **)pArg = pCtx->lockProxyPath;
++ }else{
++ *(const char **)pArg = ":auto: (not held)";
++ }
++ } else {
++ *(const char **)pArg = NULL;
++ }
++ return SQLITE_OK;
++ }
++ case SQLITE_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 */
++ rc = SQLITE_ERROR /*SQLITE_PROTOCOL? SQLITE_MISUSE?*/;
++ }else{
++ /* turn off proxy locking - already off - NOOP */
++ rc = SQLITE_OK;
++ }
++ }else{
++ const char *proxyPath = (const char *)pArg;
++ if( isProxyStyle ){
++ proxyLockingContext *pCtx =
++ (proxyLockingContext*)pFile->lockingContext;
++ if( !strcmp(pArg, ":auto:")
++ || (pCtx->lockProxyPath &&
++ !strncmp(pCtx->lockProxyPath, proxyPath, MAXPATHLEN))
++ ){
++ rc = SQLITE_OK;
++ }else{
++ rc = switchLockProxyPath(pFile, proxyPath);
++ }
++ }else{
++ /* turn on proxy file locking */
++ rc = proxyTransformUnixFile(pFile, proxyPath);
++ }
++ }
++ return rc;
++ }
++ default: {
++ assert( 0 ); /* The call assures that only valid opcodes are sent */
++ }
++ }
++ /*NOTREACHED*/
++ return SQLITE_ERROR;
++}
+
+-#define osDeleteFileA ((BOOL(WINAPI*)(LPCSTR))aSyscall[9].pCurrent)
++/*
++** Within this division (the proxying locking implementation) the procedures
++** above this point are all utilities. The lock-related methods of the
++** proxy-locking sqlite3_io_method object follow.
++*/
+
+-#if defined(SQLITE_WIN32_HAS_WIDE)
+- { "DeleteFileW", (SYSCALL)DeleteFileW, 0 },
+-#else
+- { "DeleteFileW", (SYSCALL)0, 0 },
+-#endif
+
+-#define osDeleteFileW ((BOOL(WINAPI*)(LPCWSTR))aSyscall[10].pCurrent)
++/*
++** 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, set *pResOut
++** 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 proxyCheckReservedLock(sqlite3_file *id, int *pResOut) {
++ unixFile *pFile = (unixFile*)id;
++ int rc = proxyTakeConch(pFile);
++ if( rc==SQLITE_OK ){
++ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
++ if( pCtx->conchHeld>0 ){
++ unixFile *proxy = pCtx->lockProxy;
++ return proxy->pMethod->xCheckReservedLock((sqlite3_file*)proxy, pResOut);
++ }else{ /* conchHeld < 0 is lockless */
++ pResOut=0;
++ }
++ }
++ return rc;
++}
+
+-#if SQLITE_OS_WINCE
+- { "FileTimeToLocalFileTime", (SYSCALL)FileTimeToLocalFileTime, 0 },
+-#else
+- { "FileTimeToLocalFileTime", (SYSCALL)0, 0 },
+-#endif
++/*
++** Lock the file with the lock specified by parameter eFileLock - 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. Use the sqlite3OsUnlock()
++** routine to lower a locking level.
++*/
++static int proxyLock(sqlite3_file *id, int eFileLock) {
++ unixFile *pFile = (unixFile*)id;
++ int rc = proxyTakeConch(pFile);
++ if( rc==SQLITE_OK ){
++ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
++ if( pCtx->conchHeld>0 ){
++ unixFile *proxy = pCtx->lockProxy;
++ rc = proxy->pMethod->xLock((sqlite3_file*)proxy, eFileLock);
++ pFile->eFileLock = proxy->eFileLock;
++ }else{
++ /* conchHeld < 0 is lockless */
++ }
++ }
++ return rc;
++}
+
+-#define osFileTimeToLocalFileTime ((BOOL(WINAPI*)(CONST FILETIME*, \
+- LPFILETIME))aSyscall[11].pCurrent)
+
+-#if SQLITE_OS_WINCE
+- { "FileTimeToSystemTime", (SYSCALL)FileTimeToSystemTime, 0 },
+-#else
+- { "FileTimeToSystemTime", (SYSCALL)0, 0 },
+-#endif
++/*
++** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
++** 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.
++*/
++static int proxyUnlock(sqlite3_file *id, int eFileLock) {
++ unixFile *pFile = (unixFile*)id;
++ int rc = proxyTakeConch(pFile);
++ if( rc==SQLITE_OK ){
++ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
++ if( pCtx->conchHeld>0 ){
++ unixFile *proxy = pCtx->lockProxy;
++ rc = proxy->pMethod->xUnlock((sqlite3_file*)proxy, eFileLock);
++ pFile->eFileLock = proxy->eFileLock;
++ }else{
++ /* conchHeld < 0 is lockless */
++ }
++ }
++ return rc;
++}
+
+-#define osFileTimeToSystemTime ((BOOL(WINAPI*)(CONST FILETIME*, \
+- LPSYSTEMTIME))aSyscall[12].pCurrent)
++/*
++** Close a file that uses proxy locks.
++*/
++static int proxyClose(sqlite3_file *id) {
++ if( id ){
++ unixFile *pFile = (unixFile*)id;
++ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
++ unixFile *lockProxy = pCtx->lockProxy;
++ unixFile *conchFile = pCtx->conchFile;
++ int rc = SQLITE_OK;
++
++ if( lockProxy ){
++ rc = lockProxy->pMethod->xUnlock((sqlite3_file*)lockProxy, NO_LOCK);
++ if( rc ) return rc;
++ rc = lockProxy->pMethod->xClose((sqlite3_file*)lockProxy);
++ if( rc ) return rc;
++ sqlite3_free(lockProxy);
++ pCtx->lockProxy = 0;
++ }
++ if( conchFile ){
++ if( pCtx->conchHeld ){
++ rc = proxyReleaseConch(pFile);
++ if( rc ) return rc;
++ }
++ rc = conchFile->pMethod->xClose((sqlite3_file*)conchFile);
++ if( rc ) return rc;
++ sqlite3_free(conchFile);
++ }
++ sqlite3DbFree(0, pCtx->lockProxyPath);
++ sqlite3_free(pCtx->conchFilePath);
++ sqlite3DbFree(0, pCtx->dbPath);
++ /* restore the original locking context and pMethod then close it */
++ pFile->lockingContext = pCtx->oldLockingContext;
++ pFile->pMethod = pCtx->pOldMethod;
++ sqlite3_free(pCtx);
++ return pFile->pMethod->xClose(id);
++ }
++ return SQLITE_OK;
++}
+
+- { "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
++#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
++/*
++** The proxy locking style is intended for use with AFP filesystems.
++** And since AFP is only supported on MacOSX, the proxy locking is also
++** restricted to MacOSX.
++**
++**
++******************* End of the proxy lock implementation **********************
++******************************************************************************/
+
+-#define osFormatMessageA ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPSTR, \
+- DWORD,va_list*))aSyscall[14].pCurrent)
++/*
++** Initialize the operating system interface.
++**
++** This routine registers all VFS implementations for unix-like operating
++** systems. This routine, and the sqlite3_os_end() routine that follows,
++** should be the only routines in this file that are visible from other
++** files.
++**
++** This routine is called once during SQLite initialization and by a
++** single thread. The memory allocation and mutex subsystems have not
++** necessarily been initialized when this routine is called, and so they
++** should not be used.
++*/
++SQLITE_API int 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
++ ** to the "finder" function. (pAppData is a pointer to a pointer because
++ ** silly C90 rules prohibit a void* from being cast to a function pointer
++ ** and so we have to go through the intermediate pointer to avoid problems
++ ** when compiling with -pedantic-errors on GCC.)
++ **
++ ** The FINDER parameter to this macro is the name of the pointer to the
++ ** finder-function. The finder-function returns a pointer to the
++ ** sqlite_io_methods object that implements the desired locking
++ ** behaviors. See the division above that contains the IOMETHODS
++ ** macro for addition information on finder-functions.
++ **
++ ** Most finders simply return a pointer to a fixed sqlite3_io_methods
++ ** object. But the "autolockIoFinder" available on MacOSX does a little
++ ** more than that; it looks at the filesystem type that hosts the
++ ** database file and tries to choose an locking method appropriate for
++ ** that filesystem time.
++ */
++ #define UNIXVFS(VFSNAME, FINDER) { \
++ 3, /* iVersion */ \
++ sizeof(unixFile), /* szOsFile */ \
++ MAX_PATHNAME, /* mxPathname */ \
++ 0, /* pNext */ \
++ VFSNAME, /* zName */ \
++ (void*)&FINDER, /* pAppData */ \
++ unixOpen, /* xOpen */ \
++ unixDelete, /* xDelete */ \
++ unixAccess, /* xAccess */ \
++ unixFullPathname, /* xFullPathname */ \
++ unixDlOpen, /* xDlOpen */ \
++ unixDlError, /* xDlError */ \
++ unixDlSym, /* xDlSym */ \
++ unixDlClose, /* xDlClose */ \
++ unixRandomness, /* xRandomness */ \
++ unixSleep, /* xSleep */ \
++ unixCurrentTime, /* xCurrentTime */ \
++ unixGetLastError, /* xGetLastError */ \
++ unixCurrentTimeInt64, /* xCurrentTimeInt64 */ \
++ unixSetSystemCall, /* xSetSystemCall */ \
++ unixGetSystemCall, /* xGetSystemCall */ \
++ unixNextSystemCall, /* xNextSystemCall */ \
++ }
+
+-#if defined(SQLITE_WIN32_HAS_WIDE)
+- { "FormatMessageW", (SYSCALL)FormatMessageW, 0 },
++ /*
++ ** All default VFSes for unix are contained in the following array.
++ **
++ ** Note that the sqlite3_vfs.pNext field of the VFS object is modified
++ ** by the SQLite core when the VFS is registered. So the following
++ ** array cannot be const.
++ */
++ static sqlite3_vfs aVfs[] = {
++#if SQLITE_ENABLE_LOCKING_STYLE && (OS_VXWORKS || defined(__APPLE__))
++ UNIXVFS("unix", autolockIoFinder ),
+ #else
+- { "FormatMessageW", (SYSCALL)0, 0 },
++ UNIXVFS("unix", posixIoFinder ),
+ #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 },
++ UNIXVFS("unix-none", nolockIoFinder ),
++ UNIXVFS("unix-dotfile", dotlockIoFinder ),
++ UNIXVFS("unix-excl", posixIoFinder ),
++#if OS_VXWORKS
++ UNIXVFS("unix-namedsem", semIoFinder ),
++#endif
++#if SQLITE_ENABLE_LOCKING_STYLE
++ UNIXVFS("unix-posix", posixIoFinder ),
++#if !OS_VXWORKS
++ UNIXVFS("unix-flock", flockIoFinder ),
+ #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 },
++#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
++ UNIXVFS("unix-afp", afpIoFinder ),
++ UNIXVFS("unix-nfs", nfsIoFinder ),
++ UNIXVFS("unix-proxy", proxyIoFinder ),
+ #endif
++ };
++ unsigned int i; /* Loop counter */
+
+-#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
++ /* Double-check that the aSyscall[] array has been constructed
++ ** correctly. See ticket [bb3a86e890c8e96ab] */
++ assert( ArraySize(aSyscall)==24 );
+
+-#define osGetFileAttributesA ((DWORD(WINAPI*)(LPCSTR))aSyscall[20].pCurrent)
++ /* Register all VFSes defined in the aVfs[] array */
++ for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
++ sqlite3_vfs_register(&aVfs[i], i==0);
++ }
++ return SQLITE_OK;
++}
+
+-#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
+- { "GetFileAttributesW", (SYSCALL)GetFileAttributesW, 0 },
+-#else
+- { "GetFileAttributesW", (SYSCALL)0, 0 },
+-#endif
++/*
++** Shutdown the operating system interface.
++**
++** Some operating systems might need to do some cleanup in this routine,
++** to release dynamically allocated objects. But not on unix.
++** This routine is a no-op for unix.
++*/
++SQLITE_API int sqlite3_os_end(void){
++ return SQLITE_OK;
++}
++
++#endif /* SQLITE_OS_UNIX */
+
+-#define osGetFileAttributesW ((DWORD(WINAPI*)(LPCWSTR))aSyscall[21].pCurrent)
++/************** End of os_unix.c *********************************************/
++/************** Begin file os_win.c ******************************************/
++/*
++** 2004 May 22
++**
++** 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 Windows.
++*/
++#if SQLITE_OS_WIN /* This file is used for Windows only */
+
+-#if defined(SQLITE_WIN32_HAS_WIDE)
+- { "GetFileAttributesExW", (SYSCALL)GetFileAttributesExW, 0 },
+-#else
+- { "GetFileAttributesExW", (SYSCALL)0, 0 },
++#ifdef __CYGWIN__
++# include <sys/cygwin.h>
+ #endif
+
+-#define osGetFileAttributesExW ((BOOL(WINAPI*)(LPCWSTR,GET_FILEEX_INFO_LEVELS, \
+- LPVOID))aSyscall[22].pCurrent)
++/*
++** Include code that is common to all os_*.c files
++*/
++/************** Include os_common.h in the middle of os_win.c ****************/
++/************** Begin file os_common.h ***************************************/
++/*
++** 2004 May 22
++**
++** 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 macros and a little bit of code that is common to
++** all of the platform-specific files (os_*.c) and is #included into those
++** files.
++**
++** This file should be #included by the os_*.c files only. It is not a
++** general purpose header file.
++*/
++#ifndef _OS_COMMON_H_
++#define _OS_COMMON_H_
+
+-#if !SQLITE_OS_WINRT
+- { "GetFileSize", (SYSCALL)GetFileSize, 0 },
+-#else
+- { "GetFileSize", (SYSCALL)0, 0 },
++/*
++** At least two bugs have slipped in because we changed the MEMORY_DEBUG
++** macro to SQLITE_DEBUG and some older makefiles have not yet made the
++** switch. The following code should catch this problem at compile-time.
++*/
++#ifdef MEMORY_DEBUG
++# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead."
+ #endif
+
+-#define osGetFileSize ((DWORD(WINAPI*)(HANDLE,LPDWORD))aSyscall[23].pCurrent)
+-
+-#if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_ANSI)
+- { "GetFullPathNameA", (SYSCALL)GetFullPathNameA, 0 },
++#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
+- { "GetFullPathNameA", (SYSCALL)0, 0 },
++# define OSTRACE(X)
+ #endif
+
+-#define osGetFullPathNameA ((DWORD(WINAPI*)(LPCSTR,DWORD,LPSTR, \
+- LPSTR*))aSyscall[24].pCurrent)
++/*
++** Macros for performance tracing. Normally turned off. Only works
++** on i486 hardware.
++*/
++#ifdef SQLITE_PERFORMANCE_TRACE
+
+-#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
+- { "GetFullPathNameW", (SYSCALL)GetFullPathNameW, 0 },
+-#else
+- { "GetFullPathNameW", (SYSCALL)0, 0 },
+-#endif
++/*
++** hwtime.h contains inline assembler code for implementing
++** high-performance timing routines.
++*/
++/************** Include hwtime.h in the middle of os_common.h ****************/
++/************** Begin file hwtime.h ******************************************/
++/*
++** 2008 May 27
++**
++** 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 inline asm code for retrieving "high-performance"
++** counters for x86 class CPUs.
++*/
++#ifndef _HWTIME_H_
++#define _HWTIME_H_
+
+-#define osGetFullPathNameW ((DWORD(WINAPI*)(LPCWSTR,DWORD,LPWSTR, \
+- LPWSTR*))aSyscall[25].pCurrent)
++/*
++** The following routine only works on pentium-class (or newer) processors.
++** It uses the RDTSC opcode to read the cycle count value out of the
++** processor and returns that value. This can be used for high-res
++** profiling.
++*/
++#if (defined(__GNUC__) || defined(_MSC_VER)) && \
++ (defined(i386) || defined(__i386__) || defined(_M_IX86))
+
+- { "GetLastError", (SYSCALL)GetLastError, 0 },
++ #if defined(__GNUC__)
+
+-#define osGetLastError ((DWORD(WINAPI*)(VOID))aSyscall[26].pCurrent)
++ __inline__ sqlite_uint64 sqlite3Hwtime(void){
++ unsigned int lo, hi;
++ __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
++ return (sqlite_uint64)hi << 32 | lo;
++ }
+
+-#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
++ #elif defined(_MSC_VER)
+
+-#define osGetProcAddressA ((FARPROC(WINAPI*)(HMODULE, \
+- LPCSTR))aSyscall[27].pCurrent)
++ __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){
++ __asm {
++ rdtsc
++ ret ; return value at EDX:EAX
++ }
++ }
+
+-#if !SQLITE_OS_WINRT
+- { "GetSystemInfo", (SYSCALL)GetSystemInfo, 0 },
+-#else
+- { "GetSystemInfo", (SYSCALL)0, 0 },
+-#endif
++ #endif
+
+-#define osGetSystemInfo ((VOID(WINAPI*)(LPSYSTEM_INFO))aSyscall[28].pCurrent)
++#elif (defined(__GNUC__) && defined(__x86_64__))
+
+- { "GetSystemTime", (SYSCALL)GetSystemTime, 0 },
++ __inline__ sqlite_uint64 sqlite3Hwtime(void){
++ unsigned long val;
++ __asm__ __volatile__ ("rdtsc" : "=A" (val));
++ return val;
++ }
++
++#elif (defined(__GNUC__) && defined(__ppc__))
+
+-#define osGetSystemTime ((VOID(WINAPI*)(LPSYSTEMTIME))aSyscall[29].pCurrent)
++ __inline__ sqlite_uint64 sqlite3Hwtime(void){
++ unsigned long long retval;
++ unsigned long junk;
++ __asm__ __volatile__ ("\n\
++ 1: mftbu %1\n\
++ mftb %L0\n\
++ mftbu %0\n\
++ cmpw %0,%1\n\
++ bne 1b"
++ : "=r" (retval), "=r" (junk));
++ return retval;
++ }
+
+-#if !SQLITE_OS_WINCE
+- { "GetSystemTimeAsFileTime", (SYSCALL)GetSystemTimeAsFileTime, 0 },
+ #else
+- { "GetSystemTimeAsFileTime", (SYSCALL)0, 0 },
+-#endif
+
+-#define osGetSystemTimeAsFileTime ((VOID(WINAPI*)( \
+- LPFILETIME))aSyscall[30].pCurrent)
++ #error Need implementation of sqlite3Hwtime() for your platform.
++
++ /*
++ ** To compile without implementing sqlite3Hwtime() for your platform,
++ ** you can remove the above #error and use the following
++ ** stub function. You will lose timing support for many
++ ** of the debugging and testing utilities, but it should at
++ ** least compile and run.
++ */
++SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
+
+-#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)
++#endif /* !defined(_HWTIME_H_) */
+
+-#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
+- { "GetTempPathW", (SYSCALL)GetTempPathW, 0 },
++/************** End of hwtime.h **********************************************/
++/************** Continuing where we left off in os_common.h ******************/
++
++static sqlite_uint64 g_start;
++static sqlite_uint64 g_elapsed;
++#define TIMER_START g_start=sqlite3Hwtime()
++#define TIMER_END g_elapsed=sqlite3Hwtime()-g_start
++#define TIMER_ELAPSED g_elapsed
+ #else
+- { "GetTempPathW", (SYSCALL)0, 0 },
++#define TIMER_START
++#define TIMER_END
++#define TIMER_ELAPSED ((sqlite_uint64)0)
+ #endif
+
+-#define osGetTempPathW ((DWORD(WINAPI*)(DWORD,LPWSTR))aSyscall[32].pCurrent)
+-
+-#if !SQLITE_OS_WINRT
+- { "GetTickCount", (SYSCALL)GetTickCount, 0 },
++/*
++** If we compile with the SQLITE_TEST macro set, then the following block
++** of code will give us the ability to simulate a disk I/O error. This
++** is used for testing the I/O recovery logic.
++*/
++#ifdef SQLITE_TEST
++SQLITE_API int sqlite3_io_error_hit = 0; /* Total number of I/O Errors */
++SQLITE_API int sqlite3_io_error_hardhit = 0; /* Number of non-benign errors */
++SQLITE_API int sqlite3_io_error_pending = 0; /* Count down to first I/O error */
++SQLITE_API int sqlite3_io_error_persist = 0; /* True if I/O errors persist */
++SQLITE_API int sqlite3_io_error_benign = 0; /* True if errors are benign */
++SQLITE_API int sqlite3_diskfull_pending = 0;
++SQLITE_API int sqlite3_diskfull = 0;
++#define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X)
++#define SimulateIOError(CODE) \
++ if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \
++ || sqlite3_io_error_pending-- == 1 ) \
++ { local_ioerr(); CODE; }
++static void local_ioerr(){
++ IOTRACE(("IOERR\n"));
++ sqlite3_io_error_hit++;
++ if( !sqlite3_io_error_benign ) sqlite3_io_error_hardhit++;
++}
++#define SimulateDiskfullError(CODE) \
++ if( sqlite3_diskfull_pending ){ \
++ if( sqlite3_diskfull_pending == 1 ){ \
++ local_ioerr(); \
++ sqlite3_diskfull = 1; \
++ sqlite3_io_error_hit = 1; \
++ CODE; \
++ }else{ \
++ sqlite3_diskfull_pending--; \
++ } \
++ }
+ #else
+- { "GetTickCount", (SYSCALL)0, 0 },
++#define SimulateIOErrorBenign(X)
++#define SimulateIOError(A)
++#define SimulateDiskfullError(A)
+ #endif
+
+-#define osGetTickCount ((DWORD(WINAPI*)(VOID))aSyscall[33].pCurrent)
+-
+-#if defined(SQLITE_WIN32_HAS_ANSI)
+- { "GetVersionExA", (SYSCALL)GetVersionExA, 0 },
++/*
++** When testing, keep a count of the number of open files.
++*/
++#ifdef SQLITE_TEST
++SQLITE_API int sqlite3_open_file_count = 0;
++#define OpenCounter(X) sqlite3_open_file_count+=(X)
+ #else
+- { "GetVersionExA", (SYSCALL)0, 0 },
++#define OpenCounter(X)
+ #endif
+
+-#define osGetVersionExA ((BOOL(WINAPI*)( \
+- LPOSVERSIONINFOA))aSyscall[34].pCurrent)
+-
+- { "HeapAlloc", (SYSCALL)HeapAlloc, 0 },
++#endif /* !defined(_OS_COMMON_H_) */
+
+-#define osHeapAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD, \
+- SIZE_T))aSyscall[35].pCurrent)
++/************** End of os_common.h *******************************************/
++/************** Continuing where we left off in os_win.c *********************/
+
+-#if !SQLITE_OS_WINRT
+- { "HeapCreate", (SYSCALL)HeapCreate, 0 },
+-#else
+- { "HeapCreate", (SYSCALL)0, 0 },
++/*
++** Compiling and using WAL mode requires several APIs that are only
++** available in Windows platforms based on the NT kernel.
++*/
++#if !SQLITE_OS_WINNT && !defined(SQLITE_OMIT_WAL)
++# error "WAL mode requires support from the Windows NT kernel, compile\
++ with SQLITE_OMIT_WAL."
+ #endif
+
+-#define osHeapCreate ((HANDLE(WINAPI*)(DWORD,SIZE_T, \
+- SIZE_T))aSyscall[36].pCurrent)
+-
+-#if !SQLITE_OS_WINRT
+- { "HeapDestroy", (SYSCALL)HeapDestroy, 0 },
+-#else
+- { "HeapDestroy", (SYSCALL)0, 0 },
++/*
++** Are most of the Win32 ANSI APIs available (i.e. with certain exceptions
++** based on the sub-platform)?
++*/
++#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
++# define SQLITE_WIN32_HAS_ANSI
+ #endif
+
+-#define osHeapDestroy ((BOOL(WINAPI*)(HANDLE))aSyscall[37].pCurrent)
+-
+- { "HeapFree", (SYSCALL)HeapFree, 0 },
++/*
++** Are most of the Win32 Unicode APIs available (i.e. with certain exceptions
++** based on the sub-platform)?
++*/
++#if SQLITE_OS_WINCE || SQLITE_OS_WINNT || SQLITE_OS_WINRT
++# define SQLITE_WIN32_HAS_WIDE
++#endif
+
+-#define osHeapFree ((BOOL(WINAPI*)(HANDLE,DWORD,LPVOID))aSyscall[38].pCurrent)
++/*
++** 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)?
++*/
++#if SQLITE_WIN32_FILEMAPPING_API && !defined(SQLITE_OMIT_WAL)
++/*
++** Two of the file mapping APIs are different under WinRT. Figure out which
++** set we need.
++*/
++#if SQLITE_OS_WINRT
++WINBASEAPI HANDLE WINAPI CreateFileMappingFromApp(HANDLE, \
++ LPSECURITY_ATTRIBUTES, ULONG, ULONG64, LPCWSTR);
+
+- { "HeapReAlloc", (SYSCALL)HeapReAlloc, 0 },
++WINBASEAPI LPVOID WINAPI MapViewOfFileFromApp(HANDLE, ULONG, ULONG64, SIZE_T);
++#else
++#if defined(SQLITE_WIN32_HAS_ANSI)
++WINBASEAPI HANDLE WINAPI CreateFileMappingA(HANDLE, LPSECURITY_ATTRIBUTES, \
++ DWORD, DWORD, DWORD, LPCSTR);
++#endif /* defined(SQLITE_WIN32_HAS_ANSI) */
+
+-#define osHeapReAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD,LPVOID, \
+- SIZE_T))aSyscall[39].pCurrent)
++#if defined(SQLITE_WIN32_HAS_WIDE)
++WINBASEAPI HANDLE WINAPI CreateFileMappingW(HANDLE, LPSECURITY_ATTRIBUTES, \
++ DWORD, DWORD, DWORD, LPCWSTR);
++#endif /* defined(SQLITE_WIN32_HAS_WIDE) */
+
+- { "HeapSize", (SYSCALL)HeapSize, 0 },
++WINBASEAPI LPVOID WINAPI MapViewOfFile(HANDLE, DWORD, DWORD, DWORD, SIZE_T);
++#endif /* SQLITE_OS_WINRT */
+
+-#define osHeapSize ((SIZE_T(WINAPI*)(HANDLE,DWORD, \
+- LPCVOID))aSyscall[40].pCurrent)
++/*
++** This file mapping API is common to both Win32 and WinRT.
++*/
++WINBASEAPI BOOL WINAPI UnmapViewOfFile(LPCVOID);
++#endif /* SQLITE_WIN32_FILEMAPPING_API && !defined(SQLITE_OMIT_WAL) */
+
+-#if !SQLITE_OS_WINRT
+- { "HeapValidate", (SYSCALL)HeapValidate, 0 },
+-#else
+- { "HeapValidate", (SYSCALL)0, 0 },
++/*
++** Macro to find the minimum of two numeric values.
++*/
++#ifndef MIN
++# define MIN(x,y) ((x)<(y)?(x):(y))
+ #endif
+
+-#define osHeapValidate ((BOOL(WINAPI*)(HANDLE,DWORD, \
+- LPCVOID))aSyscall[41].pCurrent)
+-
+-#if defined(SQLITE_WIN32_HAS_ANSI) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
+- { "LoadLibraryA", (SYSCALL)LoadLibraryA, 0 },
+-#else
+- { "LoadLibraryA", (SYSCALL)0, 0 },
++/*
++** Some Microsoft compilers lack this definition.
++*/
++#ifndef INVALID_FILE_ATTRIBUTES
++# define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
+ #endif
+
+-#define osLoadLibraryA ((HMODULE(WINAPI*)(LPCSTR))aSyscall[42].pCurrent)
+-
+-#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \
+- !defined(SQLITE_OMIT_LOAD_EXTENSION)
+- { "LoadLibraryW", (SYSCALL)LoadLibraryW, 0 },
+-#else
+- { "LoadLibraryW", (SYSCALL)0, 0 },
++#ifndef FILE_FLAG_MASK
++# define FILE_FLAG_MASK (0xFF3C0000)
+ #endif
+
+-#define osLoadLibraryW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[43].pCurrent)
+-
+-#if !SQLITE_OS_WINRT
+- { "LocalFree", (SYSCALL)LocalFree, 0 },
+-#else
+- { "LocalFree", (SYSCALL)0, 0 },
++#ifndef FILE_ATTRIBUTE_MASK
++# define FILE_ATTRIBUTE_MASK (0x0003FFF7)
+ #endif
+
+-#define osLocalFree ((HLOCAL(WINAPI*)(HLOCAL))aSyscall[44].pCurrent)
+-
+-#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
+- { "LockFile", (SYSCALL)LockFile, 0 },
+-#else
+- { "LockFile", (SYSCALL)0, 0 },
++#ifndef SQLITE_OMIT_WAL
++/* Forward references */
++typedef struct winShm winShm; /* A connection to shared-memory */
++typedef struct winShmNode winShmNode; /* A region of shared-memory */
+ #endif
+
+-#ifndef osLockFile
+-#define osLockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
+- DWORD))aSyscall[45].pCurrent)
++/*
++** WinCE lacks native support for file locking so we have to fake it
++** with some code of our own.
++*/
++#if SQLITE_OS_WINCE
++typedef struct winceLock {
++ int nReaders; /* Number of reader locks obtained */
++ BOOL bPending; /* Indicates a pending lock has been obtained */
++ BOOL bReserved; /* Indicates a reserved lock has been obtained */
++ BOOL bExclusive; /* Indicates an exclusive lock has been obtained */
++} winceLock;
+ #endif
+
+-#if !SQLITE_OS_WINCE
+- { "LockFileEx", (SYSCALL)LockFileEx, 0 },
+-#else
+- { "LockFileEx", (SYSCALL)0, 0 },
++/*
++** The winFile structure is a subclass of sqlite3_file* specific to the win32
++** portability layer.
++*/
++typedef struct winFile winFile;
++struct winFile {
++ const sqlite3_io_methods *pMethod; /*** Must be first ***/
++ sqlite3_vfs *pVfs; /* The VFS used to open this file */
++ HANDLE h; /* Handle for accessing the file */
++ u8 locktype; /* Type of lock currently held on this file */
++ short sharedLockByte; /* Randomly chosen byte used as a shared lock */
++ u8 ctrlFlags; /* Flags. See WINFILE_* below */
++ DWORD lastErrno; /* The Windows errno from the last I/O error */
++#ifndef SQLITE_OMIT_WAL
++ winShm *pShm; /* Instance of shared memory on this file */
+ #endif
+-
+-#ifndef osLockFileEx
+-#define osLockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD,DWORD, \
+- LPOVERLAPPED))aSyscall[46].pCurrent)
++ const char *zPath; /* Full pathname of this file */
++ int szChunk; /* Chunk size configured by FCNTL_CHUNK_SIZE */
++#if SQLITE_OS_WINCE
++ LPWSTR zDeleteOnClose; /* Name of file to delete when closing */
++ HANDLE hMutex; /* Mutex used to control access to shared lock */
++ HANDLE hShared; /* Shared memory segment used for locking */
++ winceLock local; /* Locks obtained by this instance of winFile */
++ winceLock *shared; /* Global shared lock memory for the file */
+ #endif
+-
+-#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && !defined(SQLITE_OMIT_WAL))
+- { "MapViewOfFile", (SYSCALL)MapViewOfFile, 0 },
+-#else
+- { "MapViewOfFile", (SYSCALL)0, 0 },
++#if SQLITE_MAX_MMAP_SIZE>0
++ int nFetchOut; /* Number of outstanding xFetch references */
++ HANDLE hMap; /* Handle for accessing memory mapping */
++ void *pMapRegion; /* Area memory mapped */
++ sqlite3_int64 mmapSize; /* Usable size of mapped region */
++ sqlite3_int64 mmapSizeActual; /* Actual size of mapped region */
++ sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */
+ #endif
++};
+
+-#define osMapViewOfFile ((LPVOID(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
+- SIZE_T))aSyscall[47].pCurrent)
+-
+- { "MultiByteToWideChar", (SYSCALL)MultiByteToWideChar, 0 },
+-
+-#define osMultiByteToWideChar ((int(WINAPI*)(UINT,DWORD,LPCSTR,int,LPWSTR, \
+- int))aSyscall[48].pCurrent)
+-
+- { "QueryPerformanceCounter", (SYSCALL)QueryPerformanceCounter, 0 },
+-
+-#define osQueryPerformanceCounter ((BOOL(WINAPI*)( \
+- LARGE_INTEGER*))aSyscall[49].pCurrent)
+-
+- { "ReadFile", (SYSCALL)ReadFile, 0 },
+-
+-#define osReadFile ((BOOL(WINAPI*)(HANDLE,LPVOID,DWORD,LPDWORD, \
+- LPOVERLAPPED))aSyscall[50].pCurrent)
+-
+- { "SetEndOfFile", (SYSCALL)SetEndOfFile, 0 },
+-
+-#define osSetEndOfFile ((BOOL(WINAPI*)(HANDLE))aSyscall[51].pCurrent)
++/*
++** Allowed values for winFile.ctrlFlags
++*/
++#define WINFILE_RDONLY 0x02 /* Connection is read only */
++#define WINFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */
++#define WINFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */
+
+-#if !SQLITE_OS_WINRT
+- { "SetFilePointer", (SYSCALL)SetFilePointer, 0 },
+-#else
+- { "SetFilePointer", (SYSCALL)0, 0 },
++/*
++ * The size of the buffer used by sqlite3_win32_write_debug().
++ */
++#ifndef SQLITE_WIN32_DBG_BUF_SIZE
++# define SQLITE_WIN32_DBG_BUF_SIZE ((int)(4096-sizeof(DWORD)))
+ #endif
+
+-#define osSetFilePointer ((DWORD(WINAPI*)(HANDLE,LONG,PLONG, \
+- DWORD))aSyscall[52].pCurrent)
+-
+-#if !SQLITE_OS_WINRT
+- { "Sleep", (SYSCALL)Sleep, 0 },
+-#else
+- { "Sleep", (SYSCALL)0, 0 },
++/*
++ * The value used with sqlite3_win32_set_directory() to specify that
++ * the data directory should be changed.
++ */
++#ifndef SQLITE_WIN32_DATA_DIRECTORY_TYPE
++# define SQLITE_WIN32_DATA_DIRECTORY_TYPE (1)
+ #endif
+
+-#define osSleep ((VOID(WINAPI*)(DWORD))aSyscall[53].pCurrent)
+-
+- { "SystemTimeToFileTime", (SYSCALL)SystemTimeToFileTime, 0 },
++/*
++ * The value used with sqlite3_win32_set_directory() to specify that
++ * the temporary directory should be changed.
++ */
++#ifndef SQLITE_WIN32_TEMP_DIRECTORY_TYPE
++# define SQLITE_WIN32_TEMP_DIRECTORY_TYPE (2)
++#endif
+
+-#define osSystemTimeToFileTime ((BOOL(WINAPI*)(CONST SYSTEMTIME*, \
+- LPFILETIME))aSyscall[54].pCurrent)
++/*
++ * If compiled with SQLITE_WIN32_MALLOC on Windows, we will use the
++ * various Win32 API heap functions instead of our own.
++ */
++#ifdef SQLITE_WIN32_MALLOC
+
+-#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
+- { "UnlockFile", (SYSCALL)UnlockFile, 0 },
+-#else
+- { "UnlockFile", (SYSCALL)0, 0 },
++/*
++ * If this is non-zero, an isolated heap will be created by the native Win32
++ * allocator subsystem; otherwise, the default process heap will be used. This
++ * setting has no effect when compiling for WinRT. By default, this is enabled
++ * and an isolated heap will be created to store all allocated data.
++ *
++ ******************************************************************************
++ * WARNING: It is important to note that when this setting is non-zero and the
++ * winMemShutdown function is called (e.g. by the sqlite3_shutdown
++ * function), all data that was allocated using the isolated heap will
++ * be freed immediately and any attempt to access any of that freed
++ * data will almost certainly result in an immediate access violation.
++ ******************************************************************************
++ */
++#ifndef SQLITE_WIN32_HEAP_CREATE
++# define SQLITE_WIN32_HEAP_CREATE (TRUE)
+ #endif
+
+-#ifndef osUnlockFile
+-#define osUnlockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
+- DWORD))aSyscall[55].pCurrent)
++/*
++ * The initial size of the Win32-specific heap. This value may be zero.
++ */
++#ifndef SQLITE_WIN32_HEAP_INIT_SIZE
++# define SQLITE_WIN32_HEAP_INIT_SIZE ((SQLITE_DEFAULT_CACHE_SIZE) * \
++ (SQLITE_DEFAULT_PAGE_SIZE) + 4194304)
+ #endif
+
+-#if !SQLITE_OS_WINCE
+- { "UnlockFileEx", (SYSCALL)UnlockFileEx, 0 },
+-#else
+- { "UnlockFileEx", (SYSCALL)0, 0 },
++/*
++ * The maximum size of the Win32-specific heap. This value may be zero.
++ */
++#ifndef SQLITE_WIN32_HEAP_MAX_SIZE
++# define SQLITE_WIN32_HEAP_MAX_SIZE (0)
+ #endif
+
+-#define osUnlockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
+- LPOVERLAPPED))aSyscall[56].pCurrent)
+-
+-#if SQLITE_OS_WINCE || !defined(SQLITE_OMIT_WAL)
+- { "UnmapViewOfFile", (SYSCALL)UnmapViewOfFile, 0 },
+-#else
+- { "UnmapViewOfFile", (SYSCALL)0, 0 },
++/*
++ * The extra flags to use in calls to the Win32 heap APIs. This value may be
++ * zero for the default behavior.
++ */
++#ifndef SQLITE_WIN32_HEAP_FLAGS
++# define SQLITE_WIN32_HEAP_FLAGS (0)
+ #endif
+
+-#define osUnmapViewOfFile ((BOOL(WINAPI*)(LPCVOID))aSyscall[57].pCurrent)
+-
+- { "WideCharToMultiByte", (SYSCALL)WideCharToMultiByte, 0 },
+-
+-#define osWideCharToMultiByte ((int(WINAPI*)(UINT,DWORD,LPCWSTR,int,LPSTR,int, \
+- LPCSTR,LPBOOL))aSyscall[58].pCurrent)
+-
+- { "WriteFile", (SYSCALL)WriteFile, 0 },
+-
+-#define osWriteFile ((BOOL(WINAPI*)(HANDLE,LPCVOID,DWORD,LPDWORD, \
+- LPOVERLAPPED))aSyscall[59].pCurrent)
++/*
++** The winMemData structure stores information required by the Win32-specific
++** sqlite3_mem_methods implementation.
++*/
++typedef struct winMemData winMemData;
++struct winMemData {
++#ifndef NDEBUG
++ u32 magic; /* Magic number to detect structure corruption. */
++#endif
++ HANDLE hHeap; /* The handle to our heap. */
++ BOOL bOwned; /* Do we own the heap (i.e. destroy it on shutdown)? */
++};
+
+-#if SQLITE_OS_WINRT
+- { "CreateEventExW", (SYSCALL)CreateEventExW, 0 },
+-#else
+- { "CreateEventExW", (SYSCALL)0, 0 },
++#ifndef NDEBUG
++#define WINMEM_MAGIC 0x42b2830b
+ #endif
+
+-#define osCreateEventExW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,LPCWSTR, \
+- DWORD,DWORD))aSyscall[60].pCurrent)
++static struct winMemData win_mem_data = {
++#ifndef NDEBUG
++ WINMEM_MAGIC,
++#endif
++ NULL, FALSE
++};
+
+-#if !SQLITE_OS_WINRT
+- { "WaitForSingleObject", (SYSCALL)WaitForSingleObject, 0 },
++#ifndef NDEBUG
++#define winMemAssertMagic() assert( win_mem_data.magic==WINMEM_MAGIC )
+ #else
+- { "WaitForSingleObject", (SYSCALL)0, 0 },
++#define winMemAssertMagic()
+ #endif
+
+-#define osWaitForSingleObject ((DWORD(WINAPI*)(HANDLE, \
+- DWORD))aSyscall[61].pCurrent)
++#define winMemGetHeap() win_mem_data.hHeap
+
+-#if SQLITE_OS_WINRT
+- { "WaitForSingleObjectEx", (SYSCALL)WaitForSingleObjectEx, 0 },
+-#else
+- { "WaitForSingleObjectEx", (SYSCALL)0, 0 },
+-#endif
++static void *winMemMalloc(int nBytes);
++static void winMemFree(void *pPrior);
++static void *winMemRealloc(void *pPrior, int nBytes);
++static int winMemSize(void *p);
++static int winMemRoundup(int n);
++static int winMemInit(void *pAppData);
++static void winMemShutdown(void *pAppData);
+
+-#define osWaitForSingleObjectEx ((DWORD(WINAPI*)(HANDLE,DWORD, \
+- BOOL))aSyscall[62].pCurrent)
++SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetWin32(void);
++#endif /* SQLITE_WIN32_MALLOC */
+
+-#if SQLITE_OS_WINRT
+- { "SetFilePointerEx", (SYSCALL)SetFilePointerEx, 0 },
++/*
++** The following variable is (normally) set once and never changes
++** thereafter. It records whether the operating system is Win9x
++** or WinNT.
++**
++** 0: Operating system unknown.
++** 1: Operating system is Win9x.
++** 2: Operating system is WinNT.
++**
++** In order to facilitate testing on a WinNT system, the test fixture
++** can manually set this value to 1 to emulate Win98 behavior.
++*/
++#ifdef SQLITE_TEST
++SQLITE_API int sqlite3_os_type = 0;
+ #else
+- { "SetFilePointerEx", (SYSCALL)0, 0 },
++static int sqlite3_os_type = 0;
+ #endif
+
+-#define osSetFilePointerEx ((BOOL(WINAPI*)(HANDLE,LARGE_INTEGER, \
+- PLARGE_INTEGER,DWORD))aSyscall[63].pCurrent)
+-
+-#if SQLITE_OS_WINRT
+- { "GetFileInformationByHandleEx", (SYSCALL)GetFileInformationByHandleEx, 0 },
+-#else
+- { "GetFileInformationByHandleEx", (SYSCALL)0, 0 },
++#ifndef SYSCALL
++# define SYSCALL sqlite3_syscall_ptr
+ #endif
+
+-#define osGetFileInformationByHandleEx ((BOOL(WINAPI*)(HANDLE, \
+- FILE_INFO_BY_HANDLE_CLASS,LPVOID,DWORD))aSyscall[64].pCurrent)
++/*
++** This function is not available on Windows CE or WinRT.
++ */
+
+-#if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_WAL)
+- { "MapViewOfFileFromApp", (SYSCALL)MapViewOfFileFromApp, 0 },
+-#else
+- { "MapViewOfFileFromApp", (SYSCALL)0, 0 },
++#if SQLITE_OS_WINCE || SQLITE_OS_WINRT
++# define osAreFileApisANSI() 1
+ #endif
+
+-#define osMapViewOfFileFromApp ((LPVOID(WINAPI*)(HANDLE,ULONG,ULONG64, \
+- SIZE_T))aSyscall[65].pCurrent)
+-
+-#if SQLITE_OS_WINRT
+- { "CreateFile2", (SYSCALL)CreateFile2, 0 },
++/*
++** Many system calls are accessed through pointer-to-functions so that
++** they may be overridden at runtime to facilitate fault injection during
++** testing and sandboxing. The following array holds the names and pointers
++** to all overrideable system calls.
++*/
++static struct win_syscall {
++ const char *zName; /* Name of the system call */
++ sqlite3_syscall_ptr pCurrent; /* Current value of the system call */
++ sqlite3_syscall_ptr pDefault; /* Default value */
++} aSyscall[] = {
++#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
++ { "AreFileApisANSI", (SYSCALL)AreFileApisANSI, 0 },
+ #else
+- { "CreateFile2", (SYSCALL)0, 0 },
++ { "AreFileApisANSI", (SYSCALL)0, 0 },
+ #endif
+
+-#define osCreateFile2 ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD,DWORD, \
+- LPCREATEFILE2_EXTENDED_PARAMETERS))aSyscall[66].pCurrent)
++#ifndef osAreFileApisANSI
++#define osAreFileApisANSI ((BOOL(WINAPI*)(VOID))aSyscall[0].pCurrent)
++#endif
+
+-#if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_LOAD_EXTENSION)
+- { "LoadPackagedLibrary", (SYSCALL)LoadPackagedLibrary, 0 },
++#if SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE)
++ { "CharLowerW", (SYSCALL)CharLowerW, 0 },
+ #else
+- { "LoadPackagedLibrary", (SYSCALL)0, 0 },
++ { "CharLowerW", (SYSCALL)0, 0 },
+ #endif
+
+-#define osLoadPackagedLibrary ((HMODULE(WINAPI*)(LPCWSTR, \
+- DWORD))aSyscall[67].pCurrent)
++#define osCharLowerW ((LPWSTR(WINAPI*)(LPWSTR))aSyscall[1].pCurrent)
+
+-#if SQLITE_OS_WINRT
+- { "GetTickCount64", (SYSCALL)GetTickCount64, 0 },
++#if SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE)
++ { "CharUpperW", (SYSCALL)CharUpperW, 0 },
+ #else
+- { "GetTickCount64", (SYSCALL)0, 0 },
++ { "CharUpperW", (SYSCALL)0, 0 },
+ #endif
+
+-#define osGetTickCount64 ((ULONGLONG(WINAPI*)(VOID))aSyscall[68].pCurrent)
++#define osCharUpperW ((LPWSTR(WINAPI*)(LPWSTR))aSyscall[2].pCurrent)
+
+-#if SQLITE_OS_WINRT
+- { "GetNativeSystemInfo", (SYSCALL)GetNativeSystemInfo, 0 },
+-#else
+- { "GetNativeSystemInfo", (SYSCALL)0, 0 },
+-#endif
++ { "CloseHandle", (SYSCALL)CloseHandle, 0 },
+
+-#define osGetNativeSystemInfo ((VOID(WINAPI*)( \
+- LPSYSTEM_INFO))aSyscall[69].pCurrent)
++#define osCloseHandle ((BOOL(WINAPI*)(HANDLE))aSyscall[3].pCurrent)
+
+ #if defined(SQLITE_WIN32_HAS_ANSI)
+- { "OutputDebugStringA", (SYSCALL)OutputDebugStringA, 0 },
++ { "CreateFileA", (SYSCALL)CreateFileA, 0 },
+ #else
+- { "OutputDebugStringA", (SYSCALL)0, 0 },
++ { "CreateFileA", (SYSCALL)0, 0 },
+ #endif
+
+-#define osOutputDebugStringA ((VOID(WINAPI*)(LPCSTR))aSyscall[70].pCurrent)
++#define osCreateFileA ((HANDLE(WINAPI*)(LPCSTR,DWORD,DWORD, \
++ LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[4].pCurrent)
+
+-#if defined(SQLITE_WIN32_HAS_WIDE)
+- { "OutputDebugStringW", (SYSCALL)OutputDebugStringW, 0 },
++#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
++ { "CreateFileW", (SYSCALL)CreateFileW, 0 },
+ #else
+- { "OutputDebugStringW", (SYSCALL)0, 0 },
++ { "CreateFileW", (SYSCALL)0, 0 },
+ #endif
+
+-#define osOutputDebugStringW ((VOID(WINAPI*)(LPCWSTR))aSyscall[71].pCurrent)
+-
+- { "GetProcessHeap", (SYSCALL)GetProcessHeap, 0 },
+-
+-#define osGetProcessHeap ((HANDLE(WINAPI*)(VOID))aSyscall[72].pCurrent)
++#define osCreateFileW ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD, \
++ LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[5].pCurrent)
+
+-#if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_WAL)
+- { "CreateFileMappingFromApp", (SYSCALL)CreateFileMappingFromApp, 0 },
++#if (!SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_ANSI) && \
++ !defined(SQLITE_OMIT_WAL))
++ { "CreateFileMappingA", (SYSCALL)CreateFileMappingA, 0 },
+ #else
+- { "CreateFileMappingFromApp", (SYSCALL)0, 0 },
++ { "CreateFileMappingA", (SYSCALL)0, 0 },
+ #endif
+
+-#define osCreateFileMappingFromApp ((HANDLE(WINAPI*)(HANDLE, \
+- LPSECURITY_ATTRIBUTES,ULONG,ULONG64,LPCWSTR))aSyscall[73].pCurrent)
+-
+-}; /* End of the overrideable system calls */
+-
+-/*
+-** 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;
+-
+- 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;
+-}
+-
+-/*
+-** 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;
+-
+- 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;
+-}
+-
+-/*
+-** 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;
+-
+- 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;
+-}
+-
+-/*
+-** This function outputs the specified (ANSI) string to the Win32 debugger
+-** (if available).
+-*/
++#define osCreateFileMappingA ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \
++ DWORD,DWORD,DWORD,LPCSTR))aSyscall[6].pCurrent)
+
+-SQLITE_API void 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);
++#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \
++ !defined(SQLITE_OMIT_WAL))
++ { "CreateFileMappingW", (SYSCALL)CreateFileMappingW, 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);
+- }
+-#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;
++ { "CreateFileMappingW", (SYSCALL)0, 0 },
+ #endif
+
+-SQLITE_API void 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
+-}
++#define osCreateFileMappingW ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \
++ DWORD,DWORD,DWORD,LPCWSTR))aSyscall[7].pCurrent)
+
+-/*
+-** 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 SQLITE_OS_WINCE || SQLITE_OS_WINRT
+-# define isNT() (1)
+-#elif !defined(SQLITE_WIN32_HAS_WIDE)
+-# define isNT() (0)
++#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
++ { "CreateMutexW", (SYSCALL)CreateMutexW, 0 },
+ #else
+- static int isNT(void){
+- if( sqlite3_os_type==0 ){
+- OSVERSIONINFOA sInfo;
+- sInfo.dwOSVersionInfoSize = sizeof(sInfo);
+- osGetVersionExA(&sInfo);
+- sqlite3_os_type = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1;
+- }
+- return sqlite3_os_type==2;
+- }
++ { "CreateMutexW", (SYSCALL)0, 0 },
+ #endif
+
+-#ifdef SQLITE_WIN32_MALLOC
+-/*
+-** Allocate nBytes of memory.
+-*/
+-static void *winMemMalloc(int nBytes){
+- HANDLE hHeap;
+- void *p;
++#define osCreateMutexW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,BOOL, \
++ LPCWSTR))aSyscall[8].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 defined(SQLITE_WIN32_HAS_ANSI)
++ { "DeleteFileA", (SYSCALL)DeleteFileA, 0 },
++#else
++ { "DeleteFileA", (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 (%d), heap=%p",
+- nBytes, osGetLastError(), (void*)hHeap);
+- }
+- return p;
+-}
+
+-/*
+-** Free memory.
+-*/
+-static void winMemFree(void *pPrior){
+- HANDLE hHeap;
++#define osDeleteFileA ((BOOL(WINAPI*)(LPCSTR))aSyscall[9].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_WIDE)
++ { "DeleteFileW", (SYSCALL)DeleteFileW, 0 },
++#else
++ { "DeleteFileW", (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 (%d), 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 osDeleteFileW ((BOOL(WINAPI*)(LPCWSTR))aSyscall[10].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_WINCE
++ { "FileTimeToLocalFileTime", (SYSCALL)FileTimeToLocalFileTime, 0 },
++#else
++ { "FileTimeToLocalFileTime", (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 (%d), 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 osFileTimeToLocalFileTime ((BOOL(WINAPI*)(CONST FILETIME*, \
++ LPFILETIME))aSyscall[11].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
++ { "FileTimeToSystemTime", (SYSCALL)FileTimeToSystemTime, 0 },
++#else
++ { "FileTimeToSystemTime", (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 (%d), 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 osFileTimeToSystemTime ((BOOL(WINAPI*)(CONST FILETIME*, \
++ LPSYSTEMTIME))aSyscall[12].pCurrent)
+
+-/*
+-** Initialize this module.
+-*/
+-static int winMemInit(void *pAppData){
+- winMemData *pWinMemData = (winMemData *)pAppData;
++ { "FlushFileBuffers", (SYSCALL)FlushFileBuffers, 0 },
+
+- if( !pWinMemData ) return SQLITE_ERROR;
+- assert( pWinMemData->magic==WINMEM_MAGIC );
++#define osFlushFileBuffers ((BOOL(WINAPI*)(HANDLE))aSyscall[13].pCurrent)
+
+-#if !SQLITE_OS_WINRT && SQLITE_WIN32_HEAP_CREATE
+- if( !pWinMemData->hHeap ){
+- pWinMemData->hHeap = osHeapCreate(SQLITE_WIN32_HEAP_FLAGS,
+- SQLITE_WIN32_HEAP_INIT_SIZE,
+- SQLITE_WIN32_HEAP_MAX_SIZE);
+- if( !pWinMemData->hHeap ){
+- sqlite3_log(SQLITE_NOMEM,
+- "failed to HeapCreate (%d), flags=%u, initSize=%u, maxSize=%u",
+- osGetLastError(), SQLITE_WIN32_HEAP_FLAGS,
+- SQLITE_WIN32_HEAP_INIT_SIZE, SQLITE_WIN32_HEAP_MAX_SIZE);
+- return SQLITE_NOMEM;
+- }
+- pWinMemData->bOwned = TRUE;
+- assert( pWinMemData->bOwned );
+- }
++#if defined(SQLITE_WIN32_HAS_ANSI)
++ { "FormatMessageA", (SYSCALL)FormatMessageA, 0 },
+ #else
+- pWinMemData->hHeap = osGetProcessHeap();
+- if( !pWinMemData->hHeap ){
+- sqlite3_log(SQLITE_NOMEM,
+- "failed to GetProcessHeap (%d)", osGetLastError());
+- return SQLITE_NOMEM;
+- }
+- pWinMemData->bOwned = FALSE;
+- assert( !pWinMemData->bOwned );
++ { "FormatMessageA", (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) );
++
++#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
+- return SQLITE_OK;
+-}
+
+-/*
+-** Deinitialize this module.
+-*/
+-static void winMemShutdown(void *pAppData){
+- winMemData *pWinMemData = (winMemData *)pAppData;
++#define osFormatMessageW ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPWSTR, \
++ DWORD,va_list*))aSyscall[15].pCurrent)
+
+- if( !pWinMemData ) return;
+- 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) );
++#if !defined(SQLITE_OMIT_LOAD_EXTENSION)
++ { "FreeLibrary", (SYSCALL)FreeLibrary, 0 },
++#else
++ { "FreeLibrary", (SYSCALL)0, 0 },
+ #endif
+- if( pWinMemData->bOwned ){
+- if( !osHeapDestroy(pWinMemData->hHeap) ){
+- sqlite3_log(SQLITE_NOMEM, "failed to HeapDestroy (%d), 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 osFreeLibrary ((BOOL(WINAPI*)(HMODULE))aSyscall[16].pCurrent)
+
+-SQLITE_PRIVATE void sqlite3MemSetDefault(void){
+- sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetWin32());
+-}
+-#endif /* SQLITE_WIN32_MALLOC */
++ { "GetCurrentProcessId", (SYSCALL)GetCurrentProcessId, 0 },
+
+-/*
+-** Convert a UTF-8 string to Microsoft Unicode (UTF-16?).
+-**
+-** Space to hold the returned string is obtained from malloc.
+-*/
+-static LPWSTR utf8ToUnicode(const char *zFilename){
+- int nChar;
+- LPWSTR zWideFilename;
++#define osGetCurrentProcessId ((DWORD(WINAPI*)(VOID))aSyscall[17].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;
+-}
++#if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_ANSI)
++ { "GetDiskFreeSpaceA", (SYSCALL)GetDiskFreeSpaceA, 0 },
++#else
++ { "GetDiskFreeSpaceA", (SYSCALL)0, 0 },
++#endif
+
+-/*
+-** Convert Microsoft Unicode to UTF-8. Space to hold the returned string is
+-** obtained from sqlite3_malloc().
+-*/
+-static char *unicodeToUtf8(LPCWSTR zWideFilename){
+- int nByte;
+- char *zFilename;
++#define osGetDiskFreeSpaceA ((BOOL(WINAPI*)(LPCSTR,LPDWORD,LPDWORD,LPDWORD, \
++ LPDWORD))aSyscall[18].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 && defined(SQLITE_WIN32_HAS_WIDE)
++ { "GetDiskFreeSpaceW", (SYSCALL)GetDiskFreeSpaceW, 0 },
++#else
++ { "GetDiskFreeSpaceW", (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 mbcsToUnicode(const char *zFilename){
+- int nByte;
+- LPWSTR zMbcsFilename;
+- int codepage = osAreFileApisANSI() ? CP_ACP : CP_OEMCP;
++#define osGetDiskFreeSpaceW ((BOOL(WINAPI*)(LPCWSTR,LPDWORD,LPDWORD,LPDWORD, \
++ LPDWORD))aSyscall[19].pCurrent)
+
+- 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 defined(SQLITE_WIN32_HAS_ANSI)
++ { "GetFileAttributesA", (SYSCALL)GetFileAttributesA, 0 },
++#else
++ { "GetFileAttributesA", (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 *unicodeToMbcs(LPCWSTR zWideFilename){
+- int nByte;
+- char *zFilename;
+- int codepage = osAreFileApisANSI() ? CP_ACP : CP_OEMCP;
++#define osGetFileAttributesA ((DWORD(WINAPI*)(LPCSTR))aSyscall[20].pCurrent)
+
+- 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;
+-}
++#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
++ { "GetFileAttributesW", (SYSCALL)GetFileAttributesW, 0 },
++#else
++ { "GetFileAttributesW", (SYSCALL)0, 0 },
++#endif
+
+-/*
+-** 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){
+- char *zFilenameUtf8;
+- LPWSTR zTmpWide;
++#define osGetFileAttributesW ((DWORD(WINAPI*)(LPCWSTR))aSyscall[21].pCurrent)
+
+- zTmpWide = mbcsToUnicode(zFilename);
+- if( zTmpWide==0 ){
+- return 0;
+- }
+- zFilenameUtf8 = unicodeToUtf8(zTmpWide);
+- sqlite3_free(zTmpWide);
+- return zFilenameUtf8;
+-}
++#if defined(SQLITE_WIN32_HAS_WIDE)
++ { "GetFileAttributesExW", (SYSCALL)GetFileAttributesExW, 0 },
++#else
++ { "GetFileAttributesExW", (SYSCALL)0, 0 },
++#endif
+
+-/*
+-** 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){
+- char *zFilenameMbcs;
+- LPWSTR zTmpWide;
++#define osGetFileAttributesExW ((BOOL(WINAPI*)(LPCWSTR,GET_FILEEX_INFO_LEVELS, \
++ LPVOID))aSyscall[22].pCurrent)
+
+- zTmpWide = utf8ToUnicode(zFilename);
+- if( zTmpWide==0 ){
+- return 0;
+- }
+- zFilenameMbcs = unicodeToMbcs(zTmpWide);
+- sqlite3_free(zTmpWide);
+- return zFilenameMbcs;
+-}
++#if !SQLITE_OS_WINRT
++ { "GetFileSize", (SYSCALL)GetFileSize, 0 },
++#else
++ { "GetFileSize", (SYSCALL)0, 0 },
++#endif
+
+-/*
+-** 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 sqlite3_win32_set_directory(DWORD type, LPCWSTR zValue){
+- char **ppDirectory = 0;
+-#ifndef SQLITE_OMIT_AUTOINIT
+- int rc = sqlite3_initialize();
+- if( rc ) return rc;
++#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
+- 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 = unicodeToUtf8(zValue);
+- if ( zValueUtf8==0 ){
+- return SQLITE_NOMEM;
+- }
+- }
+- sqlite3_free(*ppDirectory);
+- *ppDirectory = zValueUtf8;
+- return SQLITE_OK;
+- }
+- return SQLITE_ERROR;
+-}
+
+-/*
+-** The return value of getLastErrorMsg
+-** is zero if the error message fits in the buffer, or non-zero
+-** otherwise (if the message was truncated).
+-*/
+-static int getLastErrorMsg(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 osGetFullPathNameA ((DWORD(WINAPI*)(LPCSTR,DWORD,LPSTR, \
++ LPSTR*))aSyscall[24].pCurrent)
+
+- if( isNT() ){
+-#if SQLITE_OS_WINRT
+- WCHAR zTempWide[MAX_PATH+1]; /* NOTE: Somewhat arbitrary. */
+- dwLen = osFormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
+- FORMAT_MESSAGE_IGNORE_INSERTS,
+- NULL,
+- lastErrno,
+- 0,
+- zTempWide,
+- MAX_PATH,
+- 0);
++#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
++ { "GetFullPathNameW", (SYSCALL)GetFullPathNameW, 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);
++ { "GetFullPathNameW", (SYSCALL)0, 0 },
+ #endif
+- if( dwLen > 0 ){
+- /* allocate a buffer and convert to UTF8 */
+- sqlite3BeginBenignMalloc();
+- zOut = unicodeToUtf8(zTempWide);
+- sqlite3EndBenignMalloc();
++
++#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
+- /* free the system buffer allocated by FormatMessage */
+- osLocalFree(zTempWide);
++ { "GetSystemInfo", (SYSCALL)GetSystemInfo, 0 },
++#else
++ { "GetSystemInfo", (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 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
+- 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 osGetTempPathA ((DWORD(WINAPI*)(DWORD,LPSTR))aSyscall[31].pCurrent)
+
+- zMsg[0] = 0;
+- getLastErrorMsg(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 && defined(SQLITE_WIN32_HAS_WIDE)
++ { "GetTempPathW", (SYSCALL)GetTempPathW, 0 },
++#else
++ { "GetTempPathW", (SYSCALL)0, 0 },
++#endif
+
+- return errcode;
+-}
++#define osGetTempPathW ((DWORD(WINAPI*)(DWORD,LPWSTR))aSyscall[32].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
++ { "GetTickCount", (SYSCALL)GetTickCount, 0 },
++#else
++ { "GetTickCount", (SYSCALL)0, 0 },
+ #endif
+-#ifndef SQLITE_WIN32_IOERR_RETRY_DELAY
+-# define SQLITE_WIN32_IOERR_RETRY_DELAY 25
++
++#define osGetTickCount ((DWORD(WINAPI*)(VOID))aSyscall[33].pCurrent)
++
++#if defined(SQLITE_WIN32_HAS_ANSI)
++ { "GetVersionExA", (SYSCALL)GetVersionExA, 0 },
++#else
++ { "GetVersionExA", (SYSCALL)0, 0 },
+ #endif
+-static int win32IoerrRetry = SQLITE_WIN32_IOERR_RETRY;
+-static int win32IoerrRetryDelay = SQLITE_WIN32_IOERR_RETRY_DELAY;
+
+-/*
+-** 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 retryIoerr(int *pnRetry, DWORD *pError){
+- DWORD e = osGetLastError();
+- if( *pnRetry>=win32IoerrRetry ){
+- if( pError ){
+- *pError = e;
+- }
+- return 0;
+- }
+- if( e==ERROR_ACCESS_DENIED ||
+- e==ERROR_LOCK_VIOLATION ||
+- e==ERROR_SHARING_VIOLATION ){
+- sqlite3_win32_sleep(win32IoerrRetryDelay*(1+*pnRetry));
+- ++*pnRetry;
+- return 1;
+- }
+- if( pError ){
+- *pError = e;
+- }
+- return 0;
+-}
++#define osGetVersionExA ((BOOL(WINAPI*)( \
++ LPOSVERSIONINFOA))aSyscall[34].pCurrent)
+
+-/*
+-** Log a I/O error retry episode.
+-*/
+-static void logIoerr(int nRetry){
+- if( nRetry ){
+- sqlite3_log(SQLITE_IOERR,
+- "delayed %dms for lock/sharing conflict",
+- win32IoerrRetryDelay*nRetry*(nRetry+1)/2
+- );
+- }
+-}
++ { "HeapAlloc", (SYSCALL)HeapAlloc, 0 },
+
+-#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;
+-}
++#define osHeapAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD, \
++ SIZE_T))aSyscall[35].pCurrent)
++
++#if !SQLITE_OS_WINRT
++ { "HeapCreate", (SYSCALL)HeapCreate, 0 },
++#else
++ { "HeapCreate", (SYSCALL)0, 0 },
+ #endif
+
+-#define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-(int)offsetof(winFile,h)]
++#define osHeapCreate ((HANDLE(WINAPI*)(DWORD,SIZE_T, \
++ SIZE_T))aSyscall[36].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)
++#if !SQLITE_OS_WINRT
++ { "HeapDestroy", (SYSCALL)HeapDestroy, 0 },
++#else
++ { "HeapDestroy", (SYSCALL)0, 0 },
++#endif
+
+-/*
+-** 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 osHeapDestroy ((BOOL(WINAPI*)(HANDLE))aSyscall[37].pCurrent)
+
+- zName = utf8ToUnicode(zFilename);
+- if( zName==0 ){
+- /* out of memory */
+- return SQLITE_IOERR_NOMEM;
+- }
++ { "HeapFree", (SYSCALL)HeapFree, 0 },
+
+- /* Initialize the local lockdata */
+- memset(&pFile->local, 0, sizeof(pFile->local));
++#define osHeapFree ((BOOL(WINAPI*)(HANDLE,DWORD,LPVOID))aSyscall[38].pCurrent)
+
+- /* Replace the backslashes from the filename and lowercase it
+- ** to derive a mutex name. */
+- zTok = osCharLowerW(zName);
+- for (;*zTok;zTok++){
+- if (*zTok == '\\') *zTok = '_';
+- }
++ { "HeapReAlloc", (SYSCALL)HeapReAlloc, 0 },
+
+- /* Create/open the named mutex */
+- pFile->hMutex = osCreateMutexW(NULL, FALSE, zName);
+- if (!pFile->hMutex){
+- pFile->lastErrno = osGetLastError();
+- winLogError(SQLITE_IOERR, pFile->lastErrno,
+- "winceCreateLock1", zFilename);
+- sqlite3_free(zName);
+- return SQLITE_IOERR;
+- }
++#define osHeapReAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD,LPVOID, \
++ SIZE_T))aSyscall[39].pCurrent)
+
+- /* Acquire the mutex before continuing */
+- winceMutexAcquire(pFile->hMutex);
+-
+- /* 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);
++ { "HeapSize", (SYSCALL)HeapSize, 0 },
+
+- /* 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 osHeapSize ((SIZE_T(WINAPI*)(HANDLE,DWORD, \
++ LPCVOID))aSyscall[40].pCurrent)
+
+- sqlite3_free(zName);
++#if !SQLITE_OS_WINRT
++ { "HeapValidate", (SYSCALL)HeapValidate, 0 },
++#else
++ { "HeapValidate", (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 osHeapValidate ((BOOL(WINAPI*)(HANDLE,DWORD, \
++ LPCVOID))aSyscall[41].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;
+- }
+-
+- /* Initialize the shared memory if we're supposed to */
+- if( bInit ){
+- memset(pFile->shared, 0, sizeof(winceLock));
+- }
++#if defined(SQLITE_WIN32_HAS_ANSI) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
++ { "LoadLibraryA", (SYSCALL)LoadLibraryA, 0 },
++#else
++ { "LoadLibraryA", (SYSCALL)0, 0 },
++#endif
+
+- winceMutexRelease(pFile->hMutex);
+- return SQLITE_OK;
+-}
++#define osLoadLibraryA ((HMODULE(WINAPI*)(LPCSTR))aSyscall[42].pCurrent)
+
+-/*
+-** Destroy the part of winFile that deals with wince locks
+-*/
+-static void winceDestroyLock(winFile *pFile){
+- if (pFile->hMutex){
+- /* Acquire the mutex */
+- winceMutexAcquire(pFile->hMutex);
++#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \
++ !defined(SQLITE_OMIT_LOAD_EXTENSION)
++ { "LoadLibraryW", (SYSCALL)LoadLibraryW, 0 },
++#else
++ { "LoadLibraryW", (SYSCALL)0, 0 },
++#endif
+
+- /* 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;
+- }
+- if (pFile->local.bExclusive){
+- pFile->shared->bExclusive = FALSE;
+- }
++#define osLoadLibraryW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[43].pCurrent)
+
+- /* De-reference and close our copy of the shared memory handle */
+- osUnmapViewOfFile(pFile->shared);
+- osCloseHandle(pFile->hShared);
++#if !SQLITE_OS_WINRT
++ { "LocalFree", (SYSCALL)LocalFree, 0 },
++#else
++ { "LocalFree", (SYSCALL)0, 0 },
++#endif
+
+- /* Done with the mutex */
+- winceMutexRelease(pFile->hMutex);
+- osCloseHandle(pFile->hMutex);
+- pFile->hMutex = NULL;
+- }
+-}
++#define osLocalFree ((HLOCAL(WINAPI*)(HLOCAL))aSyscall[44].pCurrent)
+
+-/*
+-** An implementation of the LockFile() API of Windows for CE
+-*/
+-static BOOL winceLockFile(
+- LPHANDLE phFile,
+- DWORD dwFileOffsetLow,
+- DWORD dwFileOffsetHigh,
+- DWORD nNumberOfBytesToLockLow,
+- DWORD nNumberOfBytesToLockHigh
+-){
+- winFile *pFile = HANDLE_TO_WINFILE(phFile);
+- BOOL bReturn = FALSE;
++#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
++ { "LockFile", (SYSCALL)LockFile, 0 },
++#else
++ { "LockFile", (SYSCALL)0, 0 },
++#endif
+
+- UNUSED_PARAMETER(dwFileOffsetHigh);
+- UNUSED_PARAMETER(nNumberOfBytesToLockHigh);
++#ifndef osLockFile
++#define osLockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
++ DWORD))aSyscall[45].pCurrent)
++#endif
+
+- if (!pFile->hMutex) return TRUE;
+- winceMutexAcquire(pFile->hMutex);
++#if !SQLITE_OS_WINCE
++ { "LockFileEx", (SYSCALL)LockFileEx, 0 },
++#else
++ { "LockFileEx", (SYSCALL)0, 0 },
++#endif
+
+- /* 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;
+- }
+- }
++#ifndef osLockFileEx
++#define osLockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD,DWORD, \
++ LPOVERLAPPED))aSyscall[46].pCurrent)
++#endif
+
+- /* 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 SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && !defined(SQLITE_OMIT_WAL))
++ { "MapViewOfFile", (SYSCALL)MapViewOfFile, 0 },
++#else
++ { "MapViewOfFile", (SYSCALL)0, 0 },
++#endif
+
+- /* 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;
+- }
+- }
++#define osMapViewOfFile ((LPVOID(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
++ SIZE_T))aSyscall[47].pCurrent)
+
+- /* 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;
+- }
+- }
++ { "MultiByteToWideChar", (SYSCALL)MultiByteToWideChar, 0 },
+
+- winceMutexRelease(pFile->hMutex);
+- return bReturn;
+-}
++#define osMultiByteToWideChar ((int(WINAPI*)(UINT,DWORD,LPCSTR,int,LPWSTR, \
++ int))aSyscall[48].pCurrent)
+
+-/*
+-** An implementation of the UnlockFile API of Windows for CE
+-*/
+-static BOOL winceUnlockFile(
+- LPHANDLE phFile,
+- DWORD dwFileOffsetLow,
+- DWORD dwFileOffsetHigh,
+- DWORD nNumberOfBytesToUnlockLow,
+- DWORD nNumberOfBytesToUnlockHigh
+-){
+- winFile *pFile = HANDLE_TO_WINFILE(phFile);
+- BOOL bReturn = FALSE;
++ { "QueryPerformanceCounter", (SYSCALL)QueryPerformanceCounter, 0 },
+
+- UNUSED_PARAMETER(dwFileOffsetHigh);
+- UNUSED_PARAMETER(nNumberOfBytesToUnlockHigh);
++#define osQueryPerformanceCounter ((BOOL(WINAPI*)( \
++ LARGE_INTEGER*))aSyscall[49].pCurrent)
+
+- if (!pFile->hMutex) return TRUE;
+- winceMutexAcquire(pFile->hMutex);
++ { "ReadFile", (SYSCALL)ReadFile, 0 },
+
+- /* 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;
+- }
++#define osReadFile ((BOOL(WINAPI*)(HANDLE,LPVOID,DWORD,LPDWORD, \
++ LPOVERLAPPED))aSyscall[50].pCurrent)
+
+- /* 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;
+- }
+- }
++ { "SetEndOfFile", (SYSCALL)SetEndOfFile, 0 },
+
+- /* 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;
+- }
+- }
+- /* 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;
+- }
+- }
++#define osSetEndOfFile ((BOOL(WINAPI*)(HANDLE))aSyscall[51].pCurrent)
+
+- winceMutexRelease(pFile->hMutex);
+- return bReturn;
+-}
+-/*
+-** End of the special code for wince
+-*****************************************************************************/
+-#endif /* SQLITE_OS_WINCE */
++#if !SQLITE_OS_WINRT
++ { "SetFilePointer", (SYSCALL)SetFilePointer, 0 },
++#else
++ { "SetFilePointer", (SYSCALL)0, 0 },
++#endif
+
+-/*
+-** 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);
++#define osSetFilePointer ((DWORD(WINAPI*)(HANDLE,LONG,PLONG, \
++ DWORD))aSyscall[52].pCurrent)
++
++#if !SQLITE_OS_WINRT
++ { "Sleep", (SYSCALL)Sleep, 0 },
++#else
++ { "Sleep", (SYSCALL)0, 0 },
++#endif
++
++#define osSleep ((VOID(WINAPI*)(DWORD))aSyscall[53].pCurrent)
++
++ { "SystemTimeToFileTime", (SYSCALL)SystemTimeToFileTime, 0 },
++
++#define osSystemTimeToFileTime ((BOOL(WINAPI*)(CONST SYSTEMTIME*, \
++ LPFILETIME))aSyscall[54].pCurrent)
++
++#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
++ { "UnlockFile", (SYSCALL)UnlockFile, 0 },
+ #else
+- if( isNT() ){
+- 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);
+- }
++ { "UnlockFile", (SYSCALL)0, 0 },
+ #endif
+-}
+
+-/*
+-** 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);
++#ifndef osUnlockFile
++#define osUnlockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
++ DWORD))aSyscall[55].pCurrent)
++#endif
++
++#if !SQLITE_OS_WINCE
++ { "UnlockFileEx", (SYSCALL)UnlockFileEx, 0 },
+ #else
+- if( isNT() ){
+- 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);
+- }
++ { "UnlockFileEx", (SYSCALL)0, 0 },
+ #endif
+-}
+
+-/*****************************************************************************
+-** The next group of routines implement the I/O methods specified
+-** by the sqlite3_io_methods object.
+-******************************************************************************/
++#define osUnlockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
++ LPOVERLAPPED))aSyscall[56].pCurrent)
+
+-/*
+-** Some Microsoft compilers lack this definition.
+-*/
+-#ifndef INVALID_SET_FILE_POINTER
+-# define INVALID_SET_FILE_POINTER ((DWORD)-1)
++#if SQLITE_OS_WINCE || !defined(SQLITE_OMIT_WAL)
++ { "UnmapViewOfFile", (SYSCALL)UnmapViewOfFile, 0 },
++#else
++ { "UnmapViewOfFile", (SYSCALL)0, 0 },
+ #endif
+
+-/*
+-** 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 int seekWinFile(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() */
++#define osUnmapViewOfFile ((BOOL(WINAPI*)(LPCVOID))aSyscall[57].pCurrent)
+
+- OSTRACE(("SEEK file=%p, offset=%lld\n", pFile->h, iOffset));
++ { "WideCharToMultiByte", (SYSCALL)WideCharToMultiByte, 0 },
+
+- upperBits = (LONG)((iOffset>>32) & 0x7fffffff);
+- lowerBits = (LONG)(iOffset & 0xffffffff);
++#define osWideCharToMultiByte ((int(WINAPI*)(UINT,DWORD,LPCWSTR,int,LPSTR,int, \
++ LPCSTR,LPBOOL))aSyscall[58].pCurrent)
+
+- /* 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);
++ { "WriteFile", (SYSCALL)WriteFile, 0 },
+
+- if( (dwRet==INVALID_SET_FILE_POINTER
+- && ((lastErrno = osGetLastError())!=NO_ERROR)) ){
+- pFile->lastErrno = lastErrno;
+- winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno,
+- "seekWinFile", pFile->zPath);
+- OSTRACE(("SEEK file=%p, rc=SQLITE_IOERR_SEEK\n", pFile->h));
+- return 1;
+- }
++#define osWriteFile ((BOOL(WINAPI*)(HANDLE,LPCVOID,DWORD,LPDWORD, \
++ LPOVERLAPPED))aSyscall[59].pCurrent)
+
+- OSTRACE(("SEEK file=%p, rc=SQLITE_OK\n", pFile->h));
+- return 0;
++#if SQLITE_OS_WINRT
++ { "CreateEventExW", (SYSCALL)CreateEventExW, 0 },
+ #else
+- /*
+- ** Same as above, except that this implementation works for WinRT.
+- */
++ { "CreateEventExW", (SYSCALL)0, 0 },
++#endif
+
+- LARGE_INTEGER x; /* The new offset */
+- BOOL bRet; /* Value returned by SetFilePointerEx() */
++#define osCreateEventExW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,LPCWSTR, \
++ DWORD,DWORD))aSyscall[60].pCurrent)
+
+- x.QuadPart = iOffset;
+- bRet = osSetFilePointerEx(pFile->h, x, 0, FILE_BEGIN);
++#if !SQLITE_OS_WINRT
++ { "WaitForSingleObject", (SYSCALL)WaitForSingleObject, 0 },
++#else
++ { "WaitForSingleObject", (SYSCALL)0, 0 },
++#endif
+
+- if(!bRet){
+- pFile->lastErrno = osGetLastError();
+- winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno,
+- "seekWinFile", pFile->zPath);
+- OSTRACE(("SEEK file=%p, rc=SQLITE_IOERR_SEEK\n", pFile->h));
+- return 1;
+- }
++#define osWaitForSingleObject ((DWORD(WINAPI*)(HANDLE, \
++ DWORD))aSyscall[61].pCurrent)
+
+- OSTRACE(("SEEK file=%p, rc=SQLITE_OK\n", pFile->h));
+- return 0;
++#if SQLITE_OS_WINRT
++ { "WaitForSingleObjectEx", (SYSCALL)WaitForSingleObjectEx, 0 },
++#else
++ { "WaitForSingleObjectEx", (SYSCALL)0, 0 },
+ #endif
+-}
+
+-#if SQLITE_MAX_MMAP_SIZE>0
+-/* Forward references to VFS methods */
+-static int winUnmapfile(winFile*);
++#define osWaitForSingleObjectEx ((DWORD(WINAPI*)(HANDLE,DWORD, \
++ BOOL))aSyscall[62].pCurrent)
++
++#if SQLITE_OS_WINRT
++ { "SetFilePointerEx", (SYSCALL)SetFilePointerEx, 0 },
++#else
++ { "SetFilePointerEx", (SYSCALL)0, 0 },
+ #endif
+
+-/*
+-** 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.
+-*/
+-#define MX_CLOSE_ATTEMPT 3
+-static int winClose(sqlite3_file *id){
+- int rc, cnt = 0;
+- winFile *pFile = (winFile*)id;
++#define osSetFilePointerEx ((BOOL(WINAPI*)(HANDLE,LARGE_INTEGER, \
++ PLARGE_INTEGER,DWORD))aSyscall[63].pCurrent)
+
+- assert( id!=0 );
+-#ifndef SQLITE_OMIT_WAL
+- assert( pFile->pShm==0 );
++#if SQLITE_OS_WINRT
++ { "GetFileInformationByHandleEx", (SYSCALL)GetFileInformationByHandleEx, 0 },
++#else
++ { "GetFileInformationByHandleEx", (SYSCALL)0, 0 },
+ #endif
+- assert( pFile->h!=NULL && pFile->h!=INVALID_HANDLE_VALUE );
+- OSTRACE(("CLOSE file=%p\n", pFile->h));
+
+-#if SQLITE_MAX_MMAP_SIZE>0
+- rc = winUnmapfile(pFile);
+- if( rc!=SQLITE_OK ) return rc;
+-#endif
++#define osGetFileInformationByHandleEx ((BOOL(WINAPI*)(HANDLE, \
++ FILE_INFO_BY_HANDLE_CLASS,LPVOID,DWORD))aSyscall[64].pCurrent)
+
+- 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);
+- }
++#if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_WAL)
++ { "MapViewOfFileFromApp", (SYSCALL)MapViewOfFileFromApp, 0 },
++#else
++ { "MapViewOfFileFromApp", (SYSCALL)0, 0 },
+ #endif
+- if( rc ){
+- pFile->h = NULL;
+- }
+- OpenCounter(-1);
+- OSTRACE(("CLOSE file=%p, rc=%s\n", 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.
+-*/
+-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
+- OVERLAPPED overlapped; /* The offset for ReadFile. */
++#define osMapViewOfFileFromApp ((LPVOID(WINAPI*)(HANDLE,ULONG,ULONG64, \
++ SIZE_T))aSyscall[65].pCurrent)
++
++#if SQLITE_OS_WINRT
++ { "CreateFile2", (SYSCALL)CreateFile2, 0 },
++#else
++ { "CreateFile2", (SYSCALL)0, 0 },
+ #endif
+- winFile *pFile = (winFile*)id; /* file handle */
+- DWORD nRead; /* Number of bytes actually read from file */
+- int nRetry = 0; /* Number of retrys */
+
+- assert( id!=0 );
+- assert( amt>0 );
+- assert( offset>=0 );
+- SimulateIOError(return SQLITE_IOERR_READ);
+- OSTRACE(("READ file=%p, buffer=%p, amount=%d, offset=%lld, lock=%d\n",
+- pFile->h, pBuf, amt, offset, pFile->locktype));
++#define osCreateFile2 ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD,DWORD, \
++ LPCREATEFILE2_EXTENDED_PARAMETERS))aSyscall[66].pCurrent)
+
+-#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 file=%p, rc=SQLITE_OK\n", 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;
+- }
+- }
++#if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_LOAD_EXTENSION)
++ { "LoadPackagedLibrary", (SYSCALL)LoadPackagedLibrary, 0 },
++#else
++ { "LoadPackagedLibrary", (SYSCALL)0, 0 },
+ #endif
+
+-#if SQLITE_OS_WINCE
+- if( seekWinFile(pFile, offset) ){
+- OSTRACE(("READ file=%p, rc=SQLITE_FULL\n", pFile->h));
+- return SQLITE_FULL;
+- }
+- while( !osReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
++#define osLoadPackagedLibrary ((HMODULE(WINAPI*)(LPCWSTR, \
++ DWORD))aSyscall[67].pCurrent)
++
++#if SQLITE_OS_WINRT
++ { "GetTickCount64", (SYSCALL)GetTickCount64, 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 ){
++ { "GetTickCount64", (SYSCALL)0, 0 },
+ #endif
+- DWORD lastErrno;
+- if( retryIoerr(&nRetry, &lastErrno) ) continue;
+- pFile->lastErrno = lastErrno;
+- OSTRACE(("READ file=%p, rc=SQLITE_IOERR_READ\n", pFile->h));
+- return winLogError(SQLITE_IOERR_READ, pFile->lastErrno,
+- "winRead", pFile->zPath);
+- }
+- logIoerr(nRetry);
+- 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));
+- return SQLITE_IOERR_SHORT_READ;
+- }
+-
+- OSTRACE(("READ file=%p, rc=SQLITE_OK\n", pFile->h));
+- return SQLITE_OK;
+-}
+
+-/*
+-** Write data from a buffer into a file. Return SQLITE_OK on success
+-** or some other error code on failure.
+-*/
+-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 */
++#define osGetTickCount64 ((ULONGLONG(WINAPI*)(VOID))aSyscall[68].pCurrent)
+
+- assert( amt>0 );
+- assert( pFile );
+- SimulateIOError(return SQLITE_IOERR_WRITE);
+- SimulateDiskfullError(return SQLITE_FULL);
++#if SQLITE_OS_WINRT
++ { "GetNativeSystemInfo", (SYSCALL)GetNativeSystemInfo, 0 },
++#else
++ { "GetNativeSystemInfo", (SYSCALL)0, 0 },
++#endif
+
+- OSTRACE(("WRITE file=%p, buffer=%p, amount=%d, offset=%lld, lock=%d\n",
+- pFile->h, pBuf, amt, offset, pFile->locktype));
++#define osGetNativeSystemInfo ((VOID(WINAPI*)( \
++ LPSYSTEM_INFO))aSyscall[69].pCurrent)
+
+-#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 file=%p, rc=SQLITE_OK\n", 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;
+- }
+- }
++#if defined(SQLITE_WIN32_HAS_ANSI)
++ { "OutputDebugStringA", (SYSCALL)OutputDebugStringA, 0 },
++#else
++ { "OutputDebugStringA", (SYSCALL)0, 0 },
+ #endif
+
+-#if SQLITE_OS_WINCE
+- rc = seekWinFile(pFile, offset);
+- if( rc==0 ){
++#define osOutputDebugStringA ((VOID(WINAPI*)(LPCSTR))aSyscall[70].pCurrent)
++
++#if defined(SQLITE_WIN32_HAS_WIDE)
++ { "OutputDebugStringW", (SYSCALL)OutputDebugStringW, 0 },
+ #else
+- {
+-#endif
+-#if !SQLITE_OS_WINCE
+- OVERLAPPED overlapped; /* The offset for WriteFile. */
++ { "OutputDebugStringW", (SYSCALL)0, 0 },
+ #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() */
+
+-#if !SQLITE_OS_WINCE
+- memset(&overlapped, 0, sizeof(OVERLAPPED));
+- overlapped.Offset = (LONG)(offset & 0xffffffff);
+- overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
+-#endif
++#define osOutputDebugStringW ((VOID(WINAPI*)(LPCWSTR))aSyscall[71].pCurrent)
+
+- while( nRem>0 ){
+-#if SQLITE_OS_WINCE
+- if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, 0) ){
++ { "GetProcessHeap", (SYSCALL)GetProcessHeap, 0 },
++
++#define osGetProcessHeap ((HANDLE(WINAPI*)(VOID))aSyscall[72].pCurrent)
++
++#if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_WAL)
++ { "CreateFileMappingFromApp", (SYSCALL)CreateFileMappingFromApp, 0 },
+ #else
+- if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, &overlapped) ){
++ { "CreateFileMappingFromApp", (SYSCALL)0, 0 },
+ #endif
+- if( retryIoerr(&nRetry, &lastErrno) ) continue;
+- break;
++
++#define osCreateFileMappingFromApp ((HANDLE(WINAPI*)(HANDLE, \
++ LPSECURITY_ATTRIBUTES,ULONG,ULONG64,LPCWSTR))aSyscall[73].pCurrent)
++
++}; /* End of the overrideable system calls */
++
++/*
++** 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;
++
++ 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;
+ }
+- assert( nWrite==0 || nWrite<=(DWORD)nRem );
+- if( nWrite==0 || nWrite>(DWORD)nRem ){
+- lastErrno = osGetLastError();
++ }
++ }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;
+ }
+-#if !SQLITE_OS_WINCE
+- 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 file=%p, rc=SQLITE_FULL\n", pFile->h));
+- return SQLITE_FULL;
+ }
+- OSTRACE(("WRITE file=%p, rc=SQLITE_IOERR_WRITE\n", pFile->h));
+- return winLogError(SQLITE_IOERR_WRITE, pFile->lastErrno,
+- "winWrite", pFile->zPath);
+- }else{
+- logIoerr(nRetry);
+ }
+- OSTRACE(("WRITE file=%p, rc=SQLITE_OK\n", pFile->h));
+- return SQLITE_OK;
++ return rc;
+ }
+
+ /*
+-** Truncate an open file to a specified size
++** 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 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 file=%p, size=%lld, lock=%d\n",
+- 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
+- ** 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;
+- }
+-
+- /* SetEndOfFile() returns non-zero when successful, or zero when it fails. */
+- if( seekWinFile(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);
+- }
++static sqlite3_syscall_ptr winGetSystemCall(
++ sqlite3_vfs *pNotUsed,
++ const char *zName
++){
++ unsigned int i;
+
+-#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;
++ UNUSED_PARAMETER(pNotUsed);
++ for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
++ if( strcmp(zName, aSyscall[i].zName)==0 ) return aSyscall[i].pCurrent;
+ }
+-#endif
+-
+- OSTRACE(("TRUNCATE file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc)));
+- return rc;
++ return 0;
+ }
+
+-#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.
+-*/
+-SQLITE_API int sqlite3_sync_count = 0;
+-SQLITE_API int sqlite3_fullsync_count = 0;
+-#endif
+-
+ /*
+-** Make sure all writes to a particular file are committed to disk.
++** 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 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_TEST) && defined(SQLITE_DEBUG))
+- /*
+- ** 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
+- );
++static const char *winNextSystemCall(sqlite3_vfs *p, const char *zName){
++ int i = -1;
+
+- /* 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 );
++ 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;
++}
+
+- OSTRACE(("SYNC file=%p, flags=%x, lock=%d\n",
+- pFile->h, flags, pFile->locktype));
++/*
++** This function outputs the specified (ANSI) string to the Win32 debugger
++** (if available).
++*/
+
+-#ifndef SQLITE_TEST
+- UNUSED_PARAMETER(flags);
+-#else
+- if( (flags&0x0F)==SQLITE_SYNC_FULL ){
+- sqlite3_fullsync_count++;
++SQLITE_API void 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);
+ }
+- sqlite3_sync_count++;
+-#endif
+-
+- /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a
+- ** no-op
+- */
+-#ifdef SQLITE_NO_SYNC
+- return SQLITE_OK;
++#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);
+ #else
+- rc = osFlushFileBuffers(pFile->h);
+- SimulateIOError( rc=FALSE );
+- if( rc ){
+- OSTRACE(("SYNC file=%p, rc=SQLITE_OK\n", pFile->h));
+- return SQLITE_OK;
++ if( nMin>0 ){
++ memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE);
++ memcpy(zDbgBuf, zBuf, nMin);
++ fprintf(stderr, "%s", zDbgBuf);
+ }else{
+- pFile->lastErrno = osGetLastError();
+- OSTRACE(("SYNC file=%p, rc=SQLITE_IOERR_FSYNC\n", pFile->h));
+- return winLogError(SQLITE_IOERR_FSYNC, pFile->lastErrno,
+- "winSync", pFile->zPath);
++ fprintf(stderr, "%s", zBuf);
+ }
+ #endif
+ }
+
+ /*
+-** Determine the current size of a file in bytes
++** The following routine suspends the current thread for at least ms
++** milliseconds. This is equivalent to the Win32 Sleep() interface.
+ */
+-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));
++#if SQLITE_OS_WINRT
++static HANDLE sleepObj = NULL;
++#endif
+
++SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds){
+ #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);
+- }
++ if ( sleepObj==NULL ){
++ sleepObj = osCreateEventExW(NULL, NULL, CREATE_EVENT_MANUAL_RESET,
++ SYNCHRONIZE);
+ }
++ assert( sleepObj!=NULL );
++ osWaitForSingleObjectEx(sleepObj, milliseconds, FALSE);
+ #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);
+- }
+- }
++ osSleep(milliseconds);
+ #endif
+- OSTRACE(("SIZE file=%p, pSize=%p, *pSize=%lld, rc=%s\n",
+- pFile->h, pSize, *pSize, sqlite3ErrName(rc)));
+- return rc;
+ }
+
+ /*
+-** LOCKFILE_FAIL_IMMEDIATELY is undefined on some Windows systems.
++** 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.
+ */
+-#ifndef LOCKFILE_FAIL_IMMEDIATELY
+-# define LOCKFILE_FAIL_IMMEDIATELY 1
+-#endif
+-
+-#ifndef LOCKFILE_EXCLUSIVE_LOCK
+-# define LOCKFILE_EXCLUSIVE_LOCK 2
++#if SQLITE_OS_WINCE || SQLITE_OS_WINRT
++# define isNT() (1)
++#elif !defined(SQLITE_WIN32_HAS_WIDE)
++# define isNT() (0)
++#else
++ static int isNT(void){
++ if( sqlite3_os_type==0 ){
++ OSVERSIONINFOA sInfo;
++ sInfo.dwOSVersionInfoSize = sizeof(sInfo);
++ osGetVersionExA(&sInfo);
++ sqlite3_os_type = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1;
++ }
++ return sqlite3_os_type==2;
++ }
+ #endif
+
++#ifdef SQLITE_WIN32_MALLOC
+ /*
+-** 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.
++** Allocate nBytes of memory.
+ */
+-#ifndef SQLITE_LOCKFILE_FLAGS
+-# define SQLITE_LOCKFILE_FLAGS (LOCKFILE_FAIL_IMMEDIATELY | \
+- LOCKFILE_EXCLUSIVE_LOCK)
++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 (%d), heap=%p",
++ nBytes, osGetLastError(), (void*)hHeap);
++ }
++ return p;
++}
+
+ /*
+-** Currently, SQLite never calls the LockFileEx function without wanting the
+-** call to fail immediately if the lock cannot be obtained.
++** Free memory.
+ */
+-#ifndef SQLITE_LOCKFILEEX_FLAGS
+-# define SQLITE_LOCKFILEEX_FLAGS (LOCKFILE_FAIL_IMMEDIATELY)
++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 (%d), heap=%p",
++ pPrior, osGetLastError(), (void*)hHeap);
++ }
++}
+
+ /*
+-** Acquire a reader lock.
+-** Different API routines are called depending on whether or not this
+-** is Win9x or WinNT.
++** Change the size of an existing memory allocation
+ */
+-static int getReadLock(winFile *pFile){
+- int res;
+- OSTRACE(("READ-LOCK file=%p, lock=%d\n", pFile->h, pFile->locktype));
+- if( isNT() ){
+-#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);
++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);
+ }
+-#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 */
++ if( !p ){
++ sqlite3_log(SQLITE_NOMEM, "failed to %s %u bytes (%d), heap=%p",
++ pPrior ? "HeapReAlloc" : "HeapAlloc", nBytes, osGetLastError(),
++ (void*)hHeap);
+ }
+- OSTRACE(("READ-LOCK file=%p, rc=%s\n", pFile->h, sqlite3ErrName(res)));
+- return res;
++ return p;
+ }
+
+ /*
+-** Undo a readlock
++** Return the size of an outstanding allocation, in bytes.
+ */
+-static int unlockReadLock(winFile *pFile){
+- int res;
+- DWORD lastErrno;
+- OSTRACE(("READ-UNLOCK file=%p, lock=%d\n", pFile->h, pFile->locktype));
+- if( isNT() ){
+- 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);
+- }
++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, NULL) );
+ #endif
+- if( res==0 && ((lastErrno = osGetLastError())!=ERROR_NOT_LOCKED) ){
+- pFile->lastErrno = lastErrno;
+- winLogError(SQLITE_IOERR_UNLOCK, pFile->lastErrno,
+- "unlockReadLock", pFile->zPath);
++ 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 (%d), heap=%p",
++ p, osGetLastError(), (void*)hHeap);
++ return 0;
+ }
+- OSTRACE(("READ-UNLOCK file=%p, rc=%s\n", pFile->h, sqlite3ErrName(res)));
+- return res;
++ return (int)n;
+ }
+
+ /*
+-** 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.
++** Round up a request size to the next valid allocation size.
+ */
+-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;
+-
+- assert( id!=0 );
+- OSTRACE(("LOCK file=%p, oldLock=%d(%d), newLock=%d\n",
+- pFile->h, pFile->locktype, pFile->sharedLockByte, locktype));
++static int winMemRoundup(int n){
++ return n;
++}
+
+- /* 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;
+- }
++/*
++** Initialize this module.
++*/
++static int winMemInit(void *pAppData){
++ winMemData *pWinMemData = (winMemData *)pAppData;
+
+- /* 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( !pWinMemData ) return SQLITE_ERROR;
++ assert( pWinMemData->magic==WINMEM_MAGIC );
+
+- /* 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.
+- */
+- OSTRACE(("LOCK-PENDING-FAIL file=%p, count=%d, rc=%s\n",
+- pFile->h, cnt, sqlite3ErrName(res)));
+- if( cnt ) sqlite3_win32_sleep(1);
+- }
+- gotPendingLock = res;
+- if( !res ){
+- lastErrno = osGetLastError();
++#if !SQLITE_OS_WINRT && SQLITE_WIN32_HEAP_CREATE
++ if( !pWinMemData->hHeap ){
++ pWinMemData->hHeap = osHeapCreate(SQLITE_WIN32_HEAP_FLAGS,
++ SQLITE_WIN32_HEAP_INIT_SIZE,
++ SQLITE_WIN32_HEAP_MAX_SIZE);
++ if( !pWinMemData->hHeap ){
++ sqlite3_log(SQLITE_NOMEM,
++ "failed to HeapCreate (%d), flags=%u, initSize=%u, maxSize=%u",
++ osGetLastError(), SQLITE_WIN32_HEAP_FLAGS,
++ SQLITE_WIN32_HEAP_INIT_SIZE, SQLITE_WIN32_HEAP_MAX_SIZE);
++ return SQLITE_NOMEM;
+ }
++ pWinMemData->bOwned = TRUE;
++ assert( pWinMemData->bOwned );
+ }
+-
+- /* Acquire a shared lock
+- */
+- if( locktype==SHARED_LOCK && res ){
+- assert( pFile->locktype==NO_LOCK );
+- res = getReadLock(pFile);
+- if( res ){
+- newLocktype = SHARED_LOCK;
+- }else{
+- lastErrno = osGetLastError();
+- }
++#else
++ pWinMemData->hHeap = osGetProcessHeap();
++ if( !pWinMemData->hHeap ){
++ sqlite3_log(SQLITE_NOMEM,
++ "failed to GetProcessHeap (%d)", osGetLastError());
++ return SQLITE_NOMEM;
+ }
++ pWinMemData->bOwned = FALSE;
++ assert( !pWinMemData->bOwned );
++#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) );
++#endif
++ return SQLITE_OK;
++}
+
+- /* 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();
++/*
++** Deinitialize this module.
++*/
++static void winMemShutdown(void *pAppData){
++ winMemData *pWinMemData = (winMemData *)pAppData;
++
++ if( !pWinMemData ) return;
++ 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
++ if( pWinMemData->bOwned ){
++ if( !osHeapDestroy(pWinMemData->hHeap) ){
++ sqlite3_log(SQLITE_NOMEM, "failed to HeapDestroy (%d), heap=%p",
++ osGetLastError(), (void*)pWinMemData->hHeap);
++ }
++ pWinMemData->bOwned = FALSE;
+ }
++ pWinMemData->hHeap = NULL;
+ }
++}
+
+- /* Acquire a PENDING lock
+- */
+- if( locktype==EXCLUSIVE_LOCK && res ){
+- newLocktype = PENDING_LOCK;
+- gotPendingLock = 0;
+- }
++/*
++** 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;
++}
+
+- /* Acquire an EXCLUSIVE lock
+- */
+- if( locktype==EXCLUSIVE_LOCK && res ){
+- assert( pFile->locktype>=SHARED_LOCK );
+- res = unlockReadLock(pFile);
+- res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, SHARED_FIRST, 0,
+- SHARED_SIZE, 0);
+- if( res ){
+- newLocktype = EXCLUSIVE_LOCK;
+- }else{
+- lastErrno = osGetLastError();
+- getReadLock(pFile);
+- }
+- }
++SQLITE_PRIVATE void sqlite3MemSetDefault(void){
++ sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetWin32());
++}
++#endif /* SQLITE_WIN32_MALLOC */
++
++/*
++** Convert a UTF-8 string to Microsoft Unicode (UTF-16?).
++**
++** Space to hold the returned string is obtained from malloc.
++*/
++static LPWSTR utf8ToUnicode(const char *zFilename){
++ int nChar;
++ LPWSTR zWideFilename;
+
+- /* 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);
++ nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
++ if( nChar==0 ){
++ return 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{
+- OSTRACE(("LOCK-FAIL file=%p, wanted=%d, got=%d\n",
+- pFile->h, locktype, newLocktype));
+- pFile->lastErrno = lastErrno;
+- rc = SQLITE_BUSY;
++ zWideFilename = sqlite3MallocZero( nChar*sizeof(zWideFilename[0]) );
++ if( zWideFilename==0 ){
++ return 0;
+ }
+- pFile->locktype = (u8)newLocktype;
+- OSTRACE(("LOCK file=%p, lock=%d, rc=%s\n",
+- pFile->h, pFile->locktype, sqlite3ErrName(rc)));
+- return rc;
++ nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename,
++ nChar);
++ if( nChar==0 ){
++ sqlite3_free(zWideFilename);
++ zWideFilename = 0;
++ }
++ return zWideFilename;
+ }
+
+ /*
+-** 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.
++** Convert Microsoft Unicode to UTF-8. Space to hold the returned string is
++** obtained from sqlite3_malloc().
+ */
+-static int winCheckReservedLock(sqlite3_file *id, int *pResOut){
+- int rc;
+- winFile *pFile = (winFile*)id;
+-
+- SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
+- OSTRACE(("TEST-WR-LOCK file=%p, pResOut=%p\n", pFile->h, pResOut));
++static char *unicodeToUtf8(LPCWSTR zWideFilename){
++ int nByte;
++ char *zFilename;
+
+- assert( id!=0 );
+- if( pFile->locktype>=RESERVED_LOCK ){
+- rc = 1;
+- OSTRACE(("TEST-WR-LOCK file=%p, rc=%d (local)\n", pFile->h, rc));
+- }else{
+- rc = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS,RESERVED_BYTE, 0, 1, 0);
+- if( rc ){
+- winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0);
+- }
+- rc = !rc;
+- OSTRACE(("TEST-WR-LOCK file=%p, rc=%d (remote)\n", pFile->h, rc));
++ nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0);
++ if( nByte == 0 ){
++ return 0;
+ }
+- *pResOut = rc;
+- OSTRACE(("TEST-WR-LOCK file=%p, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n",
+- pFile->h, pResOut, *pResOut));
+- return SQLITE_OK;
++ 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;
+ }
+
+ /*
+-** 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;
++** 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 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 && !getReadLock(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( type>=RESERVED_LOCK ){
+- winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0);
++static LPWSTR mbcsToUnicode(const char *zFilename){
++ int nByte;
++ LPWSTR zMbcsFilename;
++ int codepage = osAreFileApisANSI() ? CP_ACP : CP_OEMCP;
++
++ nByte = osMultiByteToWideChar(codepage, 0, zFilename, -1, NULL,
++ 0)*sizeof(WCHAR);
++ if( nByte==0 ){
++ return 0;
+ }
+- if( locktype==NO_LOCK && type>=SHARED_LOCK ){
+- unlockReadLock(pFile);
++ zMbcsFilename = sqlite3MallocZero( nByte*sizeof(zMbcsFilename[0]) );
++ if( zMbcsFilename==0 ){
++ return 0;
+ }
+- if( type>=PENDING_LOCK ){
+- winUnlockFile(&pFile->h, PENDING_BYTE, 0, 1, 0);
++ nByte = osMultiByteToWideChar(codepage, 0, zFilename, -1, zMbcsFilename,
++ nByte);
++ if( nByte==0 ){
++ sqlite3_free(zMbcsFilename);
++ zMbcsFilename = 0;
+ }
+- pFile->locktype = (u8)locktype;
+- OSTRACE(("UNLOCK file=%p, lock=%d, rc=%s\n",
+- pFile->h, pFile->locktype, sqlite3ErrName(rc)));
+- return rc;
++ return zMbcsFilename;
+ }
+
+ /*
+-** If *pArg is inititially negative then this is a query. Set *pArg to
+-** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set.
++** Convert Microsoft Unicode to multi-byte character string, based on the
++** user's ANSI codepage.
+ **
+-** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags.
++** Space to hold the returned string is obtained from
++** sqlite3_malloc().
+ */
+-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 char *unicodeToMbcs(LPCWSTR zWideFilename){
++ int nByte;
++ char *zFilename;
++ int codepage = osAreFileApisANSI() ? CP_ACP : CP_OEMCP;
++
++ 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;
+ }
+
+-/* Forward declaration */
+-static int getTempname(int nBuf, char *zBuf);
+-
+ /*
+-** Control and query of the open file handle.
++** Convert multibyte character string to UTF-8. Space to hold the
++** returned string is obtained from sqlite3_malloc().
+ */
+-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("win32");
+- 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 ){
+- win32IoerrRetry = a[0];
+- }else{
+- a[0] = win32IoerrRetry;
+- }
+- if( a[1]>0 ){
+- win32IoerrRetryDelay = a[1];
+- }else{
+- a[1] = win32IoerrRetryDelay;
+- }
+- OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
+- return SQLITE_OK;
+- }
+- case SQLITE_FCNTL_TEMPFILENAME: {
+- char *zTFile = sqlite3MallocZero( pFile->pVfs->mxPathname );
+- if( zTFile ){
+- getTempname(pFile->pVfs->mxPathname, zTFile);
+- *(char**)pArg = zTFile;
+- }
+- OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
+- return SQLITE_OK;
+- }
+-#if SQLITE_MAX_MMAP_SIZE>0
+- case SQLITE_FCNTL_MMAP_SIZE: {
+- i64 newLimit = *(i64*)pArg;
+- if( newLimit>sqlite3GlobalConfig.mxMmap ){
+- newLimit = sqlite3GlobalConfig.mxMmap;
+- }
+- *(i64*)pArg = pFile->mmapSizeMax;
+- if( newLimit>=0 ) pFile->mmapSizeMax = newLimit;
+- OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
+- return SQLITE_OK;
+- }
+-#endif
++SQLITE_API char *sqlite3_win32_mbcs_to_utf8(const char *zFilename){
++ char *zFilenameUtf8;
++ LPWSTR zTmpWide;
++
++ zTmpWide = mbcsToUnicode(zFilename);
++ if( zTmpWide==0 ){
++ return 0;
+ }
+- OSTRACE(("FCNTL file=%p, rc=SQLITE_NOTFOUND\n", pFile->h));
+- return SQLITE_NOTFOUND;
++ zFilenameUtf8 = unicodeToUtf8(zTmpWide);
++ sqlite3_free(zTmpWide);
++ return zFilenameUtf8;
+ }
+
+ /*
+-** 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.
++** Convert UTF-8 to multibyte character string. Space to hold the
++** returned string is obtained from sqlite3_malloc().
+ */
+-static int winSectorSize(sqlite3_file *id){
+- (void)id;
+- return SQLITE_DEFAULT_SECTOR_SIZE;
++SQLITE_API char *sqlite3_win32_utf8_to_mbcs(const char *zFilename){
++ char *zFilenameMbcs;
++ LPWSTR zTmpWide;
++
++ zTmpWide = utf8ToUnicode(zFilename);
++ if( zTmpWide==0 ){
++ return 0;
++ }
++ zFilenameMbcs = unicodeToMbcs(zTmpWide);
++ sqlite3_free(zTmpWide);
++ return zFilenameMbcs;
+ }
+
+ /*
+-** Return a vector of device characteristics.
++** 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.
+ */
+-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);
++SQLITE_API int sqlite3_win32_set_directory(DWORD type, LPCWSTR zValue){
++ char **ppDirectory = 0;
++#ifndef SQLITE_OMIT_AUTOINIT
++ int rc = sqlite3_initialize();
++ if( rc ) return rc;
++#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 = unicodeToUtf8(zValue);
++ if ( zValueUtf8==0 ){
++ return SQLITE_NOMEM;
++ }
++ }
++ sqlite3_free(*ppDirectory);
++ *ppDirectory = zValueUtf8;
++ return SQLITE_OK;
++ }
++ return SQLITE_ERROR;
+ }
+
+-/*
+-** 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.
+-*/
+-SYSTEM_INFO winSysInfo;
+-
+-#ifndef SQLITE_OMIT_WAL
+-
+ /*
+-** 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()
++** The return value of getLastErrorMsg
++** is zero if the error message fits in the buffer, or non-zero
++** otherwise (if the message was truncated).
+ */
+-static void winShmEnterMutex(void){
+- sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+-}
+-static void winShmLeaveMutex(void){
+- sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+-}
+-#ifdef SQLITE_DEBUG
+-static int winShmMutexHeld(void) {
+- return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+-}
++static int getLastErrorMsg(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( isNT() ){
++#if SQLITE_OS_WINRT
++ WCHAR zTempWide[MAX_PATH+1]; /* NOTE: Somewhat arbitrary. */
++ dwLen = osFormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
++ FORMAT_MESSAGE_IGNORE_INSERTS,
++ NULL,
++ lastErrno,
++ 0,
++ zTempWide,
++ MAX_PATH,
++ 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 = unicodeToUtf8(zTempWide);
++ sqlite3EndBenignMalloc();
++#if !SQLITE_OS_WINRT
++ /* free the system buffer allocated by FormatMessage */
++ osLocalFree(zTempWide);
+ #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);
++ }
++ }
++#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;
++}
+
+ /*
+-** 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
++** This function - winLogErrorAtLine() - is only ever called via the macro
++** winLogError().
+ **
+-** Either winShmNode.mutex must be held or winShmNode.nRef==0 and
+-** winShmMutexHeld() is true when reading or writing any other field
+-** in this structure.
++** 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.
+ */
+-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 */
++#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 */
+
+- 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
+- u8 nextShmId; /* Next available winShm.id value */
+-#endif
+-};
++ zMsg[0] = 0;
++ getLastErrorMsg(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
++ );
+
+-/*
+-** A global array of all winShmNode objects.
+-**
+-** The winShmMutexHeld() must be true while reading or writing this list.
+-*/
+-static winShmNode *winShmNodeList = 0;
++ return errcode;
++}
+
+ /*
+-** 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.
++** 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.
+ */
+-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 */
+-#ifdef SQLITE_DEBUG
+- u8 id; /* Id of this connection with its winShmNode */
++#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 win32IoerrRetry = SQLITE_WIN32_IOERR_RETRY;
++static int win32IoerrRetryDelay = SQLITE_WIN32_IOERR_RETRY_DELAY;
+
+ /*
+-** Constants used for locking
++** 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.
+ */
+-#define WIN_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */
+-#define WIN_SHM_DMS (WIN_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */
++static int retryIoerr(int *pnRetry, DWORD *pError){
++ DWORD e = osGetLastError();
++ if( *pnRetry>=win32IoerrRetry ){
++ if( pError ){
++ *pError = e;
++ }
++ return 0;
++ }
++ if( e==ERROR_ACCESS_DENIED ||
++ e==ERROR_LOCK_VIOLATION ||
++ e==ERROR_SHARING_VIOLATION ){
++ sqlite3_win32_sleep(win32IoerrRetryDelay*(1+*pnRetry));
++ ++*pnRetry;
++ return 1;
++ }
++ if( pError ){
++ *pError = e;
++ }
++ return 0;
++}
+
+ /*
+-** Apply advisory locks for all n bytes beginning at ofst.
++** Log a I/O error retry episode.
+ */
+-#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() */
+-
+- /* Access to the winShmNode object is serialized by the caller */
+- assert( sqlite3_mutex_held(pFile->mutex) || pFile->nRef==0 );
+-
+- OSTRACE(("SHM-LOCK file=%p, lock=%d, offset=%d, size=%d\n",
+- pFile->hFile.h, lockType, ofst, nByte));
+-
+- /* 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);
+- }
+-
+- if( rc!= 0 ){
+- rc = SQLITE_OK;
+- }else{
+- pFile->lastErrno = osGetLastError();
+- rc = SQLITE_BUSY;
++static void logIoerr(int nRetry){
++ if( nRetry ){
++ sqlite3_log(SQLITE_IOERR,
++ "delayed %dms for lock/sharing conflict",
++ win32IoerrRetryDelay*nRetry*(nRetry+1)/2
++ );
+ }
++}
+
+- 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
++/*************************************************************************
++** 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;
+ }
++#endif
+
+-/* Forward references to VFS methods */
+-static int winOpen(sqlite3_vfs*,const char*,sqlite3_file*,int,int*);
+-static int winDelete(sqlite3_vfs *,const char*,int);
++#define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-(int)offsetof(winFile,h)]
+
+ /*
+-** 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.
++** Acquire a lock on the handle h
+ */
+-static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
+- winShmNode **pp;
+- winShmNode *p;
+- BOOL bRc;
+- 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++){
+- bRc = osUnmapViewOfFile(p->aRegion[i].pMap);
+- OSTRACE(("SHM-PURGE-UNMAP pid=%lu, region=%d, rc=%s\n",
+- osGetCurrentProcessId(), i, bRc ? "ok" : "failed"));
+- bRc = osCloseHandle(p->aRegion[i].hMap);
+- OSTRACE(("SHM-PURGE-CLOSE pid=%lu, region=%d, rc=%s\n",
+- osGetCurrentProcessId(), i, bRc ? "ok" : "failed"));
+- }
+- 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;
+- }
+- }
++static void winceMutexAcquire(HANDLE h){
++ DWORD dwErr;
++ do {
++ dwErr = osWaitForSingleObject(h, INFINITE);
++ } while (dwErr != WAIT_OBJECT_0 && dwErr != WAIT_ABANDONED);
+ }
+-
+ /*
+-** 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.
++** Release a lock acquired by winceMutexAcquire()
+ */
+-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 */
++#define winceMutexRelease(h) ReleaseMutex(h)
+
+- assert( pDbFd->pShm==0 ); /* Not previously opened */
++/*
++** 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;
+
+- /* Allocate space for the new sqlite3_shm object. Also speculatively
+- ** allocate space for a new winShmNode and filename.
+- */
+- 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);
++ zName = utf8ToUnicode(zFilename);
++ if( zName==0 ){
++ /* out of memory */
+ return SQLITE_IOERR_NOMEM;
+ }
+- 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.
++ /* Initialize the local lockdata */
++ memset(&pFile->local, 0, sizeof(pFile->local));
++
++ /* Replace the backslashes from the filename and lowercase it
++ ** to derive a mutex name. */
++ zTok = osCharLowerW(zName);
++ for (;*zTok;zTok++){
++ if (*zTok == '\\') *zTok = '_';
++ }
++
++ /* Create/open the named mutex */
++ pFile->hMutex = osCreateMutexW(NULL, FALSE, zName);
++ if (!pFile->hMutex){
++ pFile->lastErrno = osGetLastError();
++ winLogError(SQLITE_IOERR, pFile->lastErrno,
++ "winceCreateLock1", zFilename);
++ sqlite3_free(zName);
++ return SQLITE_IOERR;
++ }
++
++ /* Acquire the mutex before continuing */
++ winceMutexAcquire(pFile->hMutex);
++
++ /* 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.
+ */
+- 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;
++ 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;
+ }
+- 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;
+- }
++ sqlite3_free(zName);
+
+- 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 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;
+ }
++ }
+
+- /* 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 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;
+ }
+- if( rc ) goto shm_open_err;
++ winceMutexRelease(pFile->hMutex);
++ osCloseHandle(pFile->hMutex);
++ pFile->hMutex = NULL;
++ return SQLITE_IOERR;
++ }
++
++ /* Initialize the shared memory if we're supposed to */
++ if( bInit ){
++ memset(pFile->shared, 0, sizeof(winceLock));
+ }
+
+- /* Make the new connection a child of the winShmNode */
+- p->pShmNode = pShmNode;
+-#ifdef SQLITE_DEBUG
+- 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);
++ winceMutexRelease(pFile->hMutex);
+ 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();
+- return rc;
+ }
+
+ /*
+-** Close a connection to shared-memory. Delete the underlying
+-** storage if deleteFlag is true.
++** Destroy the part of winFile that deals with wince locks
+ */
+-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 */
+-
+- pDbFd = (winFile*)fd;
+- p = pDbFd->pShm;
+- if( p==0 ) return SQLITE_OK;
+- pShmNode = p->pShmNode;
++static void winceDestroyLock(winFile *pFile){
++ if (pFile->hMutex){
++ /* Acquire the mutex */
++ winceMutexAcquire(pFile->hMutex);
+
+- /* 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;
++ /* 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;
++ }
++ if (pFile->local.bExclusive){
++ pFile->shared->bExclusive = FALSE;
++ }
+
+- /* Free the connection p */
+- sqlite3_free(p);
+- pDbFd->pShm = 0;
+- sqlite3_mutex_leave(pShmNode->mutex);
++ /* De-reference and close our copy of the shared memory handle */
++ osUnmapViewOfFile(pFile->shared);
++ osCloseHandle(pFile->hShared);
+
+- /* 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);
++ /* Done with the mutex */
++ winceMutexRelease(pFile->hMutex);
++ osCloseHandle(pFile->hMutex);
++ pFile->hMutex = NULL;
+ }
+- winShmLeaveMutex();
+-
+- return SQLITE_OK;
+ }
+
+-/*
+-** Change the lock state for a shared-memory segment.
++/*
++** An implementation of the LockFile() API of Windows for CE
+ */
+-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 */
++static BOOL winceLockFile(
++ LPHANDLE phFile,
++ DWORD dwFileOffsetLow,
++ DWORD dwFileOffsetHigh,
++ DWORD nNumberOfBytesToLockLow,
++ DWORD nNumberOfBytesToLockHigh
+ ){
+- 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 */
++ winFile *pFile = HANDLE_TO_WINFILE(phFile);
++ BOOL bReturn = FALSE;
+
+- 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 );
++ UNUSED_PARAMETER(dwFileOffsetHigh);
++ UNUSED_PARAMETER(nNumberOfBytesToLockHigh);
+
+- 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 (!pFile->hMutex) return TRUE;
++ winceMutexAcquire(pFile->hMutex);
+
+- /* 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;
++ /* 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;
++ }
++ }
++
++ /* 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;
++ }
++ }
++
++ /* 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;
+ }
++ }
+
+- /* Unlock the system-level locks */
+- if( (mask & allMask)==0 ){
+- rc = winShmSystemLock(pShmNode, _SHM_UNLCK, ofst+WIN_SHM_BASE, n);
+- }else{
+- rc = SQLITE_OK;
++ /* 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;
+ }
++ }
+
+- /* 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" */
++ winceMutexRelease(pFile->hMutex);
++ return bReturn;
++}
+
+- /* 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;
++/*
++** An implementation of the UnlockFile API of Windows for CE
++*/
++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);
++
++ /* 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;
+ }
+
+- /* 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;
++ /* 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;
+ }
++ }
+
+- /* 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;
+- }
++ /* 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;
+ }
+-
+- /* 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;
+- }
++ }
++ /* 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;
+ }
+ }
+- 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;
++
++ winceMutexRelease(pFile->hMutex);
++ return bReturn;
+ }
++/*
++** End of the special code for wince
++*****************************************************************************/
++#endif /* SQLITE_OS_WINCE */
+
+ /*
+-** 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.
++** Lock a file region.
+ */
+-static void winShmBarrier(
+- sqlite3_file *fd /* Database holding the shared memory */
++static BOOL winLockFile(
++ LPHANDLE phFile,
++ DWORD flags,
++ DWORD offsetLow,
++ DWORD offsetHigh,
++ DWORD numBytesLow,
++ DWORD numBytesHigh
+ ){
+- UNUSED_PARAMETER(fd);
+- /* MemoryBarrier(); // does not work -- do not know why not */
+- winShmEnterMutex();
+- winShmLeaveMutex();
++#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( isNT() ){
++ 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
+ }
+
+ /*
+-** 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 */
++** Unlock a file region.
++ */
++static BOOL winUnlockFile(
++ LPHANDLE phFile,
++ DWORD offsetLow,
++ DWORD offsetHigh,
++ DWORD numBytesLow,
++ DWORD numBytesHigh
+ ){
+- winFile *pDbFd = (winFile*)fd;
+- winShm *p = pDbFd->pShm;
+- winShmNode *pShmNode;
+- int rc = SQLITE_OK;
++#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( isNT() ){
++ 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
++}
+
+- if( !p ){
+- rc = winOpenSharedMemory(pDbFd);
+- if( rc!=SQLITE_OK ) return rc;
+- p = pDbFd->pShm;
++/*****************************************************************************
++** The next group of routines implement the I/O methods specified
++** by the sqlite3_io_methods object.
++******************************************************************************/
++
++/*
++** Some Microsoft compilers lack this definition.
++*/
++#ifndef INVALID_SET_FILE_POINTER
++# define INVALID_SET_FILE_POINTER ((DWORD)-1)
++#endif
++
++/*
++** 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 int seekWinFile(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));
++
++ 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,
++ "seekWinFile", pFile->zPath);
++ OSTRACE(("SEEK file=%p, rc=SQLITE_IOERR_SEEK\n", pFile->h));
++ return 1;
+ }
+- pShmNode = p->pShmNode;
+
+- sqlite3_mutex_enter(pShmNode->mutex);
+- assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
++ OSTRACE(("SEEK file=%p, rc=SQLITE_OK\n", pFile->h));
++ return 0;
++#else
++ /*
++ ** Same as above, except that this implementation works for WinRT.
++ */
+
+- 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 */
++ LARGE_INTEGER x; /* The new offset */
++ BOOL bRet; /* Value returned by SetFilePointerEx() */
+
+- pShmNode->szRegion = szRegion;
++ x.QuadPart = iOffset;
++ bRet = osSetFilePointerEx(pFile->h, x, 0, FILE_BEGIN);
+
+- /* 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(!bRet){
++ pFile->lastErrno = osGetLastError();
++ winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno,
++ "seekWinFile", pFile->zPath);
++ OSTRACE(("SEEK file=%p, rc=SQLITE_IOERR_SEEK\n", pFile->h));
++ return 1;
++ }
+
+- 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;
+- }
+- }
++ OSTRACE(("SEEK file=%p, rc=SQLITE_OK\n", pFile->h));
++ return 0;
++#endif
++}
+
+- /* Map the requested memory region into this processes address space. */
+- apNew = (struct ShmRegion *)sqlite3_realloc(
+- pShmNode->aRegion, (iRegion+1)*sizeof(apNew[0])
+- );
+- if( !apNew ){
+- rc = SQLITE_IOERR_NOMEM;
+- goto shmpage_out;
+- }
+- pShmNode->aRegion = apNew;
++#if SQLITE_MAX_MMAP_SIZE>0
++/* Forward references to VFS methods */
++static int winUnmapfile(winFile*);
++#endif
+
+- 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
+- );
++/*
++** 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.
++*/
++#define MX_CLOSE_ATTEMPT 3
++static int winClose(sqlite3_file *id){
++ int rc, cnt = 0;
++ winFile *pFile = (winFile*)id;
++
++ assert( id!=0 );
++#ifndef SQLITE_OMIT_WAL
++ assert( pFile->pShm==0 );
+ #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
+- );
++ assert( pFile->h!=NULL && pFile->h!=INVALID_HANDLE_VALUE );
++ OSTRACE(("CLOSE file=%p\n", pFile->h));
++
++#if SQLITE_MAX_MMAP_SIZE>0
++ rc = winUnmapfile(pFile);
++ if( rc!=SQLITE_OK ) return rc;
+ #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;
+- }
+
+- pShmNode->aRegion[pShmNode->nRegion].pMap = pMap;
+- pShmNode->aRegion[pShmNode->nRegion].hMap = hMap;
+- pShmNode->nRegion++;
++ 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);
+ }
+-
+-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{
+- *pp = 0;
++#endif
++ if( rc ){
++ pFile->h = NULL;
+ }
+- sqlite3_mutex_leave(pShmNode->mutex);
+- return rc;
++ OpenCounter(-1);
++ OSTRACE(("CLOSE file=%p, rc=%s\n", pFile->h, rc ? "ok" : "failed"));
++ return rc ? SQLITE_OK
++ : winLogError(SQLITE_IOERR_CLOSE, osGetLastError(),
++ "winClose", pFile->zPath);
+ }
+
+-#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.
++** Read data from a file into a buffer. Return SQLITE_OK if all
++** bytes were read successfully and SQLITE_IOERR if anything goes
++** wrong.
+ */
++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
++ 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 */
++
++ assert( id!=0 );
++ assert( amt>0 );
++ assert( offset>=0 );
++ SimulateIOError(return SQLITE_IOERR_READ);
++ OSTRACE(("READ file=%p, buffer=%p, amount=%d, offset=%lld, lock=%d\n",
++ pFile->h, pBuf, amt, offset, pFile->locktype));
++
+ #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,
+- "winUnmap1", pFile->zPath);
++ /* 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 file=%p, rc=SQLITE_OK\n", 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;
+ }
+- 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,
+- "winUnmap2", pFile->zPath);
+- }
+- pFile->hMap = NULL;
++#endif
++
++#if SQLITE_OS_WINCE
++ if( seekWinFile(pFile, offset) ){
++ OSTRACE(("READ file=%p, rc=SQLITE_FULL\n", 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( retryIoerr(&nRetry, &lastErrno) ) continue;
++ pFile->lastErrno = lastErrno;
++ OSTRACE(("READ file=%p, rc=SQLITE_IOERR_READ\n", pFile->h));
++ return winLogError(SQLITE_IOERR_READ, pFile->lastErrno,
++ "winRead", pFile->zPath);
++ }
++ logIoerr(nRetry);
++ 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));
++ return SQLITE_IOERR_SHORT_READ;
+ }
+- OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, rc=SQLITE_OK\n",
+- osGetCurrentProcessId(), pFile));
++
++ OSTRACE(("READ file=%p, rc=SQLITE_OK\n", pFile->h));
+ 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.
+-**
+-** 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.
++** Write data from a buffer into a file. Return SQLITE_OK on success
++** or some other error code on failure.
+ */
+-static int winMapfile(winFile *pFd, sqlite3_int64 nByte){
+- sqlite3_int64 nMap = nByte;
+- int rc;
++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( nMap>=0 || pFd->nFetchOut==0 );
+- OSTRACE(("MAP-FILE pid=%lu, pFile=%p, size=%lld\n",
+- osGetCurrentProcessId(), pFd, nByte));
++ assert( amt>0 );
++ assert( pFile );
++ SimulateIOError(return SQLITE_IOERR_WRITE);
++ SimulateDiskfullError(return SQLITE_FULL);
+
+- if( pFd->nFetchOut>0 ) return SQLITE_OK;
++ OSTRACE(("WRITE file=%p, buffer=%p, amount=%d, offset=%lld, lock=%d\n",
++ pFile->h, pBuf, amt, offset, pFile->locktype));
+
+- 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 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 file=%p, rc=SQLITE_OK\n", 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;
+ }
+ }
+- if( nMap>pFd->mmapSizeMax ){
+- nMap = pFd->mmapSizeMax;
+- }
+- nMap &= ~(sqlite3_int64)(winSysInfo.dwPageSize - 1);
+-
+- if( nMap==0 && pFd->mmapSize>0 ){
+- winUnmapfile(pFd);
+- }
+- if( nMap!=pFd->mmapSize ){
+- void *pNew = 0;
+- DWORD protect = PAGE_READONLY;
+- DWORD flags = FILE_MAP_READ;
++#endif
+
+- 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);
++#if SQLITE_OS_WINCE
++ rc = seekWinFile(pFile, offset);
++ if( rc==0 ){
++#else
++ {
+ #endif
+- if( pFd->hMap==NULL ){
+- pFd->lastErrno = osGetLastError();
+- rc = winLogError(SQLITE_IOERR_MMAP, pFd->lastErrno,
+- "winMapfile", pFd->zPath);
+- /* Log the error, but continue normal operation using xRead/xWrite */
+- OSTRACE(("MAP-FILE-CREATE pid=%lu, pFile=%p, rc=SQLITE_IOERR_MMAP\n",
+- osGetCurrentProcessId(), pFd));
+- return SQLITE_OK;
+- }
+- assert( (nMap % winSysInfo.dwPageSize)==0 );
+-#if SQLITE_OS_WINRT
+- pNew = osMapViewOfFileFromApp(pFd->hMap, flags, 0, nMap);
++#if !SQLITE_OS_WINCE
++ 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() */
++
++#if !SQLITE_OS_WINCE
++ 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( !osWriteFile(pFile->h, aRem, nRem, &nWrite, 0) ){
+ #else
+- assert( sizeof(SIZE_T)==sizeof(sqlite3_int64) || nMap<=0xffffffff );
+- pNew = osMapViewOfFile(pFd->hMap, flags, 0, 0, (SIZE_T)nMap);
++ if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, &overlapped) ){
+ #endif
+- if( pNew==NULL ){
+- osCloseHandle(pFd->hMap);
+- pFd->hMap = NULL;
+- pFd->lastErrno = osGetLastError();
+- winLogError(SQLITE_IOERR_MMAP, pFd->lastErrno,
+- "winMapfile", pFd->zPath);
+- OSTRACE(("MAP-FILE-MAP pid=%lu, pFile=%p, rc=SQLITE_IOERR_MMAP\n",
+- osGetCurrentProcessId(), pFd));
+- return SQLITE_OK;
++ if( retryIoerr(&nRetry, &lastErrno) ) continue;
++ break;
++ }
++ assert( nWrite==0 || nWrite<=(DWORD)nRem );
++ if( nWrite==0 || nWrite>(DWORD)nRem ){
++ lastErrno = osGetLastError();
++ break;
++ }
++#if !SQLITE_OS_WINCE
++ 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;
+ }
+- pFd->pMapRegion = pNew;
+- pFd->mmapSize = nMap;
+- pFd->mmapSizeActual = nMap;
+ }
+
+- OSTRACE(("MAP-FILE pid=%lu, pFile=%p, rc=SQLITE_OK\n",
+- osGetCurrentProcessId(), pFd));
++ if( rc ){
++ if( ( pFile->lastErrno==ERROR_HANDLE_DISK_FULL )
++ || ( pFile->lastErrno==ERROR_DISK_FULL )){
++ OSTRACE(("WRITE file=%p, rc=SQLITE_FULL\n", pFile->h));
++ return SQLITE_FULL;
++ }
++ OSTRACE(("WRITE file=%p, rc=SQLITE_IOERR_WRITE\n", pFile->h));
++ return winLogError(SQLITE_IOERR_WRITE, pFile->lastErrno,
++ "winWrite", pFile->zPath);
++ }else{
++ logIoerr(nRetry);
++ }
++ OSTRACE(("WRITE file=%p, rc=SQLITE_OK\n", pFile->h));
+ return SQLITE_OK;
+ }
+-#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 this function does return a pointer, the caller must eventually
+-** release the reference by calling winUnfetch().
++** Truncate an open file to a specified size
+ */
+-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 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;
+
+- OSTRACE(("FETCH pid=%lu, pFile=%p, offset=%lld, amount=%d, pp=%p\n",
+- osGetCurrentProcessId(), fd, iOff, nAmt, pp));
++ assert( pFile );
++ SimulateIOError(return SQLITE_IOERR_TRUNCATE);
++ OSTRACE(("TRUNCATE file=%p, size=%lld, lock=%d\n",
++ 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
++ ** 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;
++ }
++
++ /* SetEndOfFile() returns non-zero when successful, or zero when it fails. */
++ if( seekWinFile(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 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;
+- }
+- }
+- if( pFd->mmapSize >= iOff+nAmt ){
+- *pp = &((u8 *)pFd->pMapRegion)[iOff];
+- pFd->nFetchOut++;
+- }
++ /* 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;
+ }
+ #endif
+
+- OSTRACE(("FETCH pid=%lu, pFile=%p, pp=%p, *pp=%p, rc=SQLITE_OK\n",
+- osGetCurrentProcessId(), fd, pp, *pp));
+- return SQLITE_OK;
++ OSTRACE(("TRUNCATE file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc)));
++ return rc;
+ }
+
++#ifdef SQLITE_TEST
+ /*
+-** 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.
++** 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 winUnfetch(sqlite3_file *fd, i64 iOff, void *p){
+-#if SQLITE_MAX_MMAP_SIZE>0
+- winFile *pFd = (winFile*)fd; /* The underlying database file */
++SQLITE_API int sqlite3_sync_count = 0;
++SQLITE_API int sqlite3_fullsync_count = 0;
++#endif
+
+- /* 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) );
++/*
++** 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_TEST) && defined(SQLITE_DEBUG))
++ /*
++ ** 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
+
+- /* If p!=0, it must match the iOff value. */
+- assert( p==0 || p==&((u8 *)pFd->pMapRegion)[iOff] );
++ assert( pFile );
++ /* Check that one of SQLITE_SYNC_NORMAL or FULL was passed */
++ assert((flags&0x0F)==SQLITE_SYNC_NORMAL
++ || (flags&0x0F)==SQLITE_SYNC_FULL
++ );
+
+- OSTRACE(("UNFETCH pid=%lu, pFile=%p, offset=%lld, p=%p\n",
+- osGetCurrentProcessId(), pFd, iOff, p));
++ /* 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( 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 can be omitted - potentially improving
+- ** performance. */
+- winUnmapfile(pFd);
+- }
++ OSTRACE(("SYNC file=%p, flags=%x, lock=%d\n",
++ pFile->h, flags, pFile->locktype));
+
+- assert( pFd->nFetchOut>=0 );
++#ifndef SQLITE_TEST
++ UNUSED_PARAMETER(flags);
++#else
++ if( (flags&0x0F)==SQLITE_SYNC_FULL ){
++ sqlite3_fullsync_count++;
++ }
++ sqlite3_sync_count++;
+ #endif
+
+- OSTRACE(("UNFETCH pid=%lu, pFile=%p, rc=SQLITE_OK\n",
+- osGetCurrentProcessId(), fd));
++ /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a
++ ** no-op
++ */
++#ifdef SQLITE_NO_SYNC
+ return SQLITE_OK;
++#else
++ rc = osFlushFileBuffers(pFile->h);
++ SimulateIOError( rc=FALSE );
++ if( rc ){
++ OSTRACE(("SYNC file=%p, rc=SQLITE_OK\n", pFile->h));
++ return SQLITE_OK;
++ }else{
++ pFile->lastErrno = osGetLastError();
++ OSTRACE(("SYNC file=%p, rc=SQLITE_IOERR_FSYNC\n", pFile->h));
++ return winLogError(SQLITE_IOERR_FSYNC, pFile->lastErrno,
++ "winSync", pFile->zPath);
++ }
++#endif
+ }
+
+ /*
+-** Here ends the implementation of all sqlite3_file methods.
+-**
+-********************** End sqlite3_file Methods *******************************
+-******************************************************************************/
+-
+-/*
+-** This vector defines all the methods that can operate on an
+-** sqlite3_file for win32.
++** Determine the current size of a file in bytes
+ */
+-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 int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){
++ winFile *pFile = (winFile*)id;
++ int rc = SQLITE_OK;
+
+-/****************************************************************************
+-**************************** sqlite3_vfs methods ****************************
+-**
+-** This division contains the implementation of methods on the
+-** sqlite3_vfs object.
+-*/
++ assert( id!=0 );
++ assert( pSize!=0 );
++ SimulateIOError(return SQLITE_IOERR_FSTAT);
++ OSTRACE(("SIZE file=%p, pSize=%p\n", pFile->h, pSize));
+
+-/*
+-** 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 *convertUtf8Filename(const char *zFilename){
+- void *zConverted = 0;
+- if( isNT() ){
+- zConverted = utf8ToUnicode(zFilename);
++#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);
++ }
+ }
+-#ifdef SQLITE_WIN32_HAS_ANSI
+- else{
+- zConverted = sqlite3_win32_utf8_to_mbcs(zFilename);
++#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);
++ }
+ }
+ #endif
+- /* caller will handle out of memory */
+- return zConverted;
++ OSTRACE(("SIZE file=%p, pSize=%p, *pSize=%lld, rc=%s\n",
++ pFile->h, pSize, *pSize, sqlite3ErrName(rc)));
++ return rc;
+ }
+
+ /*
+-** Create a temporary file name in zBuf. zBuf must be big enough to
+-** hold at pVfs->mxPathname characters.
++** LOCKFILE_FAIL_IMMEDIATELY is undefined on some Windows systems.
+ */
+-static int getTempname(int nBuf, char *zBuf){
+- static char zChars[] =
+- "abcdefghijklmnopqrstuvwxyz"
+- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+- "0123456789";
+- size_t i, j;
+- int nTempPath;
+- char zTempPath[MAX_PATH+2];
++#ifndef LOCKFILE_FAIL_IMMEDIATELY
++# define LOCKFILE_FAIL_IMMEDIATELY 1
++#endif
+
+- /* 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 );
++#ifndef LOCKFILE_EXCLUSIVE_LOCK
++# define LOCKFILE_EXCLUSIVE_LOCK 2
++#endif
+
+- memset(zTempPath, 0, MAX_PATH+2);
++/*
++** 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
+
+- if( sqlite3_temp_directory ){
+- sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", sqlite3_temp_directory);
+- }
+-#if !SQLITE_OS_WINRT
+- else if( isNT() ){
+- char *zMulti;
+- WCHAR zWidePath[MAX_PATH];
+- osGetTempPathW(MAX_PATH-30, zWidePath);
+- zMulti = unicodeToUtf8(zWidePath);
+- if( zMulti ){
+- sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zMulti);
+- sqlite3_free(zMulti);
+- }else{
+- OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
+- return SQLITE_IOERR_NOMEM;
+- }
++/*
++** 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 getReadLock(winFile *pFile){
++ int res;
++ OSTRACE(("READ-LOCK file=%p, lock=%d\n", pFile->h, pFile->locktype));
++ if( isNT() ){
++#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
+ }
+ #ifdef SQLITE_WIN32_HAS_ANSI
+ else{
+- char *zUtf8;
+- char zMbcsPath[MAX_PATH];
+- osGetTempPathA(MAX_PATH-30, zMbcsPath);
+- zUtf8 = sqlite3_win32_mbcs_to_utf8(zMbcsPath);
+- if( zUtf8 ){
+- sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zUtf8);
+- sqlite3_free(zUtf8);
+- }else{
+- OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
+- return SQLITE_IOERR_NOMEM;
+- }
++ 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
+-#endif
+-
+- /* Check that the output buffer is large enough for the temporary file
+- ** name. If it is not, return SQLITE_ERROR.
+- */
+- nTempPath = sqlite3Strlen30(zTempPath);
+-
+- if( (nTempPath + sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX) + 18) >= nBuf ){
+- OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n"));
+- return SQLITE_ERROR;
+- }
+-
+- for(i=nTempPath; i>0 && zTempPath[i-1]=='\\'; i--){}
+- zTempPath[i] = 0;
+-
+- sqlite3_snprintf(nBuf-18, zBuf, (nTempPath > 0) ?
+- "%s\\"SQLITE_TEMP_FILE_PREFIX : SQLITE_TEMP_FILE_PREFIX,
+- zTempPath);
+- 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( res == 0 ){
++ pFile->lastErrno = osGetLastError();
++ /* No need to log a failure to lock */
+ }
+- zBuf[j] = 0;
+- zBuf[j+1] = 0;
+-
+- OSTRACE(("TEMP-FILENAME name=%s, rc=SQLITE_OK\n", zBuf));
+- return SQLITE_OK;
++ OSTRACE(("READ-LOCK file=%p, rc=%s\n", pFile->h, sqlite3ErrName(res)));
++ return res;
+ }
+
+ /*
+-** 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.
++** Undo a readlock
+ */
+-static int winIsDir(const void *zConverted){
+- DWORD attr;
+- int rc = 0;
++static int unlockReadLock(winFile *pFile){
++ int res;
+ DWORD lastErrno;
+-
++ OSTRACE(("READ-UNLOCK file=%p, lock=%d\n", pFile->h, pFile->locktype));
+ if( isNT() ){
+- int cnt = 0;
+- WIN32_FILE_ATTRIBUTE_DATA sAttrData;
+- memset(&sAttrData, 0, sizeof(sAttrData));
+- while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted,
+- GetFileExInfoStandard,
+- &sAttrData)) && retryIoerr(&cnt, &lastErrno) ){}
+- if( !rc ){
+- return 0; /* Invalid name? */
+- }
+- attr = sAttrData.dwFileAttributes;
+-#if SQLITE_OS_WINCE==0
+- }else{
+- attr = osGetFileAttributesA((char*)zConverted);
++ 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,
++ "unlockReadLock", pFile->zPath);
+ }
+- return (attr!=INVALID_FILE_ATTRIBUTES) && (attr&FILE_ATTRIBUTE_DIRECTORY);
++ OSTRACE(("READ-UNLOCK file=%p, rc=%s\n", pFile->h, sqlite3ErrName(res)));
++ return res;
+ }
+
+ /*
+-** Open a file.
++** 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.
+ */
+-static int winOpen(
+- sqlite3_vfs *pVfs, /* Not used */
+- 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;
+- DWORD dwDesiredAccess;
+- DWORD dwShareMode;
+- DWORD dwCreationDisposition;
+- DWORD dwFlagsAndAttributes = 0;
+-#if SQLITE_OS_WINCE
+- int isTemp = 0;
+-#endif
++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;
+- 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[MAX_PATH+2]; /* Buffer used to create temp filename */
+-
+- 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
++ DWORD lastErrno = NO_ERROR;
+
+- OSTRACE(("OPEN name=%s, pFile=%p, flags=%x, pOutFlags=%p\n",
+- zUtf8Name, id, flags, pOutFlags));
++ assert( id!=0 );
++ OSTRACE(("LOCK file=%p, oldLock=%d(%d), newLock=%d\n",
++ pFile->h, pFile->locktype, pFile->sharedLockByte, locktype));
+
+- /* 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.
++ /* 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.
+ */
+- 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 );
++ if( pFile->locktype>=locktype ){
++ OSTRACE(("LOCK-HELD file=%p, rc=SQLITE_OK\n", pFile->h));
++ return SQLITE_OK;
++ }
+
+- /* 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
+- );
++ /* 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 );
+
+- assert( pFile!=0 );
+- memset(pFile, 0, sizeof(winFile));
+- pFile->h = INVALID_HANDLE_VALUE;
++ /* 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.
++ */
++ OSTRACE(("LOCK-PENDING-FAIL file=%p, count=%d, rc=%s\n",
++ pFile->h, cnt, sqlite3ErrName(res)));
++ if( cnt ) sqlite3_win32_sleep(1);
++ }
++ gotPendingLock = res;
++ if( !res ){
++ lastErrno = osGetLastError();
++ }
++ }
+
+-#if SQLITE_OS_WINRT
+- if( !sqlite3_temp_directory ){
+- sqlite3_log(SQLITE_ERROR,
+- "sqlite3_temp_directory variable should be set for WinRT");
++ /* Acquire a shared lock
++ */
++ if( locktype==SHARED_LOCK && res ){
++ assert( pFile->locktype==NO_LOCK );
++ res = getReadLock(pFile);
++ if( res ){
++ newLocktype = SHARED_LOCK;
++ }else{
++ lastErrno = osGetLastError();
++ }
+ }
+-#endif
+
+- /* If the second argument to this function is NULL, generate a
+- ** temporary file name to use
++ /* Acquire a RESERVED lock
+ */
+- if( !zUtf8Name ){
+- assert(isDelete && !isOpenJournal);
+- memset(zTmpname, 0, MAX_PATH+2);
+- rc = getTempname(MAX_PATH+2, zTmpname);
+- if( rc!=SQLITE_OK ){
+- OSTRACE(("OPEN name=%s, rc=%s", zUtf8Name, sqlite3ErrName(rc)));
+- return rc;
++ 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();
+ }
+- zUtf8Name = zTmpname;
+ }
+
+- /* Database filenames are double-zero terminated if they are not
+- ** URIs with parameters. Hence, they can always be passed into
+- ** sqlite3_uri_parameter().
++ /* Acquire a PENDING lock
+ */
+- assert( (eType!=SQLITE_OPEN_MAIN_DB) || (flags & SQLITE_OPEN_URI) ||
+- zUtf8Name[strlen(zUtf8Name)+1]==0 );
++ if( locktype==EXCLUSIVE_LOCK && res ){
++ newLocktype = PENDING_LOCK;
++ gotPendingLock = 0;
++ }
+
+- /* Convert the filename to the system encoding. */
+- zConverted = convertUtf8Filename(zUtf8Name);
+- if( zConverted==0 ){
+- OSTRACE(("OPEN name=%s, rc=SQLITE_IOERR_NOMEM", zUtf8Name));
+- return SQLITE_IOERR_NOMEM;
++ /* Acquire an EXCLUSIVE lock
++ */
++ if( locktype==EXCLUSIVE_LOCK && res ){
++ assert( pFile->locktype>=SHARED_LOCK );
++ res = unlockReadLock(pFile);
++ res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, SHARED_FIRST, 0,
++ SHARED_SIZE, 0);
++ if( res ){
++ newLocktype = EXCLUSIVE_LOCK;
++ }else{
++ lastErrno = osGetLastError();
++ getReadLock(pFile);
++ }
+ }
+
+- if( winIsDir(zConverted) ){
+- sqlite3_free(zConverted);
+- OSTRACE(("OPEN name=%s, rc=SQLITE_CANTOPEN_ISDIR", zUtf8Name));
+- return SQLITE_CANTOPEN_ISDIR;
++ /* 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( isReadWrite ){
+- dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
++ /* Update the state of the lock has held in the file descriptor then
++ ** return the appropriate result code.
++ */
++ if( res ){
++ rc = SQLITE_OK;
+ }else{
+- dwDesiredAccess = GENERIC_READ;
++ OSTRACE(("LOCK-FAIL file=%p, wanted=%d, got=%d\n",
++ pFile->h, locktype, newLocktype));
++ pFile->lastErrno = lastErrno;
++ rc = SQLITE_BUSY;
+ }
++ pFile->locktype = (u8)newLocktype;
++ OSTRACE(("LOCK file=%p, lock=%d, rc=%s\n",
++ pFile->h, pFile->locktype, sqlite3ErrName(rc)));
++ return rc;
++}
+
+- /* 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;
++/*
++** 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.
++*/
++static int winCheckReservedLock(sqlite3_file *id, int *pResOut){
++ int rc;
++ 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 ){
++ rc = 1;
++ OSTRACE(("TEST-WR-LOCK file=%p, rc=%d (local)\n", pFile->h, rc));
+ }else{
+- /* Opens a file, only if it exists. */
+- dwCreationDisposition = OPEN_EXISTING;
++ rc = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS,RESERVED_BYTE, 0, 1, 0);
++ if( rc ){
++ winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0);
++ }
++ rc = !rc;
++ OSTRACE(("TEST-WR-LOCK file=%p, rc=%d (remote)\n", pFile->h, rc));
+ }
++ *pResOut = rc;
++ OSTRACE(("TEST-WR-LOCK file=%p, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n",
++ pFile->h, pResOut, *pResOut));
++ return SQLITE_OK;
++}
+
+- dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
++/*
++** 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;
++*/
++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 && !getReadLock(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( type>=RESERVED_LOCK ){
++ winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0);
++ }
++ if( locktype==NO_LOCK && type>=SHARED_LOCK ){
++ unlockReadLock(pFile);
++ }
++ if( type>=PENDING_LOCK ){
++ winUnlockFile(&pFile->h, PENDING_BYTE, 0, 1, 0);
++ }
++ pFile->locktype = (u8)locktype;
++ OSTRACE(("UNLOCK file=%p, lock=%d, rc=%s\n",
++ pFile->h, pFile->locktype, sqlite3ErrName(rc)));
++ return rc;
++}
+
+- 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
++/*
++** If *pArg is inititially 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.
++*/
++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{
+- dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
++ pFile->ctrlFlags |= mask;
+ }
+- /* 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
++}
+
+- if( isNT() ){
+-#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 &&
+- retryIoerr(&cnt, &lastErrno) ){
+- /* Noop */
++/* Forward declaration */
++static int getTempname(int nBuf, char *zBuf);
++
++/*
++** 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("win32");
++ OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
++ return SQLITE_OK;
+ }
+-#else
+- while( (h = osCreateFileW((LPCWSTR)zConverted,
+- dwDesiredAccess,
+- dwShareMode, NULL,
+- dwCreationDisposition,
+- dwFlagsAndAttributes,
+- NULL))==INVALID_HANDLE_VALUE &&
+- retryIoerr(&cnt, &lastErrno) ){
+- /* Noop */
++ case SQLITE_FCNTL_WIN32_AV_RETRY: {
++ int *a = (int*)pArg;
++ if( a[0]>0 ){
++ win32IoerrRetry = a[0];
++ }else{
++ a[0] = win32IoerrRetry;
++ }
++ if( a[1]>0 ){
++ win32IoerrRetryDelay = a[1];
++ }else{
++ a[1] = win32IoerrRetryDelay;
++ }
++ OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
++ return SQLITE_OK;
+ }
+-#endif
+- }
+-#ifdef SQLITE_WIN32_HAS_ANSI
+- else{
+- while( (h = osCreateFileA((LPCSTR)zConverted,
+- dwDesiredAccess,
+- dwShareMode, NULL,
+- dwCreationDisposition,
+- dwFlagsAndAttributes,
+- NULL))==INVALID_HANDLE_VALUE &&
+- retryIoerr(&cnt, &lastErrno) ){
+- /* Noop */
++ case SQLITE_FCNTL_TEMPFILENAME: {
++ char *zTFile = sqlite3MallocZero( pFile->pVfs->mxPathname );
++ if( zTFile ){
++ getTempname(pFile->pVfs->mxPathname, zTFile);
++ *(char**)pArg = zTFile;
++ }
++ OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
++ return SQLITE_OK;
+ }
+- }
+-#endif
+- logIoerr(cnt);
+-
+- 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);
+- if( isReadWrite && !isExclusive ){
+- return winOpen(pVfs, zName, id,
+- ((flags|SQLITE_OPEN_READONLY) &
+- ~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)),
+- pOutFlags);
+- }else{
+- return SQLITE_CANTOPEN_BKPT;
++#if SQLITE_MAX_MMAP_SIZE>0
++ case SQLITE_FCNTL_MMAP_SIZE: {
++ i64 newLimit = *(i64*)pArg;
++ if( newLimit>sqlite3GlobalConfig.mxMmap ){
++ newLimit = sqlite3GlobalConfig.mxMmap;
++ }
++ *(i64*)pArg = pFile->mmapSizeMax;
++ if( newLimit>=0 ) pFile->mmapSizeMax = newLimit;
++ OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
++ return SQLITE_OK;
+ }
++#endif
+ }
++ OSTRACE(("FCNTL file=%p, rc=SQLITE_NOTFOUND\n", pFile->h));
++ return SQLITE_NOTFOUND;
++}
+
+- if( pOutFlags ){
+- if( isReadWrite ){
+- *pOutFlags = SQLITE_OPEN_READWRITE;
+- }else{
+- *pOutFlags = SQLITE_OPEN_READONLY;
+- }
+- }
++/*
++** 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;
++}
+
+- 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"));
++/*
++** 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);
++}
+
+-#if SQLITE_OS_WINCE
+- if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB
+- && (rc = winceCreateLock(zName, pFile))!=SQLITE_OK
+- ){
+- osCloseHandle(h);
+- sqlite3_free(zConverted);
+- OSTRACE(("OPEN-CE-LOCK name=%s, rc=%s\n", zName, sqlite3ErrName(rc)));
+- return rc;
+- }
+- if( isTemp ){
+- pFile->zDeleteOnClose = zConverted;
+- }else
+-#endif
+- {
+- sqlite3_free(zConverted);
+- }
++/*
++** 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.
++*/
++SYSTEM_INFO winSysInfo;
+
+- 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
++#ifndef SQLITE_OMIT_WAL
+
+- OpenCounter(+1);
+- return rc;
++/*
++** 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));
++}
++#ifdef SQLITE_DEBUG
++static int winShmMutexHeld(void) {
++ return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
++}
++#endif
+
+ /*
+-** Delete the named file.
++** 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.
+ **
+-** 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.
+ */
+-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;
+- void *zConverted;
+- UNUSED_PARAMETER(pVfs);
+- UNUSED_PARAMETER(syncDir);
++struct winShmNode {
++ sqlite3_mutex *mutex; /* Mutex to access this object */
++ char *zFilename; /* Name of the file */
++ winFile hFile; /* File handle from winOpen */
+
+- SimulateIOError(return SQLITE_IOERR_DELETE);
+- OSTRACE(("DELETE name=%s, syncDir=%d\n", zFilename, syncDir));
++ 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 */
+
+- zConverted = convertUtf8Filename(zFilename);
+- if( zConverted==0 ){
+- return SQLITE_IOERR_NOMEM;
+- }
+- if( isNT() ){
+- 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;
+- }
+-#else
+- attr = osGetFileAttributesW(zConverted);
++ 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
++ u8 nextShmId; /* Next available winShm.id value */
+ #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 ( !retryIoerr(&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 ( !retryIoerr(&cnt, &lastErrno) ){
+- rc = SQLITE_ERROR; /* No more retries. */
+- break;
+- }
+- } while(1);
+- }
++};
++
++/*
++** A global array of all winShmNode objects.
++**
++** The winShmMutexHeld() must be true while reading or writing this list.
++*/
++static winShmNode *winShmNodeList = 0;
++
++/*
++** 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.
++*/
++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 */
++#ifdef SQLITE_DEBUG
++ u8 id; /* Id of this connection with its winShmNode */
+ #endif
+- if( rc && rc!=SQLITE_IOERR_DELETE_NOENT ){
+- rc = winLogError(SQLITE_IOERR_DELETE, lastErrno,
+- "winDelete", zFilename);
+- }else{
+- logIoerr(cnt);
+- }
+- sqlite3_free(zConverted);
+- OSTRACE(("DELETE name=%s, rc=%s\n", zFilename, sqlite3ErrName(rc)));
+- return rc;
+-}
++};
+
+ /*
+-** Check the existence and status of a file.
++** Constants used for locking
+ */
+-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 */
++#define WIN_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */
++#define WIN_SHM_DMS (WIN_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */
++
++/*
++** 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 */
+ ){
+- DWORD attr;
+- int rc = 0;
+- DWORD lastErrno;
+- void *zConverted;
+- UNUSED_PARAMETER(pVfs);
++ int rc = 0; /* Result code form Lock/UnlockFileEx() */
+
+- SimulateIOError( return SQLITE_IOERR_ACCESS; );
+- OSTRACE(("ACCESS name=%s, flags=%x, pResOut=%p\n",
+- zFilename, flags, pResOut));
++ /* Access to the winShmNode object is serialized by the caller */
++ assert( sqlite3_mutex_held(pFile->mutex) || pFile->nRef==0 );
+
+- zConverted = convertUtf8Filename(zFilename);
+- if( zConverted==0 ){
+- OSTRACE(("ACCESS name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename));
+- return SQLITE_IOERR_NOMEM;
+- }
+- if( isNT() ){
+- int cnt = 0;
+- WIN32_FILE_ATTRIBUTE_DATA sAttrData;
+- memset(&sAttrData, 0, sizeof(sAttrData));
+- while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted,
+- GetFileExInfoStandard,
+- &sAttrData)) && retryIoerr(&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{
+- logIoerr(cnt);
+- if( lastErrno!=ERROR_FILE_NOT_FOUND && lastErrno!=ERROR_PATH_NOT_FOUND ){
+- winLogError(SQLITE_IOERR_ACCESS, lastErrno, "winAccess", zFilename);
+- sqlite3_free(zConverted);
+- return SQLITE_IOERR_ACCESS;
+- }else{
+- attr = INVALID_FILE_ATTRIBUTES;
+- }
+- }
+- }
+-#ifdef SQLITE_WIN32_HAS_ANSI
+- else{
+- attr = osGetFileAttributesA((char*)zConverted);
++ OSTRACE(("SHM-LOCK file=%p, lock=%d, offset=%d, size=%d\n",
++ pFile->hFile.h, lockType, ofst, nByte));
++
++ /* 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);
+ }
+-#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( rc!= 0 ){
++ rc = SQLITE_OK;
++ }else{
++ pFile->lastErrno = osGetLastError();
++ rc = SQLITE_BUSY;
+ }
+- *pResOut = rc;
+- OSTRACE(("ACCESS name=%s, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n",
+- zFilename, pResOut, *pResOut));
+- 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);
+
+ /*
+-** 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).
++** 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 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 ( zPathname[0]=='/' || zPathname[0]=='\\' ){
+- return TRUE;
+- }
+-
+- /*
+- ** 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 ( sqlite3Isalpha(zPathname[0]) && zPathname[1]==':' ){
+- return TRUE;
++static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
++ winShmNode **pp;
++ winShmNode *p;
++ BOOL bRc;
++ 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++){
++ bRc = osUnmapViewOfFile(p->aRegion[i].pMap);
++ OSTRACE(("SHM-PURGE-UNMAP pid=%lu, region=%d, rc=%s\n",
++ osGetCurrentProcessId(), i, bRc ? "ok" : "failed"));
++ bRc = osCloseHandle(p->aRegion[i].hMap);
++ OSTRACE(("SHM-PURGE-CLOSE pid=%lu, region=%d, rc=%s\n",
++ osGetCurrentProcessId(), i, bRc ? "ok" : "failed"));
++ }
++ 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;
++ }
+ }
+-
+- /*
+- ** 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;
+ }
+
+ /*
+-** Turn a relative pathname into a full pathname. Write the full
+-** pathname into zOut[]. zOut[] will be at least pVfs->mxPathname
+-** bytes in size.
++** 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 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 */
+-){
+-
+-#if defined(__CYGWIN__)
+- SimulateIOError( return SQLITE_ERROR );
+- UNUSED_PARAMETER(nFull);
+- assert( pVfs->mxPathname>=MAX_PATH );
+- 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[MAX_PATH+1];
+- memset(zOut, 0, MAX_PATH+1);
+- cygwin_conv_path(CCP_POSIX_TO_WIN_A|CCP_RELATIVE, zRelative, zOut,
+- MAX_PATH+1);
+- sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s\\%s",
+- sqlite3_data_directory, zOut);
+- }else{
+- cygwin_conv_path(CCP_POSIX_TO_WIN_A, zRelative, zFull, nFull);
+- }
+- 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\\%s",
+- sqlite3_data_directory, zRelative);
+- }else{
+- sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zRelative);
+- }
+- return SQLITE_OK;
+-#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 */
+
+-#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__)
+- DWORD nByte;
+- void *zConverted;
+- char *zOut;
++ assert( pDbFd->pShm==0 ); /* Not previously opened */
+
+- /* If this path name begins with "/X:", where "X" is any alphabetic
+- ** character, discard the initial "/" from the pathname.
++ /* Allocate space for the new sqlite3_shm object. Also speculatively
++ ** allocate space for a new winShmNode and filename.
+ */
+- if( zRelative[0]=='/' && sqlite3Isalpha(zRelative[1]) && zRelative[2]==':' ){
+- zRelative++;
++ 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);
+
+- /* 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.
++ /* Look to see if there is an existing winShmNode that can be used.
++ ** If no matching winShmNode currently exists, create a new one.
+ */
+- 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.
++ 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.
+ */
+- sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s\\%s",
+- sqlite3_data_directory, zRelative);
+- return SQLITE_OK;
+- }
+- zConverted = convertUtf8Filename(zRelative);
+- if( zConverted==0 ){
+- return SQLITE_IOERR_NOMEM;
++ if( sqlite3StrICmp(pShmNode->zFilename, pNew->zFilename)==0 ) break;
+ }
+- if( isNT() ){
+- LPWSTR zTemp;
+- nByte = osGetFullPathNameW((LPCWSTR)zConverted, 0, 0, 0);
+- if( nByte==0 ){
+- winLogError(SQLITE_ERROR, osGetLastError(),
+- "GetFullPathNameW1", zConverted);
+- sqlite3_free(zConverted);
+- return SQLITE_CANTOPEN_FULLPATH;
+- }
+- 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 ){
+- winLogError(SQLITE_ERROR, osGetLastError(),
+- "GetFullPathNameW2", zConverted);
+- sqlite3_free(zConverted);
+- sqlite3_free(zTemp);
+- return SQLITE_CANTOPEN_FULLPATH;
++ 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;
+ }
+- sqlite3_free(zConverted);
+- zOut = unicodeToUtf8(zTemp);
+- sqlite3_free(zTemp);
+- }
+-#ifdef SQLITE_WIN32_HAS_ANSI
+- else{
+- char *zTemp;
+- nByte = osGetFullPathNameA((char*)zConverted, 0, 0, 0);
+- if( nByte==0 ){
+- winLogError(SQLITE_ERROR, osGetLastError(),
+- "GetFullPathNameA1", zConverted);
+- sqlite3_free(zConverted);
+- return SQLITE_CANTOPEN_FULLPATH;
++
++ 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;
+ }
+- nByte += 3;
+- zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) );
+- if( zTemp==0 ){
+- sqlite3_free(zConverted);
+- return SQLITE_IOERR_NOMEM;
++
++ /* 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);
++ }
+ }
+- nByte = osGetFullPathNameA((char*)zConverted, nByte, zTemp, 0);
+- if( nByte==0 ){
+- winLogError(SQLITE_ERROR, osGetLastError(),
+- "GetFullPathNameA2", zConverted);
+- sqlite3_free(zConverted);
+- sqlite3_free(zTemp);
+- return SQLITE_CANTOPEN_FULLPATH;
++ if( rc==SQLITE_OK ){
++ winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1);
++ rc = winShmSystemLock(pShmNode, _SHM_RDLCK, WIN_SHM_DMS, 1);
+ }
+- 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;
++ if( rc ) goto shm_open_err;
+ }
++
++ /* Make the new connection a child of the winShmNode */
++ p->pShmNode = pShmNode;
++#ifdef SQLITE_DEBUG
++ 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();
++ return rc;
+ }
+
+-#ifndef SQLITE_OMIT_LOAD_EXTENSION
+-/*
+-** Interfaces for opening a shared library, finding entry points
+-** within the shared library, and closing the shared library.
+-*/
+ /*
+-** Interfaces for opening a shared library, finding entry points
+-** within the shared library, and closing the shared library.
++** Close a connection to shared-memory. Delete the underlying
++** storage if deleteFlag is true.
+ */
+-static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){
+- HANDLE h;
+- void *zConverted = convertUtf8Filename(zFilename);
+- UNUSED_PARAMETER(pVfs);
+- if( zConverted==0 ){
+- return 0;
+- }
+- if( isNT() ){
+-#if SQLITE_OS_WINRT
+- h = osLoadPackagedLibrary((LPCWSTR)zConverted, 0);
+-#else
+- h = osLoadLibraryW((LPCWSTR)zConverted);
+-#endif
+- }
+-#ifdef SQLITE_WIN32_HAS_ANSI
+- else{
+- h = osLoadLibraryA((char*)zConverted);
+- }
+-#endif
+- sqlite3_free(zConverted);
+- return (void*)h;
+-}
+-static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
+- UNUSED_PARAMETER(pVfs);
+- getLastErrorMsg(osGetLastError(), nBuf, zBufOut);
+-}
+-static void (*winDlSym(sqlite3_vfs *pVfs,void *pH,const char *zSym))(void){
+- UNUSED_PARAMETER(pVfs);
+- return (void(*)(void))osGetProcAddressA((HANDLE)pH, zSym);
+-}
+-static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){
+- UNUSED_PARAMETER(pVfs);
+- osFreeLibrary((HANDLE)pHandle);
+-}
+-#else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */
+- #define winDlOpen 0
+- #define winDlError 0
+- #define winDlSym 0
+- #define winDlClose 0
+-#endif
++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 */
+
++ pDbFd = (winFile*)fd;
++ p = pDbFd->pShm;
++ if( p==0 ) return SQLITE_OK;
++ pShmNode = p->pShmNode;
+
+-/*
+-** Write up to nBuf bytes of randomness into zBuf.
+-*/
+-static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
+- int n = 0;
+- UNUSED_PARAMETER(pVfs);
+-#if defined(SQLITE_TEST)
+- 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);
+- }
+-#endif
+- return n;
+-}
++ /* 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;
+
++ /* Free the connection p */
++ sqlite3_free(p);
++ pDbFd->pShm = 0;
++ sqlite3_mutex_leave(pShmNode->mutex);
+
+-/*
+-** 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;
++ /* 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();
++
++ return SQLITE_OK;
+ }
+
+ /*
+-** 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.
++** Change the lock state for a shared-memory segment.
+ */
+-#ifdef SQLITE_TEST
+-SQLITE_API int sqlite3_current_time = 0; /* Fake system time in seconds since 1970. */
+-#endif
++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 */
+
+-/*
+-** 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).
+- */
+- 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;
++ 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 );
+
+-#if SQLITE_OS_WINCE
+- SYSTEMTIME time;
+- osGetSystemTime(&time);
+- /* if SystemTimeToFileTime() fails, it returns zero. */
+- if (!osSystemTimeToFileTime(&time,&ft)){
+- return SQLITE_ERROR;
+- }
+-#else
+- osGetSystemTimeAsFileTime( &ft );
+-#endif
++ 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 */
+
+- *piNow = winFiletimeEpoch +
+- ((((sqlite3_int64)ft.dwHighDateTime)*max32BitValue) +
+- (sqlite3_int64)ft.dwLowDateTime)/(sqlite3_int64)10000;
++ /* 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;
++ }
+
+-#ifdef SQLITE_TEST
+- if( sqlite3_current_time ){
+- *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch;
++ /* Unlock the system-level locks */
++ if( (mask & allMask)==0 ){
++ rc = winShmSystemLock(pShmNode, _SHM_UNLCK, ofst+WIN_SHM_BASE, n);
++ }else{
++ rc = SQLITE_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" */
++
++ /* 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;
++ }
++ }
++
++ /* 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;
++ }
++ }
++
++ /* 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;
++ }
++ }
+ }
+-#endif
+- UNUSED_PARAMETER(pVfs);
+- return SQLITE_OK;
++ 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;
+ }
+
+ /*
+-** 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.
++** 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.
+ */
+-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 void winShmBarrier(
++ sqlite3_file *fd /* Database holding the shared memory */
++){
++ UNUSED_PARAMETER(fd);
++ /* MemoryBarrier(); // does not work -- do not know why not */
++ winShmEnterMutex();
++ winShmLeaveMutex();
+ }
+
+ /*
+-** 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.
++** 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.
+ **
+-** 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:
++** If an error occurs, an error code is returned and *pp is set to NULL.
+ **
+-** int xGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
+-** assert(zBuf[0]=='\0');
+-** return 0;
+-** }
++** 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.
+ **
+-** 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.
++** 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 winGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
+- UNUSED_PARAMETER(pVfs);
+- return getLastErrorMsg(osGetLastError(), nBuf, zBuf);
+-}
++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 *p = pDbFd->pShm;
++ winShmNode *pShmNode;
++ int rc = SQLITE_OK;
+
+-/*
+-** Initialize and deinitialize the operating system interface.
+-*/
+-SQLITE_API int sqlite3_os_init(void){
+- static sqlite3_vfs winVfs = {
+- 3, /* iVersion */
+- sizeof(winFile), /* szOsFile */
+- MAX_PATH, /* 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( !p ){
++ rc = winOpenSharedMemory(pDbFd);
++ if( rc!=SQLITE_OK ) return rc;
++ p = pDbFd->pShm;
++ }
++ pShmNode = p->pShmNode;
+
+- /* Double-check that the aSyscall[] array has been constructed
+- ** correctly. See ticket [bb3a86e890c8e96ab] */
+- assert( ArraySize(aSyscall)==74 );
++ sqlite3_mutex_enter(pShmNode->mutex);
++ assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
+
+- /* get memory map allocation granularity */
+- memset(&winSysInfo, 0, sizeof(SYSTEM_INFO));
++ 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_realloc(
++ 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
+- osGetNativeSystemInfo(&winSysInfo);
++ 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
+- osGetSystemInfo(&winSysInfo);
++ pMap = osMapViewOfFile(hMap, FILE_MAP_WRITE | FILE_MAP_READ,
++ 0, iOffset - iOffsetShift, szRegion + iOffsetShift
++ );
+ #endif
+- assert( winSysInfo.dwAllocationGranularity>0 );
+- assert( winSysInfo.dwPageSize>0 );
++ 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;
++ }
+
+- sqlite3_vfs_register(&winVfs, 1);
+- return SQLITE_OK;
+-}
++ pShmNode->aRegion[pShmNode->nRegion].pMap = pMap;
++ pShmNode->aRegion[pShmNode->nRegion].hMap = hMap;
++ pShmNode->nRegion++;
++ }
++ }
+
+-SQLITE_API int sqlite3_os_end(void){
+-#if SQLITE_OS_WINRT
+- if( sleepObj!=NULL ){
+- osCloseHandle(sleepObj);
+- sleepObj = NULL;
++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{
++ *pp = 0;
+ }
+-#endif
+- return SQLITE_OK;
++ sqlite3_mutex_leave(pShmNode->mutex);
++ return rc;
+ }
+
+-#endif /* SQLITE_OS_WIN */
++#else
++# define winShmMap 0
++# define winShmLock 0
++# define winShmBarrier 0
++# define winShmUnmap 0
++#endif /* #ifndef SQLITE_OMIT_WAL */
+
+-/************** 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.
++** Cleans up the mapped region of the specified file, if any.
+ */
+-
+-/* Size of the Bitvec structure in bytes. */
+-#define BITVEC_SZ 512
+-
+-/* 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*))
+-
+-/* 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)
+-
+-/* 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)
+-
+-#define BITVEC_NPTR (BITVEC_USIZE/sizeof(Bitvec *))
+-
++#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,
++ "winUnmap1", 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,
++ "winUnmap2", pFile->zPath);
++ }
++ pFile->hMap = NULL;
++ }
++ OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, rc=SQLITE_OK\n",
++ osGetCurrentProcessId(), pFile));
++ return SQLITE_OK;
++}
+
+ /*
+-** 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.
++** 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 iSize>BITVEC_NBIT and iDivisor==0 then Bitvec.u.aHash[] is
+-** a hash table that will hold up to BITVEC_MXHASH distinct values.
++** 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.
+ **
+-** 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.
++** 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.
+ */
+-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;
+-};
++static int winMapfile(winFile *pFd, sqlite3_int64 nByte){
++ sqlite3_int64 nMap = nByte;
++ int rc;
+
+-/*
+-** 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;
+- }
+- return p;
+-}
++ assert( nMap>=0 || pFd->nFetchOut==0 );
++ OSTRACE(("MAP-FILE pid=%lu, pFile=%p, size=%lld\n",
++ osGetCurrentProcessId(), pFd, nByte));
+
+-/*
+-** 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( 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( 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;
++ if( nMap>pFd->mmapSizeMax ){
++ nMap = pFd->mmapSizeMax;
++ }
++ nMap &= ~(sqlite3_int64)(winSysInfo.dwPageSize - 1);
++
++ 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;
+ }
+- return 0;
++#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,
++ "winMapfile", pFd->zPath);
++ /* Log the error, but continue normal operation using xRead/xWrite */
++ OSTRACE(("MAP-FILE-CREATE pid=%lu, pFile=%p, rc=SQLITE_IOERR_MMAP\n",
++ osGetCurrentProcessId(), pFd));
++ return SQLITE_OK;
++ }
++ assert( (nMap % winSysInfo.dwPageSize)==0 );
++#if SQLITE_OS_WINRT
++ pNew = osMapViewOfFileFromApp(pFd->hMap, flags, 0, nMap);
++#else
++ assert( sizeof(SIZE_T)==sizeof(sqlite3_int64) || nMap<=0xffffffff );
++ pNew = osMapViewOfFile(pFd->hMap, flags, 0, 0, (SIZE_T)nMap);
++#endif
++ if( pNew==NULL ){
++ osCloseHandle(pFd->hMap);
++ pFd->hMap = NULL;
++ pFd->lastErrno = osGetLastError();
++ winLogError(SQLITE_IOERR_MMAP, pFd->lastErrno,
++ "winMapfile", pFd->zPath);
++ OSTRACE(("MAP-FILE-MAP pid=%lu, pFile=%p, rc=SQLITE_IOERR_MMAP\n",
++ osGetCurrentProcessId(), pFd));
++ return SQLITE_OK;
++ }
++ pFd->pMapRegion = pNew;
++ pFd->mmapSize = nMap;
++ pFd->mmapSizeActual = nMap;
+ }
++
++ OSTRACE(("MAP-FILE pid=%lu, pFile=%p, rc=SQLITE_OK\n",
++ osGetCurrentProcessId(), pFd));
++ return SQLITE_OK;
+ }
++#endif /* SQLITE_MAX_MMAP_SIZE>0 */
+
+ /*
+-** Set the i-th bit. Return 0 on success and an error code if
+-** anything goes wrong.
++** 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.
+ **
+-** 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.
++** 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.
+ **
+-** 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.
++** If this function does return a pointer, the caller must eventually
++** release the reference by calling winUnfetch().
+ */
+-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];
+- }
+- 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]);
++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;
++
++ 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;
+ }
+- sqlite3StackFree(0, aiValues);
+- return rc;
++ }
++ if( pFd->mmapSize >= iOff+nAmt ){
++ *pp = &((u8 *)pFd->pMapRegion)[iOff];
++ pFd->nFetchOut++;
+ }
+ }
+-bitvec_set_end:
+- p->nSet++;
+- p->u.aHash[h] = i;
++#endif
++
++ OSTRACE(("FETCH pid=%lu, pFile=%p, pp=%p, *pp=%p, rc=SQLITE_OK\n",
++ osGetCurrentProcessId(), fd, pp, *pp));
+ return SQLITE_OK;
+ }
+
+ /*
+-** Clear the i-th bit.
++** 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.
+ **
+-** pBuf must be a pointer to at least BITVEC_SZ bytes of temporary storage
+-** that BitvecClear can use to rebuilt its hash table.
++** 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_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;
+- }
+- }
+- if( p->iSize<=BITVEC_NBIT ){
+- p->u.aBitmap[i/BITVEC_SZELEM] &= ~(1 << (i&(BITVEC_SZELEM-1)));
++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{
+- 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];
+- }
+- }
++ /* 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
++ ** performance. */
++ winUnmapfile(pFd);
+ }
++
++ assert( pFd->nFetchOut>=0 );
++#endif
++
++ OSTRACE(("UNFETCH pid=%lu, pFile=%p, rc=SQLITE_OK\n",
++ osGetCurrentProcessId(), fd));
++ return SQLITE_OK;
+ }
+
+ /*
+-** 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(p);
+-}
++** Here ends the implementation of all sqlite3_file methods.
++**
++********************** End sqlite3_file Methods *******************************
++******************************************************************************/
+
+ /*
+-** Return the value of the iSize parameter specified when Bitvec *p
+-** was created.
++** 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.
+ */
+-SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec *p){
+- return p->iSize;
+-}
+
+-#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.
++** 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.
+ */
+-#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
++static void *convertUtf8Filename(const char *zFilename){
++ void *zConverted = 0;
++ if( isNT() ){
++ zConverted = utf8ToUnicode(zFilename);
++ }
++#ifdef SQLITE_WIN32_HAS_ANSI
++ else{
++ zConverted = sqlite3_win32_utf8_to_mbcs(zFilename);
++ }
++#endif
++ /* caller will handle out of memory */
++ return zConverted;
++}
+
+ /*
+-** 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.
+-**
+-** If a memory allocation error occurs, return -1.
++** Create a temporary file name in zBuf. zBuf must be big enough to
++** hold at pVfs->mxPathname characters.
+ */
+-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;
++static int getTempname(int nBuf, char *zBuf){
++ static char zChars[] =
++ "abcdefghijklmnopqrstuvwxyz"
++ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
++ "0123456789";
++ size_t i, j;
++ int nTempPath;
++ char zTempPath[MAX_PATH+2];
+
+- /* 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_malloc(BITVEC_SZ);
+- if( pBitvec==0 || pV==0 || pTmpSpace==0 ) goto bitvec_end;
++ /* 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 );
+
+- /* NULL pBitvec tests */
+- sqlite3BitvecSet(0, 1);
+- sqlite3BitvecClear(0, 1, pTmpSpace);
++ memset(zTempPath, 0, MAX_PATH+2);
+
+- /* 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;
+- }
++ if( sqlite3_temp_directory ){
++ sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", sqlite3_temp_directory);
++ }
++#if !SQLITE_OS_WINRT
++ else if( isNT() ){
++ char *zMulti;
++ WCHAR zWidePath[MAX_PATH];
++ osGetTempPathW(MAX_PATH-30, zWidePath);
++ zMulti = unicodeToUtf8(zWidePath);
++ if( zMulti ){
++ sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zMulti);
++ sqlite3_free(zMulti);
++ }else{
++ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
++ return SQLITE_IOERR_NOMEM;
+ }
+- 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;
+- }
++ }
++#ifdef SQLITE_WIN32_HAS_ANSI
++ else{
++ char *zUtf8;
++ char zMbcsPath[MAX_PATH];
++ osGetTempPathA(MAX_PATH-30, zMbcsPath);
++ zUtf8 = sqlite3_win32_mbcs_to_utf8(zMbcsPath);
++ if( zUtf8 ){
++ sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zUtf8);
++ sqlite3_free(zUtf8);
+ }else{
+- CLEARBIT(pV, (i+1));
+- sqlite3BitvecClear(pBitvec, i+1, pTmpSpace);
++ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
++ return SQLITE_IOERR_NOMEM;
+ }
+ }
++#endif
++#endif
+
+- /* 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.
++ /* Check that the output buffer is large enough for the temporary file
++ ** name. If it is not, return SQLITE_ERROR.
+ */
+- 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;
+- }
++ nTempPath = sqlite3Strlen30(zTempPath);
++
++ if( (nTempPath + sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX) + 18) >= nBuf ){
++ OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n"));
++ return SQLITE_ERROR;
+ }
+
+- /* Free allocated structure */
+-bitvec_end:
+- sqlite3_free(pTmpSpace);
+- sqlite3_free(pV);
+- sqlite3BitvecDestroy(pBitvec);
+- return rc;
++ for(i=nTempPath; i>0 && zTempPath[i-1]=='\\'; i--){}
++ zTempPath[i] = 0;
++
++ sqlite3_snprintf(nBuf-18, zBuf, (nTempPath > 0) ?
++ "%s\\"SQLITE_TEMP_FILE_PREFIX : SQLITE_TEMP_FILE_PREFIX,
++ zTempPath);
++ 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) ];
++ }
++ zBuf[j] = 0;
++ zBuf[j+1] = 0;
++
++ OSTRACE(("TEMP-FILENAME name=%s, rc=SQLITE_OK\n", zBuf));
++ return SQLITE_OK;
+ }
+-#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.
++** 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 winIsDir(const void *zConverted){
++ DWORD attr;
++ int rc = 0;
++ DWORD lastErrno;
++
++ if( isNT() ){
++ int cnt = 0;
++ WIN32_FILE_ATTRIBUTE_DATA sAttrData;
++ memset(&sAttrData, 0, sizeof(sAttrData));
++ while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted,
++ GetFileExInfoStandard,
++ &sAttrData)) && retryIoerr(&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);
++}
++
++/*
++** Open a file.
+ */
++static int winOpen(
++ sqlite3_vfs *pVfs, /* Not used */
++ 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;
++ 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[MAX_PATH+2]; /* Buffer used to create temp filename */
++
++ 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
++
++ 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);
+
+-/*
+-** 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 */
+- int bPurgeable; /* True if pages are on backing store */
+- 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 */
+-};
++ /* 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 );
+
+-/*
+-** 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
++ /* 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
++ );
+
+-/********************************** Linked List Management ********************/
++ assert( pFile!=0 );
++ memset(pFile, 0, sizeof(winFile));
++ pFile->h = INVALID_HANDLE_VALUE;
+
+-#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) );
++#if SQLITE_OS_WINRT
++ if( !sqlite3_temp_directory ){
++ sqlite3_log(SQLITE_ERROR,
++ "sqlite3_temp_directory variable should be set for WinRT");
+ }
+- return (p==0 || p->nRef || (p->flags&PGHDR_NEED_SYNC)==0);
+-}
+-#endif /* !NDEBUG && SQLITE_ENABLE_EXPENSIVE_ASSERT */
++#endif
+
+-/*
+-** Remove page pPage from the list of dirty pages.
+-*/
+-static void pcacheRemoveFromDirtyList(PgHdr *pPage){
+- PCache *p = pPage->pCache;
++ /* If the second argument to this function is NULL, generate a
++ ** temporary file name to use
++ */
++ if( !zUtf8Name ){
++ assert(isDelete && !isOpenJournal);
++ memset(zTmpname, 0, MAX_PATH+2);
++ rc = getTempname(MAX_PATH+2, zTmpname);
++ if( rc!=SQLITE_OK ){
++ OSTRACE(("OPEN name=%s, rc=%s", zUtf8Name, sqlite3ErrName(rc)));
++ return rc;
++ }
++ zUtf8Name = zTmpname;
++ }
+
+- assert( pPage->pDirtyNext || pPage==p->pDirtyTail );
+- assert( pPage->pDirtyPrev || pPage==p->pDirty );
++ /* 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[strlen(zUtf8Name)+1]==0 );
+
+- /* 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;
++ /* Convert the filename to the system encoding. */
++ zConverted = convertUtf8Filename(zUtf8Name);
++ if( zConverted==0 ){
++ OSTRACE(("OPEN name=%s, rc=SQLITE_IOERR_NOMEM", zUtf8Name));
++ return SQLITE_IOERR_NOMEM;
+ }
+
+- if( pPage->pDirtyNext ){
+- pPage->pDirtyNext->pDirtyPrev = pPage->pDirtyPrev;
+- }else{
+- assert( pPage==p->pDirtyTail );
+- p->pDirtyTail = pPage->pDirtyPrev;
++ if( winIsDir(zConverted) ){
++ sqlite3_free(zConverted);
++ OSTRACE(("OPEN name=%s, rc=SQLITE_CANTOPEN_ISDIR", zUtf8Name));
++ return SQLITE_CANTOPEN_ISDIR;
+ }
+- if( pPage->pDirtyPrev ){
+- pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext;
++
++ if( isReadWrite ){
++ dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
+ }else{
+- assert( pPage==p->pDirty );
+- p->pDirty = pPage->pDirtyNext;
++ dwDesiredAccess = GENERIC_READ;
+ }
+- 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;
++ /* 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;
++ }
+
+- assert( pPage->pDirtyNext==0 && pPage->pDirtyPrev==0 && p->pDirty!=pPage );
++ dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+
+- pPage->pDirtyNext = p->pDirty;
+- if( pPage->pDirtyNext ){
+- assert( pPage->pDirtyNext->pDirtyPrev==0 );
+- pPage->pDirtyNext->pDirtyPrev = pPage;
++ 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;
+ }
+- p->pDirty = pPage;
+- if( !p->pDirtyTail ){
+- p->pDirtyTail = pPage;
++ /* 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
++
++ if( isNT() ){
++#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 &&
++ retryIoerr(&cnt, &lastErrno) ){
++ /* Noop */
++ }
++#else
++ while( (h = osCreateFileW((LPCWSTR)zConverted,
++ dwDesiredAccess,
++ dwShareMode, NULL,
++ dwCreationDisposition,
++ dwFlagsAndAttributes,
++ NULL))==INVALID_HANDLE_VALUE &&
++ retryIoerr(&cnt, &lastErrno) ){
++ /* Noop */
++ }
++#endif
+ }
+- if( !p->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) ){
+- p->pSynced = pPage;
++#ifdef SQLITE_WIN32_HAS_ANSI
++ else{
++ while( (h = osCreateFileA((LPCSTR)zConverted,
++ dwDesiredAccess,
++ dwShareMode, NULL,
++ dwCreationDisposition,
++ dwFlagsAndAttributes,
++ NULL))==INVALID_HANDLE_VALUE &&
++ retryIoerr(&cnt, &lastErrno) ){
++ /* Noop */
++ }
+ }
+- expensive_assert( pcacheCheckSynced(p) );
+-}
++#endif
++ logIoerr(cnt);
+
+-/*
+-** 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){
+- PCache *pCache = p->pCache;
+- if( pCache->bPurgeable ){
+- if( p->pgno==1 ){
+- pCache->pPage1 = 0;
++ 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);
++ if( isReadWrite && !isExclusive ){
++ return winOpen(pVfs, zName, id,
++ ((flags|SQLITE_OPEN_READONLY) &
++ ~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)),
++ pOutFlags);
++ }else{
++ return SQLITE_CANTOPEN_BKPT;
+ }
+- sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, p->pPage, 0);
+ }
+-}
+
+-/*************************************************** 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);
++ if( pOutFlags ){
++ if( isReadWrite ){
++ *pOutFlags = SQLITE_OPEN_READWRITE;
++ }else{
++ *pOutFlags = SQLITE_OPEN_READONLY;
++ }
+ }
+-}
+-
+-/*
+-** 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().
+-*/
+-SQLITE_PRIVATE void 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 = szPage;
+- p->szExtra = szExtra;
+- p->bPurgeable = bPurgeable;
+- p->xStress = xStress;
+- p->pStress = pStress;
+- p->szCache = 100;
+-}
++ 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"));
+
+-/*
+-** 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){
+- assert( pCache->nRef==0 && pCache->pDirty==0 );
+- if( pCache->pCache ){
+- sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
+- pCache->pCache = 0;
+- pCache->pPage1 = 0;
++#if SQLITE_OS_WINCE
++ if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB
++ && (rc = winceCreateLock(zName, pFile))!=SQLITE_OK
++ ){
++ osCloseHandle(h);
++ sqlite3_free(zConverted);
++ OSTRACE(("OPEN-CE-LOCK name=%s, rc=%s\n", zName, sqlite3ErrName(rc)));
++ return rc;
++ }
++ if( isTemp ){
++ pFile->zDeleteOnClose = zConverted;
++ }else
++#endif
++ {
++ sqlite3_free(zConverted);
+ }
+- 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));
++ 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
++
++ OpenCounter(+1);
++ return rc;
+ }
+
+ /*
+-** Try to obtain a page from the cache.
++** Delete the named file.
++**
++** 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 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 */
++static int winDelete(
++ sqlite3_vfs *pVfs, /* Not used on win32 */
++ const char *zFilename, /* Name of file to delete */
++ int syncDir /* Not used on win32 */
+ ){
+- sqlite3_pcache_page *pPage = 0;
+- PgHdr *pPgHdr = 0;
+- int eCreate;
+-
+- assert( pCache!=0 );
+- assert( createFlag==1 || createFlag==0 );
+- assert( pgno>0 );
++ int cnt = 0;
++ int rc;
++ DWORD attr;
++ DWORD lastErrno;
++ void *zConverted;
++ UNUSED_PARAMETER(pVfs);
++ UNUSED_PARAMETER(syncDir);
+
+- /* If the pluggable cache (sqlite3_pcache*) has not been allocated,
+- ** allocate it now.
+- */
+- if( !pCache->pCache && createFlag ){
+- sqlite3_pcache *p;
+- 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;
+- }
++ SimulateIOError(return SQLITE_IOERR_DELETE);
++ OSTRACE(("DELETE name=%s, syncDir=%d\n", zFilename, syncDir));
+
+- eCreate = createFlag * (1 + (!pCache->bPurgeable || !pCache->pDirty));
+- if( pCache->pCache ){
+- pPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
++ zConverted = convertUtf8Filename(zFilename);
++ if( zConverted==0 ){
++ return SQLITE_IOERR_NOMEM;
+ }
+-
+- if( !pPage && eCreate==1 ){
+- PgHdr *pPg;
+-
+- /* 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;
+-#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));
++ if( isNT() ){
++ 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;
++ }
++#else
++ attr = osGetFileAttributesW(zConverted);
+ #endif
+- rc = pCache->xStress(pCache->pStress, pPg);
+- if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
+- return rc;
++ 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;
+ }
+- }
+-
+- pPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2);
++ if ( attr&FILE_ATTRIBUTE_DIRECTORY ){
++ rc = SQLITE_ERROR; /* Files only. */
++ break;
++ }
++ if ( osDeleteFileW(zConverted) ){
++ rc = SQLITE_OK; /* Deleted OK. */
++ break;
++ }
++ if ( !retryIoerr(&cnt, &lastErrno) ){
++ rc = SQLITE_ERROR; /* No more retries. */
++ break;
++ }
++ } while(1);
+ }
+-
+- 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;
+- }
++#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 ( !retryIoerr(&cnt, &lastErrno) ){
++ rc = SQLITE_ERROR; /* No more retries. */
++ break;
++ }
++ } while(1);
+ }
+- *ppPage = pPgHdr;
+- return (pPgHdr==0 && eCreate) ? SQLITE_NOMEM : SQLITE_OK;
++#endif
++ if( rc && rc!=SQLITE_IOERR_DELETE_NOENT ){
++ rc = winLogError(SQLITE_IOERR_DELETE, lastErrno,
++ "winDelete", zFilename);
++ }else{
++ logIoerr(cnt);
++ }
++ sqlite3_free(zConverted);
++ OSTRACE(("DELETE name=%s, rc=%s\n", zFilename, sqlite3ErrName(rc)));
++ return rc;
+ }
+
+ /*
+-** 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.
++** Check the existence and status of a file.
+ */
+-SQLITE_PRIVATE void sqlite3PcacheRelease(PgHdr *p){
+- assert( p->nRef>0 );
+- p->nRef--;
+- if( p->nRef==0 ){
+- PCache *pCache = p->pCache;
+- pCache->nRef--;
+- if( (p->flags&PGHDR_DIRTY)==0 ){
+- pcacheUnpin(p);
++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;
++ void *zConverted;
++ UNUSED_PARAMETER(pVfs);
++
++ SimulateIOError( return SQLITE_IOERR_ACCESS; );
++ OSTRACE(("ACCESS name=%s, flags=%x, pResOut=%p\n",
++ zFilename, flags, pResOut));
++
++ zConverted = convertUtf8Filename(zFilename);
++ if( zConverted==0 ){
++ OSTRACE(("ACCESS name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename));
++ return SQLITE_IOERR_NOMEM;
++ }
++ if( isNT() ){
++ int cnt = 0;
++ WIN32_FILE_ATTRIBUTE_DATA sAttrData;
++ memset(&sAttrData, 0, sizeof(sAttrData));
++ while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted,
++ GetFileExInfoStandard,
++ &sAttrData)) && retryIoerr(&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{
+- /* Move the page to the head of the dirty list. */
+- pcacheRemoveFromDirtyList(p);
+- pcacheAddToDirtyList(p);
++ logIoerr(cnt);
++ if( lastErrno!=ERROR_FILE_NOT_FOUND && lastErrno!=ERROR_PATH_NOT_FOUND ){
++ winLogError(SQLITE_IOERR_ACCESS, lastErrno, "winAccess", zFilename);
++ sqlite3_free(zConverted);
++ return SQLITE_IOERR_ACCESS;
++ }else{
++ attr = INVALID_FILE_ATTRIBUTES;
++ }
+ }
+ }
+-}
+-
+-/*
+-** 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.
+-*/
+-SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr *p){
+- PCache *pCache;
+- assert( p->nRef==1 );
+- if( p->flags&PGHDR_DIRTY ){
+- pcacheRemoveFromDirtyList(p);
++#ifdef SQLITE_WIN32_HAS_ANSI
++ else{
++ attr = osGetFileAttributesA((char*)zConverted);
+ }
+- pCache = p->pCache;
+- pCache->nRef--;
+- if( p->pgno==1 ){
+- pCache->pPage1 = 0;
++#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");
+ }
+- sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, p->pPage, 1);
++ *pResOut = rc;
++ OSTRACE(("ACCESS name=%s, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n",
++ zFilename, pResOut, *pResOut));
++ return SQLITE_OK;
+ }
+
++
+ /*
+-** Make sure the page is marked as dirty. If it isn't dirty already,
+-** make it so.
++** 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 void sqlite3PcacheMakeDirty(PgHdr *p){
+- p->flags &= ~PGHDR_DONT_WRITE;
+- assert( p->nRef>0 );
+- if( 0==(p->flags & PGHDR_DIRTY) ){
+- p->flags |= PGHDR_DIRTY;
+- pcacheAddToDirtyList( p);
++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 ( zPathname[0]=='/' || zPathname[0]=='\\' ){
++ return TRUE;
+ }
+-}
+
+-/*
+-** 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) ){
+- pcacheRemoveFromDirtyList(p);
+- p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC);
+- if( p->nRef==0 ){
+- pcacheUnpin(p);
+- }
++ /*
++ ** 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 ( sqlite3Isalpha(zPathname[0]) && zPathname[1]==':' ){
++ return TRUE;
+ }
++
++ /*
++ ** 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;
+ }
+
+ /*
+-** Make every page in the cache clean.
++** 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 void sqlite3PcacheCleanAll(PCache *pCache){
+- PgHdr *p;
+- while( (p = pCache->pDirty)!=0 ){
+- sqlite3PcacheMakeClean(p);
++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 */
++){
++
++#if defined(__CYGWIN__)
++ SimulateIOError( return SQLITE_ERROR );
++ UNUSED_PARAMETER(nFull);
++ assert( pVfs->mxPathname>=MAX_PATH );
++ 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[MAX_PATH+1];
++ memset(zOut, 0, MAX_PATH+1);
++ cygwin_conv_path(CCP_POSIX_TO_WIN_A|CCP_RELATIVE, zRelative, zOut,
++ MAX_PATH+1);
++ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s\\%s",
++ sqlite3_data_directory, zOut);
++ }else{
++ cygwin_conv_path(CCP_POSIX_TO_WIN_A, zRelative, zFull, nFull);
+ }
+-}
++ return SQLITE_OK;
++#endif
+
+-/*
+-** 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;
++#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\\%s",
++ sqlite3_data_directory, zRelative);
++ }else{
++ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zRelative);
+ }
+- pCache->pSynced = pCache->pDirtyTail;
+-}
++ return SQLITE_OK;
++#endif
+
+-/*
+-** 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) ){
+- pcacheRemoveFromDirtyList(p);
+- pcacheAddToDirtyList(p);
++#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__)
++ DWORD nByte;
++ void *zConverted;
++ char *zOut;
++
++ /* If this path name begins with "/X:", where "X" is any alphabetic
++ ** character, discard the initial "/" from the pathname.
++ */
++ if( zRelative[0]=='/' && sqlite3Isalpha(zRelative[1]) && zRelative[2]==':' ){
++ zRelative++;
+ }
+-}
+
+-/*
+-** 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.
+-*/
+-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);
+- }
++ /* 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\\%s",
++ sqlite3_data_directory, zRelative);
++ return SQLITE_OK;
++ }
++ zConverted = convertUtf8Filename(zRelative);
++ if( zConverted==0 ){
++ return SQLITE_IOERR_NOMEM;
++ }
++ if( isNT() ){
++ LPWSTR zTemp;
++ nByte = osGetFullPathNameW((LPCWSTR)zConverted, 0, 0, 0);
++ if( nByte==0 ){
++ winLogError(SQLITE_ERROR, osGetLastError(),
++ "GetFullPathNameW1", zConverted);
++ sqlite3_free(zConverted);
++ return SQLITE_CANTOPEN_FULLPATH;
+ }
+- if( pgno==0 && pCache->pPage1 ){
+- memset(pCache->pPage1->pData, 0, pCache->szPage);
+- pgno = 1;
++ nByte += 3;
++ zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) );
++ if( zTemp==0 ){
++ sqlite3_free(zConverted);
++ return SQLITE_IOERR_NOMEM;
+ }
+- sqlite3GlobalConfig.pcache2.xTruncate(pCache->pCache, pgno+1);
++ nByte = osGetFullPathNameW((LPCWSTR)zConverted, nByte, zTemp, 0);
++ if( nByte==0 ){
++ winLogError(SQLITE_ERROR, osGetLastError(),
++ "GetFullPathNameW2", zConverted);
++ sqlite3_free(zConverted);
++ sqlite3_free(zTemp);
++ return SQLITE_CANTOPEN_FULLPATH;
++ }
++ sqlite3_free(zConverted);
++ zOut = unicodeToUtf8(zTemp);
++ sqlite3_free(zTemp);
+ }
+-}
+-
+-/*
+-** Close a cache.
+-*/
+-SQLITE_PRIVATE void sqlite3PcacheClose(PCache *pCache){
+- if( pCache->pCache ){
+- sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
++#ifdef SQLITE_WIN32_HAS_ANSI
++ else{
++ char *zTemp;
++ nByte = osGetFullPathNameA((char*)zConverted, 0, 0, 0);
++ if( nByte==0 ){
++ winLogError(SQLITE_ERROR, osGetLastError(),
++ "GetFullPathNameA1", zConverted);
++ sqlite3_free(zConverted);
++ return SQLITE_CANTOPEN_FULLPATH;
++ }
++ 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 ){
++ winLogError(SQLITE_ERROR, osGetLastError(),
++ "GetFullPathNameA2", zConverted);
++ sqlite3_free(zConverted);
++ sqlite3_free(zTemp);
++ return SQLITE_CANTOPEN_FULLPATH;
++ }
++ 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
+ }
+
+-/*
+-** Discard the contents of the cache.
++#ifndef SQLITE_OMIT_LOAD_EXTENSION
++/*
++** Interfaces for opening a shared library, finding entry points
++** within the shared library, and closing the shared library.
+ */
+-SQLITE_PRIVATE void sqlite3PcacheClear(PCache *pCache){
+- sqlite3PcacheTruncate(pCache, 0);
+-}
+-
+ /*
+-** Merge two lists of pages connected by pDirty and in pgno order.
+-** Do not both fixing the pDirtyPrev pointers.
++** Interfaces for opening a shared library, finding entry points
++** within the shared library, and closing the shared library.
+ */
+-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;
+- }
++static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){
++ HANDLE h;
++ void *zConverted = convertUtf8Filename(zFilename);
++ UNUSED_PARAMETER(pVfs);
++ if( zConverted==0 ){
++ return 0;
+ }
+- if( pA ){
+- pTail->pDirty = pA;
+- }else if( pB ){
+- pTail->pDirty = pB;
+- }else{
+- pTail->pDirty = 0;
++ if( isNT() ){
++#if SQLITE_OS_WINRT
++ h = osLoadPackagedLibrary((LPCWSTR)zConverted, 0);
++#else
++ h = osLoadLibraryW((LPCWSTR)zConverted);
++#endif
+ }
+- return result.pDirty;
++#ifdef SQLITE_WIN32_HAS_ANSI
++ else{
++ h = osLoadLibraryA((char*)zConverted);
++ }
++#endif
++ sqlite3_free(zConverted);
++ return (void*)h;
++}
++static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
++ UNUSED_PARAMETER(pVfs);
++ getLastErrorMsg(osGetLastError(), nBuf, zBufOut);
++}
++static void (*winDlSym(sqlite3_vfs *pVfs,void *pH,const char *zSym))(void){
++ UNUSED_PARAMETER(pVfs);
++ return (void(*)(void))osGetProcAddressA((HANDLE)pH, zSym);
++}
++static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){
++ UNUSED_PARAMETER(pVfs);
++ osFreeLibrary((HANDLE)pHandle);
+ }
++#else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */
++ #define winDlOpen 0
++ #define winDlError 0
++ #define winDlSym 0
++ #define winDlClose 0
++#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.
+-**
+-** 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.
++** Write up to nBuf bytes of randomness into zBuf.
+ */
+-#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 winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
++ int n = 0;
++ UNUSED_PARAMETER(pVfs);
++#if defined(SQLITE_TEST)
++ 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);
+ }
+- p = a[0];
+- for(i=1; i<N_SORT_BUCKET; i++){
+- p = pcacheMergeDirtyList(p, a[i]);
++ if( sizeof(DWORD)<=nBuf-n ){
++ DWORD pid = osGetCurrentProcessId();
++ memcpy(&zBuf[n], &pid, sizeof(pid));
++ n += sizeof(pid);
+ }
+- return p;
++#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);
++ }
++#endif
++ return n;
+ }
+
++
+ /*
+-** Return a list of all dirty pages in the cache, sorted by page number.
++** Sleep for a little while. Return the amount of time slept.
+ */
+-SQLITE_PRIVATE PgHdr *sqlite3PcacheDirtyList(PCache *pCache){
+- PgHdr *p;
+- for(p=pCache->pDirty; p; p=p->pDirtyNext){
+- p->pDirty = p->pDirtyNext;
+- }
+- return pcacheSortDirtyList(pCache->pDirty);
++static int winSleep(sqlite3_vfs *pVfs, int microsec){
++ sqlite3_win32_sleep((microsec+999)/1000);
++ UNUSED_PARAMETER(pVfs);
++ return ((microsec+999)/1000)*1000;
+ }
+
+-/*
+-** Return the total number of referenced pages held by the cache.
++/*
++** 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.
+ */
+-SQLITE_PRIVATE int sqlite3PcacheRefCount(PCache *pCache){
+- return pCache->nRef;
+-}
++#ifdef SQLITE_TEST
++SQLITE_API int sqlite3_current_time = 0; /* Fake system time in seconds since 1970. */
++#endif
+
+ /*
+-** Return the number of references to the page supplied as an argument.
++** 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.
+ */
+-SQLITE_PRIVATE int sqlite3PcachePageRefcount(PgHdr *p){
+- return p->nRef;
+-}
++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;
+
+-/*
+-** 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);
++#if SQLITE_OS_WINCE
++ SYSTEMTIME time;
++ osGetSystemTime(&time);
++ /* if SystemTimeToFileTime() fails, it returns zero. */
++ if (!osSystemTimeToFileTime(&time,&ft)){
++ return SQLITE_ERROR;
+ }
+- return nPage;
+-}
++#else
++ osGetSystemTimeAsFileTime( &ft );
++#endif
++
++ *piNow = winFiletimeEpoch +
++ ((((sqlite3_int64)ft.dwHighDateTime)*max32BitValue) +
++ (sqlite3_int64)ft.dwLowDateTime)/(sqlite3_int64)10000;
+
+ #ifdef SQLITE_TEST
+-/*
+-** Get the suggested cache-size value.
+-*/
+-SQLITE_PRIVATE int sqlite3PcacheGetCachesize(PCache *pCache){
+- return numberOfCachePages(pCache);
+-}
++ if( sqlite3_current_time ){
++ *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch;
++ }
+ #endif
++ UNUSED_PARAMETER(pVfs);
++ return SQLITE_OK;
++}
+
+ /*
+-** Set the suggested cache-size value.
++** 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 void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){
+- pCache->szCache = mxPage;
+- if( pCache->pCache ){
+- sqlite3GlobalConfig.pcache2.xCachesize(pCache->pCache,
+- numberOfCachePages(pCache));
++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;
+ }
+
+ /*
+-** Free up as much memory as possible from the page 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 void sqlite3PcacheShrink(PCache *pCache){
+- if( pCache->pCache ){
+- sqlite3GlobalConfig.pcache2.xShrink(pCache->pCache);
+- }
++static int winGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
++ UNUSED_PARAMETER(pVfs);
++ return getLastErrorMsg(osGetLastError(), nBuf, zBuf);
+ }
+
+-#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.
++** Initialize and deinitialize the operating system interface.
+ */
+-SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *)){
+- PgHdr *pDirty;
+- for(pDirty=pCache->pDirty; pDirty; pDirty=pDirty->pDirtyNext){
+- xIter(pDirty);
+- }
++SQLITE_API int sqlite3_os_init(void){
++ static sqlite3_vfs winVfs = {
++ 3, /* iVersion */
++ sizeof(winFile), /* szOsFile */
++ MAX_PATH, /* 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 */
++ };
++
++ /* Double-check that the aSyscall[] array has been constructed
++ ** correctly. See ticket [bb3a86e890c8e96ab] */
++ assert( ArraySize(aSyscall)==74 );
++
++ /* 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 );
++
++ sqlite3_vfs_register(&winVfs, 1);
++ return SQLITE_OK;
+ }
++
++SQLITE_API int 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:
+@@ -36670,1019 +38609,1027 @@
+ ** 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 overriden, 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 others 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.
+-*/
+-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 */
+-};
+-
+-/*
+-** 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.
++** 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 PgHdr1 {
+- sqlite3_pcache_page page;
+- unsigned int iKey; /* Key value (page number) */
+- 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 */
+-};
+
+-/*
+-** 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 */
+-};
++/* Size of the Bitvec structure in bytes. */
++#define BITVEC_SZ 512
+
+-/*
+-** Global data used by this cache.
+-*/
+-static SQLITE_WSD struct PCacheGlobal {
+- PGroup grp; /* The global PGroup for mode (2) */
++/* 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*))
+
+- /* 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;
++/* 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)
+
+-/*
+-** 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))
++/* 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)
+
+-/*
+-** Macros to enter and leave the PCache LRU mutex.
+-*/
+-#define pcache1EnterMutex(X) sqlite3_mutex_enter((X)->mutex)
+-#define pcache1LeaveMutex(X) sqlite3_mutex_leave((X)->mutex)
++#define BITVEC_NPTR (BITVEC_USIZE/sizeof(Bitvec *))
+
+-/******************************************************************************/
+-/******** Page Allocation/SQLITE_CONFIG_PCACHE Related Functions **************/
+
+ /*
+-** 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.
++** A bitmap is an instance of the following structure.
+ **
+-** This routine is called from sqlite3_initialize() and so it is guaranteed
+-** to be serialized already. There is no need for further mutexing.
++** 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.
+ */
+-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;
+- }
+-}
++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;
++};
+
+ /*
+-** 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.
+-*/
+-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;
+- if( p ){
+- pcache1.pFree = pcache1.pFree->pNext;
+- pcache1.nFreeSlot--;
+- pcache1.bUnderPressure = pcache1.nFreeSlot<pcache1.nReserve;
+- assert( pcache1.nFreeSlot>=0 );
+- sqlite3StatusAdd(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);
+- sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz);
+- sqlite3_mutex_leave(pcache1.mutex);
+- }
+-#endif
+- sqlite3MemdebugSetType(p, MEMTYPE_PCACHE);
++** 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;
+ }
+ return p;
+ }
+
+ /*
+-** Free an allocated buffer obtained from pcache1Alloc().
++** 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 int pcache1Free(void *p){
+- int nFreed = 0;
++SQLITE_PRIVATE int sqlite3BitvecTest(Bitvec *p, u32 i){
+ if( p==0 ) return 0;
+- if( p>=pcache1.pStart && p<pcache1.pEnd ){
+- PgFreeslot *pSlot;
+- sqlite3_mutex_enter(pcache1.mutex);
+- sqlite3StatusAdd(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);
+- sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -nFreed);
+- sqlite3_mutex_leave(pcache1.mutex);
+-#endif
+- sqlite3_free(p);
++ 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( 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;
++ }
++ return 0;
+ }
+- return nFreed;
+ }
+
+-#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+ /*
+-** Return the size of a pcache allocation
++** 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 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;
++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];
++ }
++ 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(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 int 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_malloc(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);
++ }
+ }
+
+- return (p->apHash ? SQLITE_OK : SQLITE_NOMEM);
++ /* 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:
+ **
+-** If pPage is NULL then this routine is a no-op.
++** 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;
+
+- if( pPage==0 ) return;
+- pCache = pPage->pCache;
+- pGroup = pCache->pGroup;
+- assert( sqlite3_mutex_held(pGroup->mutex) );
+- if( pPage->pLruNext || pPage==pGroup->pLruTail ){
+- if( pPage->pLruPrev ){
+- pPage->pLruPrev->pLruNext = pPage->pLruNext;
+- }
+- if( pPage->pLruNext ){
+- pPage->pLruNext->pLruPrev = pPage->pLruPrev;
+- }
+- if( pGroup->pLruHead==pPage ){
+- pGroup->pLruHead = pPage->pLruNext;
+- }
+- if( pGroup->pLruTail==pPage ){
+- pGroup->pLruTail = pPage->pLruPrev;
+- }
+- pPage->pLruNext = 0;
+- pPage->pLruPrev = 0;
+- pPage->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 */
++ int bPurgeable; /* True if pages are on backing store */
++ 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 */
++};
++
++/*
++** 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)
+ /*
+-** Remove the page supplied as an argument from the hash table
+-** (PCache1.apHash structure) that it is currently stored in.
++** 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:
+ **
+-** The PGroup mutex must be held when this function is called.
++** expensive_assert( pcacheCheckSynced(pCache) );
+ */
+-static void pcache1RemoveFromHash(PgHdr1 *pPage){
+- unsigned int h;
+- PCache1 *pCache = pPage->pCache;
+- PgHdr1 **pp;
++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 */
+
+- 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;
++/*
++** Remove page pPage from the list of dirty pages.
++*/
++static void pcacheRemoveFromDirtyList(PgHdr *pPage){
++ 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;
++ }
++ 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;
++ }
++ pPage->pDirtyNext = 0;
++ pPage->pDirtyPrev = 0;
+
+- pCache->nPage--;
++ expensive_assert( pcacheCheckSynced(p) );
+ }
+
+ /*
+-** If there are currently more than nMaxPage pages allocated, try
+-** to recycle pages to reduce the number allocated to nMaxPage.
++** Add page pPage to the head of the dirty list (PCache1.pDirty is set to
++** pPage).
+ */
+-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 );
+- pcache1PinPage(p);
+- pcache1RemoveFromHash(p);
+- pcache1FreePage(p);
++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;
+ }
++ p->pDirty = pPage;
++ if( !p->pDirtyTail ){
++ p->pDirtyTail = pPage;
++ }
++ if( !p->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) ){
++ p->pSynced = pPage;
++ }
++ expensive_assert( pcacheCheckSynced(p) );
+ }
+
+ /*
+-** 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.
++** 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 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;
+- pcache1PinPage(pPage);
+- pcache1FreePage(pPage);
+- }else{
+- pp = &pPage->pNext;
+- TESTONLY( nPage++; )
+- }
++static void pcacheUnpin(PgHdr *p){
++ PCache *pCache = p->pCache;
++ if( pCache->bPurgeable ){
++ if( p->pgno==1 ){
++ pCache->pPage1 = 0;
+ }
++ sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, p->pPage, 0);
+ }
+- assert( pCache->nPage==nPage );
+ }
+
+-/******************************************************************************/
+-/******** sqlite3_pcache Methods **********************************************/
+-
+-/*
+-** Implementation of the sqlite3_pcache.xInit method.
++/*************************************************** General Interfaces ******
++**
++** Initialize and shutdown the page cache subsystem. Neither of these
++** functions are threadsafe.
+ */
+-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 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();
+ }
+- pcache1.grp.mxPinned = 10;
+- pcache1.isInit = 1;
+- return SQLITE_OK;
++ return sqlite3GlobalConfig.pcache2.xInit(sqlite3GlobalConfig.pcache2.pArg);
+ }
+-
+-/*
+-** 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));
++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);
++ }
+ }
+
+ /*
+-** Implementation of the sqlite3_pcache.xCreate method.
+-**
+-** Allocate a new cache.
++** Return the size in bytes of a PCache object.
+ */
+-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 */
+-
+- /*
+- ** The seperateCache 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
+-
+- 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);
+- if( bPurgeable ){
+- pCache->nMin = 10;
+- pcache1EnterMutex(pGroup);
+- pGroup->nMinPage += pCache->nMin;
+- pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
+- pcache1LeaveMutex(pGroup);
+- }
+- }
+- return (sqlite3_pcache *)pCache;
+-}
++SQLITE_PRIVATE int sqlite3PcacheSize(void){ return sizeof(PCache); }
+
+ /*
+-** Implementation of the sqlite3_pcache.xCachesize method.
+-**
+-** Configure the cache_size limit for a cache.
++** 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 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);
+- }
++SQLITE_PRIVATE void 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 = szPage;
++ p->szExtra = szExtra;
++ p->bPurgeable = bPurgeable;
++ p->xStress = xStress;
++ p->pStress = pStress;
++ p->szCache = 100;
+ }
+
+ /*
+-** Implementation of the sqlite3_pcache.xShrink method.
+-**
+-** Free up as much memory as possible.
++** Change the page size for PCache object. The caller must ensure that there
++** are no outstanding page references when this function is called.
+ */
+-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 void sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
++ assert( pCache->nRef==0 && pCache->pDirty==0 );
++ if( pCache->pCache ){
++ sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
++ pCache->pCache = 0;
++ pCache->pPage1 = 0;
+ }
++ pCache->szPage = szPage;
+ }
+
+ /*
+-** Implementation of the sqlite3_pcache.xPagecount method.
++** Compute the number of pages of cache requested.
+ */
+-static int pcache1Pagecount(sqlite3_pcache *p){
+- int n;
+- PCache1 *pCache = (PCache1*)p;
+- pcache1EnterMutex(pCache->pGroup);
+- n = pCache->nPage;
+- pcache1LeaveMutex(pCache->pGroup);
+- return n;
++static int numberOfCachePages(PCache *p){
++ if( p->szCache>=0 ){
++ return p->szCache;
++ }else{
++ return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra));
++ }
+ }
+
+ /*
+-** 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.
++** Try to obtain a page from the cache.
+ */
+-static sqlite3_pcache_page *pcache1Fetch(
+- sqlite3_pcache *p,
+- unsigned int iKey,
+- int createFlag
++SQLITE_PRIVATE int 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 */
+ ){
+- unsigned int nPinned;
+- PCache1 *pCache = (PCache1 *)p;
+- PGroup *pGroup;
+- PgHdr1 *pPage = 0;
++ sqlite3_pcache_page *pPage = 0;
++ PgHdr *pPgHdr = 0;
++ int eCreate;
+
+- assert( pCache->bPurgeable || createFlag!=1 );
+- 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!=0 );
++ assert( createFlag==1 || createFlag==0 );
++ assert( pgno>0 );
+
+- /* 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);
++ /* If the pluggable cache (sqlite3_pcache*) has not been allocated,
++ ** allocate it now.
++ */
++ if( !pCache->pCache && createFlag ){
++ sqlite3_pcache *p;
++ 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;
+ }
+
+- /* Step 2: Abort if no existing page is found and createFlag is 0 */
+- if( pPage || createFlag==0 ){
+- pcache1PinPage(pPage);
+- goto fetch_out;
++ eCreate = createFlag * (1 + (!pCache->bPurgeable || !pCache->pDirty));
++ if( pCache->pCache ){
++ pPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
+ }
+
+- /* 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;
++ if( !pPage && eCreate==1 ){
++ PgHdr *pPg;
++
++ /* 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;
++#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;
++ }
++ }
+
+- /* 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;
++ pPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2);
+ }
+
+- if( pCache->nPage>=pCache->nHash && pcache1ResizeHash(pCache) ){
+- goto fetch_out;
+- }
++ if( pPage ){
++ pPgHdr = (PgHdr *)pPage->pExtra;
+
+- /* 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;
+- pcache1RemoveFromHash(pPage);
+- pcache1PinPage(pPage);
+- pOther = pPage->pCache;
++ 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] );
+
+- /* 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( 0==pPgHdr->nRef ){
++ pCache->nRef++;
++ }
++ pPgHdr->nRef++;
++ if( pgno==1 ){
++ pCache->pPage1 = pPgHdr;
++ }
++ }
++ *ppPage = pPgHdr;
++ return (pPgHdr==0 && eCreate) ? SQLITE_NOMEM : SQLITE_OK;
++}
+
+- if( pOther->szPage+pOther->szExtra != pCache->szPage+pCache->szExtra ){
+- pcache1FreePage(pPage);
+- pPage = 0;
++/*
++** 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.
++*/
++SQLITE_PRIVATE void sqlite3PcacheRelease(PgHdr *p){
++ assert( p->nRef>0 );
++ p->nRef--;
++ if( p->nRef==0 ){
++ PCache *pCache = p->pCache;
++ pCache->nRef--;
++ if( (p->flags&PGHDR_DIRTY)==0 ){
++ pcacheUnpin(p);
+ }else{
+- pGroup->nCurrentPage -= (pOther->bPurgeable - pCache->bPurgeable);
++ /* Move the page to the head of the dirty list. */
++ pcacheRemoveFromDirtyList(p);
++ pcacheAddToDirtyList(p);
+ }
+ }
++}
+
+- /* 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();
++/*
++** 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.
++*/
++SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr *p){
++ PCache *pCache;
++ assert( p->nRef==1 );
++ if( p->flags&PGHDR_DIRTY ){
++ pcacheRemoveFromDirtyList(p);
++ }
++ pCache = p->pCache;
++ pCache->nRef--;
++ if( p->pgno==1 ){
++ pCache->pPage1 = 0;
++ }
++ sqlite3GlobalConfig.pcache2.xUnpin(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;
++ pcacheAddToDirtyList( p);
++ }
++}
++
++/*
++** 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) ){
++ pcacheRemoveFromDirtyList(p);
++ p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC);
++ if( p->nRef==0 ){
++ pcacheUnpin(p);
++ }
+ }
++}
+
+- 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;
+- *(void **)pPage->page.pExtra = 0;
+- pCache->apHash[h] = pPage;
++/*
++** Make every page in the cache clean.
++*/
++SQLITE_PRIVATE void sqlite3PcacheCleanAll(PCache *pCache){
++ PgHdr *p;
++ while( (p = pCache->pDirty)!=0 ){
++ sqlite3PcacheMakeClean(p);
+ }
++}
+
+-fetch_out:
+- if( pPage && iKey>pCache->iMaxKey ){
+- pCache->iMaxKey = iKey;
++/*
++** 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;
+ }
+- pcache1LeaveMutex(pGroup);
+- return &pPage->page;
++ 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) ){
++ pcacheRemoveFromDirtyList(p);
++ pcacheAddToDirtyList(p);
++ }
++}
+
+ /*
+-** 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);
++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);
++ }
++}
+
+- /* 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 );
++/*
++** Close a cache.
++*/
++SQLITE_PRIVATE void sqlite3PcacheClose(PCache *pCache){
++ if( pCache->pCache ){
++ sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
++ }
++}
+
+- 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;
++/*
++** Discard the contents of the cache.
++*/
++SQLITE_PRIVATE void sqlite3PcacheClear(PCache *pCache){
++ sqlite3PcacheTruncate(pCache, 0);
++}
++
++/*
++** 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{
+- pGroup->pLruTail = pPage;
+- pGroup->pLruHead = pPage;
++ pTail->pDirty = pB;
++ pTail = pB;
++ pB = pB->pDirty;
+ }
+- pCache->nRecyclable++;
+ }
+-
+- pcache1LeaveMutex(pCache->pGroup);
++ if( pA ){
++ pTail->pDirty = pA;
++ }else if( pB ){
++ pTail->pDirty = pB;
++ }else{
++ pTail->pDirty = 0;
++ }
++ return result.pDirty;
+ }
+
+ /*
+-** Implementation of the sqlite3_pcache.xRekey 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.
++**
++** 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 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;
++#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);
++ }
+ }
+- *pp = pPage->pNext;
++ p = a[0];
++ for(i=1; i<N_SORT_BUCKET; i++){
++ p = pcacheMergeDirtyList(p, a[i]);
++ }
++ return p;
++}
+
+- h = iNew%pCache->nHash;
+- pPage->iKey = iNew;
+- pPage->pNext = pCache->apHash[h];
+- pCache->apHash[h] = pPage;
+- if( iNew>pCache->iMaxKey ){
+- pCache->iMaxKey = iNew;
++/*
++** Return a list of all dirty pages in the cache, sorted by page number.
++*/
++SQLITE_PRIVATE PgHdr *sqlite3PcacheDirtyList(PCache *pCache){
++ PgHdr *p;
++ for(p=pCache->pDirty; p; p=p->pDirtyNext){
++ p->pDirty = p->pDirtyNext;
+ }
++ return pcacheSortDirtyList(pCache->pDirty);
++}
+
+- pcache1LeaveMutex(pCache->pGroup);
++/*
++** Return the total number of referenced pages held by the cache.
++*/
++SQLITE_PRIVATE int sqlite3PcacheRefCount(PCache *pCache){
++ return pCache->nRef;
+ }
+
+ /*
+-** Implementation of the sqlite3_pcache.xTruncate method.
+-**
+-** 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.
++** Return the number of references to the page supplied as an argument.
+ */
+-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;
++SQLITE_PRIVATE int sqlite3PcachePageRefcount(PgHdr *p){
++ return p->nRef;
++}
++
++/*
++** 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);
+ }
+- pcache1LeaveMutex(pCache->pGroup);
++ return nPage;
+ }
+
++#ifdef SQLITE_TEST
+ /*
+-** Implementation of the sqlite3_pcache.xDestroy method.
+-**
+-** Destroy a cache allocated using pcache1Create().
++** Get the suggested cache-size value.
+ */
+-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 int sqlite3PcacheGetCachesize(PCache *pCache){
++ return numberOfCachePages(pCache);
+ }
++#endif
+
+ /*
+-** This function is called during initialization (sqlite3_initialize()) to
+-** install the default pluggable cache module, assuming the user has not
+-** already provided an alternative.
++** Set the suggested cache-size value.
+ */
+-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 void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){
++ pCache->szCache = mxPage;
++ if( pCache->pCache ){
++ 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
+- pcache1PinPage(p);
+- pcache1RemoveFromHash(p);
+- pcache1FreePage(p);
+- }
+- pcache1LeaveMutex(&pcache1.grp);
++SQLITE_PRIVATE void sqlite3PcacheShrink(PCache *pCache){
++ if( pCache->pCache ){
++ sqlite3GlobalConfig.pcache2.xShrink(pCache->pCache);
+ }
+- return nFree;
+ }
+-#endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */
+
+-#ifdef SQLITE_TEST
++#if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
+ /*
+-** This function is used by test procedures to inspect the internal state
+-** of the global cache.
++** 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 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){
+- nRecyclable++;
++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:
+@@ -37693,3176 +39640,3005 @@
+ **
+ *************************************************************************
+ **
+-** 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 overriden, 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 others 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. (Sometime 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 */
++};
++
++/*
++** 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) */
++ 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 */
++};
++
++/*
++** 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 */
++};
++
++/*
++** Global data used by this cache.
+ */
++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;
+
++/*
++** 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))
+
+ /*
+-** Target size for allocation chunks.
++** Macros to enter and leave the PCache LRU mutex.
+ */
+-#define ROWSET_ALLOCATION_SIZE 1024
++#define pcache1EnterMutex(X) sqlite3_mutex_enter((X)->mutex)
++#define pcache1LeaveMutex(X) sqlite3_mutex_leave((X)->mutex)
++
++/******************************************************************************/
++/******** Page Allocation/SQLITE_CONFIG_PCACHE Related Functions **************/
+
+ /*
+-** The number of rowset entries per allocation chunk.
++** 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_ENTRY_PER_CHUNK \
+- ((ROWSET_ALLOCATION_SIZE-8)/sizeof(struct RowSetEntry))
++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;
++ }
++}
+
+ /*
+-** Each entry in a RowSet is an instance of the following 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().
+ **
+-** 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.
++** Multiple threads can run this routine at the same time. Global variables
++** in pcache1 need to be protected via mutex.
+ */
+-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 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;
++ if( p ){
++ pcache1.pFree = pcache1.pFree->pNext;
++ pcache1.nFreeSlot--;
++ pcache1.bUnderPressure = pcache1.nFreeSlot<pcache1.nReserve;
++ assert( pcache1.nFreeSlot>=0 );
++ sqlite3StatusAdd(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);
++ sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz);
++ sqlite3_mutex_leave(pcache1.mutex);
++ }
++#endif
++ sqlite3MemdebugSetType(p, MEMTYPE_PCACHE);
++ }
++ return p;
++}
+
+ /*
+-** 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.
++** Free an allocated buffer obtained from pcache1Alloc().
+ */
+-struct RowSetChunk {
+- struct RowSetChunk *pNextChunk; /* Next chunk on list of them all */
+- struct RowSetEntry aEntry[ROWSET_ENTRY_PER_CHUNK]; /* Allocated entries */
+-};
++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);
++ sqlite3StatusAdd(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);
++ sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -nFreed);
++ sqlite3_mutex_leave(pcache1.mutex);
++#endif
++ sqlite3_free(p);
++ }
++ return nFreed;
++}
+
++#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+ /*
+-** A RowSet in an instance of the following structure.
+-**
+-** A typedef of this structure if found in sqliteInt.h.
++** Return the size of a pcache allocation
+ */
+-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 */
+- u8 rsFlags; /* Various flags */
+- u8 iBatch; /* Current insert batch */
+-};
++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;
++ }
++}
++#endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */
+
+ /*
+-** Allowed values for RowSet.rsFlags
++** Allocate a new page object initially associated with cache pCache.
+ */
+-#define ROWSET_SORTED 0x01 /* True if RowSet.pEntry is sorted */
+-#define ROWSET_NEXT 0x02 /* True if sqlite3RowSetNext() has been called */
++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;
++ }
++#else
++ pPg = pcache1Alloc(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++;
++ }
++ return p;
++ }
++ return 0;
++}
+
+ /*
+-** 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.
++** Free a page object allocated by pcache1AllocPage().
+ **
+-** 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.
++** 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().
+ */
+-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;
++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--;
++ }
++ }
+ }
+
+ /*
+-** 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.
++** 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 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;
++SQLITE_PRIVATE void *sqlite3PageMalloc(int sz){
++ return pcache1Alloc(sz);
+ }
+
+ /*
+-** Allocate a new RowSetEntry object that is associated with the
+-** given RowSet. Return a pointer to the new and completely uninitialized
+-** objected.
++** Free an allocated buffer obtained from sqlite3PageMalloc().
++*/
++SQLITE_PRIVATE void sqlite3PageFree(void *p){
++ pcache1Free(p);
++}
++
++
++/*
++** Return true if it desirable to avoid allocating a new page cache
++** entry.
+ **
+-** In an OOM situation, the RowSet.db->mallocFailed flag is set and this
+-** routine returns 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.
++**
++** 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 *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 pcache1UnderMemoryPressure(PCache1 *pCache){
++ if( pcache1.nSlot && (pCache->szPage+pCache->szExtra)<=pcache1.szSlot ){
++ return pcache1.bUnderPressure;
++ }else{
++ return sqlite3HeapNearlyFull();
+ }
+- p->nFresh--;
+- return p->pFresh++;
+ }
+
++/******************************************************************************/
++/******** General Implementation Functions ************************************/
++
+ /*
+-** Insert a new value into a RowSet.
++** This function is used to resize the hash table used by the cache passed
++** as the first argument.
+ **
+-** The mallocFailed flag of the database connection is set if a
+-** memory allocation fails.
++** The PCache mutex must be held when this function is called.
+ */
+-SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet *p, i64 rowid){
+- struct RowSetEntry *pEntry; /* The new entry */
+- struct RowSetEntry *pLast; /* The last prior entry */
++static int pcache1ResizeHash(PCache1 *p){
++ PgHdr1 **apNew;
++ unsigned int nNew;
++ unsigned int i;
+
+- /* This routine is never called after sqlite3RowSetNext() */
+- assert( p!=0 && (p->rsFlags & ROWSET_NEXT)==0 );
++ assert( sqlite3_mutex_held(p->pGroup->mutex) );
+
+- 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;
++ nNew = p->nHash*2;
++ if( nNew<256 ){
++ nNew = 256;
++ }
++
++ 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;
++ }
+ }
+- pLast->pRight = pEntry;
+- }else{
+- p->pEntry = pEntry;
++ sqlite3_free(p->apHash);
++ p->apHash = apNew;
++ p->nHash = nNew;
+ }
+- p->pLast = pEntry;
++
++ return (p->apHash ? SQLITE_OK : SQLITE_NOMEM);
+ }
+
+ /*
+-** Merge two lists of RowSetEntry objects. Remove duplicates.
++** 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.
+ **
+-** The input lists are connected via pRight pointers and are
+-** assumed to each already be in sorted order.
++** The PGroup mutex must be held when this function is called.
++**
++** If pPage is NULL then this routine is a no-op.
+ */
+-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;
++static void pcache1PinPage(PgHdr1 *pPage){
++ PCache1 *pCache;
++ PGroup *pGroup;
+
+- 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( pPage==0 ) return;
++ pCache = pPage->pCache;
++ pGroup = pCache->pGroup;
++ assert( sqlite3_mutex_held(pGroup->mutex) );
++ if( pPage->pLruNext || pPage==pGroup->pLruTail ){
++ if( pPage->pLruPrev ){
++ pPage->pLruPrev->pLruNext = pPage->pLruNext;
+ }
++ if( pPage->pLruNext ){
++ pPage->pLruNext->pLruPrev = pPage->pLruPrev;
++ }
++ if( pGroup->pLruHead==pPage ){
++ pGroup->pLruHead = pPage->pLruNext;
++ }
++ if( pGroup->pLruTail==pPage ){
++ pGroup->pLruTail = pPage->pLruPrev;
++ }
++ pPage->pLruNext = 0;
++ pPage->pLruPrev = 0;
++ pPage->pCache->nRecyclable--;
+ }
+- 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];
++** 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.
++*/
++static void pcache1RemoveFromHash(PgHdr1 *pPage){
++ unsigned int h;
++ PCache1 *pCache = pPage->pCache;
++ PgHdr1 **pp;
+
+- 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;
++ 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;
++
++ 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 );
++ pcache1PinPage(p);
++ pcache1RemoveFromHash(p);
++ pcache1FreePage(p);
++ }
++}
+
+ /*
+-** 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.
++** 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 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 */
++static void pcache1TruncateUnsafe(
++ PCache1 *pCache, /* The cache to truncate */
++ unsigned int iLimit /* Drop pages with this pgno or larger */
+ ){
+- 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;
++ 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;
++ pcache1PinPage(pPage);
++ pcache1FreePage(pPage);
++ }else{
++ pp = &pPage->pNext;
++ TESTONLY( nPage++; )
++ }
++ }
+ }
+- assert( (*ppLast)->pRight==0 );
++ assert( pCache->nPage==nPage );
+ }
+
++/******************************************************************************/
++/******** sqlite3_pcache Methods **********************************************/
+
+ /*
+-** 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.
+-**
+-** 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.
+-**
+-** Return a pointer to the root of the constructed binary tree.
++** Implementation of the sqlite3_pcache.xInit method.
+ */
+-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 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);
+ }
+- p->pLeft = pLeft;
+- *ppList = p->pRight;
+- p->pRight = rowSetNDeepTree(ppList, iDepth-1);
+- return p;
++ pcache1.grp.mxPinned = 10;
++ pcache1.isInit = 1;
++ return SQLITE_OK;
+ }
+
+ /*
+-** 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.
++** Implementation of the sqlite3_pcache.xShutdown method.
++** Note that the static mutex allocated in xInit does
++** not need to be freed.
+ */
+-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;
++static void pcache1Shutdown(void *NotUsed){
++ UNUSED_PARAMETER(NotUsed);
++ assert( pcache1.isInit!=0 );
++ memset(&pcache1, 0, sizeof(pcache1));
+ }
+
+ /*
+-** 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.
++** Implementation of the sqlite3_pcache.xCreate method.
+ **
+-** This routine should only be called once in the life of a RowSet.
++** Allocate a new cache.
+ */
+-static void rowSetToList(RowSet *p){
++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 */
+
+- /* This routine is called only once */
+- assert( p!=0 && (p->rsFlags & ROWSET_NEXT)==0 );
++ /*
++ ** The seperateCache 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
+
+- if( (p->rsFlags & ROWSET_SORTED)==0 ){
+- p->pEntry = rowSetEntrySort(p->pEntry);
+- }
++ assert( (szPage & (szPage-1))==0 && szPage>=512 && szPage<=65536 );
++ assert( szExtra < 300 );
+
+- /* 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);
++ 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);
++ if( bPurgeable ){
++ pCache->nMin = 10;
++ pcache1EnterMutex(pGroup);
++ pGroup->nMinPage += pCache->nMin;
++ pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
++ pcache1LeaveMutex(pGroup);
+ }
+- p->pForest = p->pForest->pRight;
+ }
+-#endif
+- p->rsFlags |= ROWSET_NEXT; /* Verify this routine is never called again */
++ return (sqlite3_pcache *)pCache;
+ }
+
+ /*
+-** Extract the smallest element from the RowSet.
+-** Write the element into *pRowid. Return 1 on success. Return
+-** 0 if the RowSet is already empty.
++** Implementation of the sqlite3_pcache.xCachesize method.
+ **
+-** After this routine has been called, the sqlite3RowSetInsert()
+-** routine may not be called again.
++** Configure the cache_size limit for a cache.
+ */
+-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);
+-
+- /* 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;
++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);
+ }
+ }
+
+ /*
+-** Check to see if element iRowid was inserted into the rowset as
+-** part of any insert batch prior to iBatch. Return 1 or 0.
++** Implementation of the sqlite3_pcache.xShrink method.
+ **
+-** 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
+-** pRowSet->pForest so that they can be tested.
++** Free up as much memory as possible.
+ */
+-SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, u8 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;
++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);
+ }
++}
+
+- /* 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;
++/*
++** Implementation of the sqlite3_pcache.xPagecount method.
++*/
++static int pcache1Pagecount(sqlite3_pcache *p){
++ int n;
++ PCache1 *pCache = (PCache1*)p;
++ pcache1EnterMutex(pCache->pGroup);
++ n = pCache->nPage;
++ pcache1LeaveMutex(pCache->pGroup);
++ return n;
+ }
+
+-/************** End of rowset.c **********************************************/
+-/************** Begin file pager.c *******************************************/
+ /*
+-** 2001 September 15
++** Implementation of the sqlite3_pcache.xFetch method.
+ **
+-** The author disclaims copyright to this source code. In place of
+-** a legal notice, here is a blessing:
++** Fetch a page by key value.
+ **
+-** 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.
++** 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.
+ **
+-*************************************************************************
+-** 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.
+-*/
+-#ifndef SQLITE_OMIT_DISKIO
+-/************** Include wal.h in the middle of pager.c ***********************/
+-/************** Begin file wal.h *********************************************/
+-/*
+-** 2010 February 1
++** 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.
+ **
+-** The author disclaims copyright to this source code. In place of
+-** a legal notice, here is a blessing:
++** 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).
+ **
+-** 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.
++** 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.
+ **
+-*************************************************************************
+-** 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.
++** 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.
+ */
++static sqlite3_pcache_page *pcache1Fetch(
++ sqlite3_pcache *p,
++ unsigned int iKey,
++ int createFlag
++){
++ unsigned int nPinned;
++ PCache1 *pCache = (PCache1 *)p;
++ PGroup *pGroup;
++ PgHdr1 *pPage = 0;
+
+-#ifndef _WAL_H_
+-#define _WAL_H_
+-
+-
+-/* Additional values that can be added to the sync_flags argument of
+-** sqlite3WalFrames():
+-*/
+-#define WAL_SYNC_TRANSACTIONS 0x20 /* Sync at the end of each transaction */
+-#define SQLITE_SYNC_MASK 0x13 /* Mask off the SQLITE_SYNC_* values */
++ assert( pCache->bPurgeable || createFlag!=1 );
++ assert( pCache->bPurgeable || pCache->nMin==0 );
++ assert( pCache->bPurgeable==0 || pCache->nMin==10 );
++ assert( pCache->nMin==0 || pCache->bPurgeable );
++ pcache1EnterMutex(pGroup = pCache->pGroup);
+
+-#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
++ /* 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);
++ }
+
+-#define WAL_SAVEPOINT_NDATA 4
++ /* Step 2: Abort if no existing page is found and createFlag is 0 */
++ if( pPage || createFlag==0 ){
++ pcache1PinPage(pPage);
++ goto fetch_out;
++ }
+
+-/* Connection to a write-ahead log (WAL) file.
+-** There is one object of this type for each pager.
+-*/
+-typedef struct Wal Wal;
++ /* 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
+
+-/* 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 *);
++ /* 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;
++ }
+
+-/* Set the limiting size of a WAL file. */
+-SQLITE_PRIVATE void sqlite3WalLimit(Wal*, i64);
++ if( pCache->nPage>=pCache->nHash && pcache1ResizeHash(pCache) ){
++ goto fetch_out;
++ }
+
+-/* 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.
+-*/
+-SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *);
+-SQLITE_PRIVATE void sqlite3WalEndReadTransaction(Wal *pWal);
++ /* 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;
++ pcache1RemoveFromHash(pPage);
++ pcache1PinPage(pPage);
++ pOther = pPage->pCache;
+
+-/* 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 *);
++ /* 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 the WAL is not empty, return the size of the database. */
+-SQLITE_PRIVATE Pgno sqlite3WalDbsize(Wal *pWal);
++ if( pOther->szPage+pOther->szExtra != pCache->szPage+pCache->szExtra ){
++ pcache1FreePage(pPage);
++ pPage = 0;
++ }else{
++ pGroup->nCurrentPage -= (pOther->bPurgeable - pCache->bPurgeable);
++ }
++ }
+
+-/* Obtain or release the WRITER lock. */
+-SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal);
+-SQLITE_PRIVATE int sqlite3WalEndWriteTransaction(Wal *pWal);
++ /* 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();
++ }
+
+-/* Undo any frames written (but not committed) to the log */
+-SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx);
++ 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;
++ *(void **)pPage->page.pExtra = 0;
++ pCache->apHash[h] = pPage;
++ }
+
+-/* Return an integer that records the current (uncommitted) write
+-** position in the WAL */
+-SQLITE_PRIVATE void sqlite3WalSavepoint(Wal *pWal, u32 *aWalData);
++fetch_out:
++ if( pPage && iKey>pCache->iMaxKey ){
++ pCache->iMaxKey = iKey;
++ }
++ pcache1LeaveMutex(pGroup);
++ return &pPage->page;
++}
+
+-/* 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);
++/*
++** Implementation of the sqlite3_pcache.xUnpin method.
++**
++** 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);
+
+-/* 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 */
+-);
++ /* 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 );
+
+-/* 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.
+-*/
+-SQLITE_PRIVATE int sqlite3WalCallback(Wal *pWal);
++ 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++;
++ }
+
+-/* 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);
++ pcache1LeaveMutex(pCache->pGroup);
++}
+
+-/* 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.
++/*
++** Implementation of the sqlite3_pcache.xRekey method.
+ */
+-SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal);
++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 );
+
+-#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
++ pcache1EnterMutex(pCache->pGroup);
+
+-#endif /* ifndef SQLITE_OMIT_WAL */
+-#endif /* _WAL_H_ */
++ h = iOld%pCache->nHash;
++ pp = &pCache->apHash[h];
++ while( (*pp)!=pPage ){
++ pp = &(*pp)->pNext;
++ }
++ *pp = pPage->pNext;
+
+-/************** End of wal.h *************************************************/
+-/************** Continuing where we left off in pager.c **********************/
++ 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);
++}
+
+-/******************* 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 arbitarily without effecting 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
+-** 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.
++/*
++** Implementation of the sqlite3_pcache.xTruncate method.
+ **
+-** (13) A SHARED lock is held on the database file while reading any
+-** content out of the database file.
++** 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.
+ **
+-******************************************************************************/
++** Destroy a cache allocated using pcache1Create().
++*/
++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);
++}
+
+ /*
+-** Macros for troubleshooting. Normally turned off
++** This function is called during initialization (sqlite3_initialize()) to
++** install the default pluggable cache module, assuming the user has not
++** already provided an alternative.
+ */
+-#if 0
+-int sqlite3PagerTrace=1; /* True to enable tracing */
+-#define sqlite3DebugPrintf printf
+-#define PAGERTRACE(X) if( sqlite3PagerTrace ){ sqlite3DebugPrintf X; }
+-#else
+-#define PAGERTRACE(X)
+-#endif
++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);
++}
+
++#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+ /*
+-** The following two macros are used within the PAGERTRACE() macros above
+-** to print out file-descriptors.
++** 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.
+ **
+-** 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.
++** 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.
+ */
+-#define PAGERID(p) ((int)(p->fd))
+-#define FILEHANDLEID(fd) ((int)fd)
++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
++ pcache1PinPage(p);
++ pcache1RemoveFromHash(p);
++ pcache1FreePage(p);
++ }
++ pcache1LeaveMutex(&pcache1.grp);
++ }
++ return nFree;
++}
++#endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */
+
++#ifdef SQLITE_TEST
+ /*
+-** 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:
+-**
+-** 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.
+-**
+-** Temporary pager files may enter the ERROR state, but in-memory pagers
+-** cannot.
+-**
+-** 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.
+-**
+-** 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.
+-**
+-** 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().
++** This function is used by test procedures to inspect the internal state
++** of the global cache.
++*/
++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){
++ 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 ******************************************/
++/*
++** 2008 December 3
+ **
+-** 3. An error occurs while attempting to write to the journal or
+-** database file in function pagerStress() in order to free up
+-** memory.
++** The author disclaims copyright to this source code. In place of
++** a legal notice, here is a blessing:
+ **
+-** 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.
++** 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.
+ **
+-** 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.
+-**
++** This module implements an object we call a "RowSet".
+ **
+-** Notes:
++** 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.
+ **
+-** * 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.
++** 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.
+ **
+-** * 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".
++** Hence, the primitive operations for a RowSet are:
+ **
+-** * See also: assert_pager_state().
+-*/
+-#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
+-
+-/*
+-** 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.
++** CREATE
++** INSERT
++** TEST
++** SMALLEST
++** DESTROY
+ **
+-** 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 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 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 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 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
+-** 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.
++** 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.
+ **
+-** 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.
++** No INSERTs may occurs after a SMALLEST. An assertion will fail if
++** that is attempted.
+ **
+-** 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.
++** The cost of an INSERT is roughly constant. (Sometime 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).
+ **
+-** Pager.eLock may only be set to UNKNOWN_LOCK when the pager is in
+-** PAGER_OPEN state.
++** There is an added cost of O(N) when switching between TEST and
++** SMALLEST primitives.
+ */
+-#define UNKNOWN_LOCK (EXCLUSIVE_LOCK+1)
++
+
+ /*
+-** A macro used for invoking the codec if there is one
++** Target size for allocation chunks.
+ */
+-#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
++#define ROWSET_ALLOCATION_SIZE 1024
+
+ /*
+-** 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.
++** The number of rowset entries per allocation chunk.
+ */
+-#define MAX_SECTOR_SIZE 0x10000
++#define ROWSET_ENTRY_PER_CHUNK \
++ ((ROWSET_ALLOCATION_SIZE-8)/sizeof(struct RowSetEntry))
+
+ /*
+-** 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().
++** Each entry in a RowSet is an instance of the following object.
+ **
+-** 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()).
++** 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.
+ */
+-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
++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) */
+ };
+
+ /*
+-** A 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, doNotSyncSpill
++** 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.
+ **
+-** These two boolean 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).
++** A typedef of this structure if found in sqliteInt.h.
++*/
++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 */
++ u8 rsFlags; /* Various flags */
++ u8 iBatch; /* Current insert batch */
++};
++
++/*
++** 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 */
++
++/*
++** 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.
+ **
+-** When doNotSpill is non-zero, writing to the database from pagerStress()
+-** is disabled altogether. This 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().
++** It must be the case that N is sufficient to make a Rowset. If not
++** an assertion fault occurs.
+ **
+-** If doNotSyncSpill is non-zero, 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.
+-**
+-** subjInMemory
+-**
+-** 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.
+-**
+-** dbSize, dbOrigSize, dbFileSize
+-**
+-** 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).
+-**
+-** 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).
+-**
+-** 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.
+-**
+-** 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.
+-**
+-** 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 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.
+-**
+-** 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
++** 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;
++}
++
++/*
++** 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;
++}
++
++/*
++** Allocate a new RowSetEntry object that is associated with the
++** given RowSet. Return a pointer to the new and completely uninitialized
++** objected.
+ **
+-** 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.
++** In an OOM situation, the RowSet.db->mallocFailed flag is set and this
++** routine returns NULL.
+ */
+-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 file */
+- u8 readOnly; /* True for a read-only database */
+- u8 memDb; /* True to inhibit all file I/O */
++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 block contains those class members that change during
+- ** routine opertion. 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 doNotSyncSpill; /* Do not do a spill that requires jrnl sync */
+- u8 subjInMemory; /* True to use in-memory sub-journals */
+- 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[] */
+- char dbFileVers[16]; /* Changes whenever database file changes */
++/*
++** Insert a new value into a RowSet.
++**
++** The mallocFailed flag of the database connection is set if a
++** memory allocation fails.
++*/
++SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet *p, i64 rowid){
++ struct RowSetEntry *pEntry; /* The new entry */
++ struct RowSetEntry *pLast; /* The last prior entry */
+
+- 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) */
+- /*
+- ** End of the routinely-changing class members
+- ***************************************************************************/
++ /* This routine is never called after sqlite3RowSetNext() */
++ assert( p!=0 && (p->rsFlags & ROWSET_NEXT)==0 );
+
+- 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
+-};
++ 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;
++}
+
+ /*
+-** 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().
++** Merge two lists of RowSetEntry objects. Remove duplicates.
++**
++** The input lists are connected via pRight pointers and are
++** assumed to each already be in sorted order.
+ */
+-#define PAGER_STAT_HIT 0
+-#define PAGER_STAT_MISS 1
+-#define PAGER_STAT_WRITE 2
++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;
++ }
++ }
++ 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 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
++** 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;
++}
+
+
+ /*
+-** 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.
++** 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.
+ */
+-static const unsigned char aJournalMagic[] = {
+- 0xd9, 0xd5, 0x05, 0xf9, 0x20, 0xa1, 0x63, 0xd7,
+-};
++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 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().
++** 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.
++**
++** 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.
++**
++** Return a pointer to the root of the constructed binary tree.
+ */
+-#define JOURNAL_HDR_SZ(pPager) (pPager->sectorSize)
++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;
++}
+
+ /*
+-** 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.
++** 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.
+ */
+-#ifdef SQLITE_OMIT_MEMORYDB
+-# define MEMDB 0
+-#else
+-# define MEMDB pPager->memDb
+-#endif
++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 */
+
+-/*
+-** 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
++ 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;
++}
+
+ /*
+-** The maximum legal page number is (2^31 - 1).
++** 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 routine should only be called once in the life of a RowSet.
+ */
+-#define PAGER_MAX_PGNO 2147483647
++static void rowSetToList(RowSet *p){
++
++ /* This routine is called only once */
++ assert( p!=0 && (p->rsFlags & ROWSET_NEXT)==0 );
++
++ if( (p->rsFlags & ROWSET_SORTED)==0 ){
++ p->pEntry = rowSetEntrySort(p->pEntry);
++ }
++
++ /* 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;
++ }
++#endif
++ p->rsFlags |= ROWSET_NEXT; /* Verify this routine is never called again */
++}
+
+ /*
+-** 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) ){ ...
+-**
+-** instead of
++** Extract the smallest element from the RowSet.
++** Write the element into *pRowid. Return 1 on success. Return
++** 0 if the RowSet is already empty.
+ **
+-** if( pPager->jfd->pMethods ){ ...
++** After this routine has been called, the sqlite3RowSetInsert()
++** routine may not be called again.
+ */
+-#define isOpen(pFd) ((pFd)->pMethods)
++SQLITE_PRIVATE int sqlite3RowSetNext(RowSet *p, i64 *pRowid){
++ assert( p!=0 );
+
+-/*
+-** 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);
++ /* Merge the forest into a single sorted list on first call */
++ if( (p->rsFlags & ROWSET_NEXT)==0 ) rowSetToList(p);
++
++ /* 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;
++ }
+ }
+-#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) );
++** Check to see if element iRowid was inserted into the rowset as
++** part of any insert batch prior to iBatch. Return 1 or 0.
+ **
+-** This function runs many asserts to try to find inconsistencies in
+-** the internal state of the Pager object.
++** 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
++** pRowSet->pForest so that they can be tested.
+ */
+-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
+- );
++SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, u8 iBatch, sqlite3_int64 iRowid){
++ struct RowSetEntry *p, *pTree;
+
+- /* 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 );
++ /* This routine is never called after sqlite3RowSetNext() */
++ assert( pRowSet!=0 && (pRowSet->rsFlags & ROWSET_NEXT)==0 );
+
+- /* 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.
++ /* Sort entries into the forest on the first test of a new batch
+ */
+- assert( p->journalMode==PAGER_JOURNALMODE_OFF || p->useJournal );
+- assert( p->journalMode!=PAGER_JOURNALMODE_OFF || !isOpen(p->jfd) );
++ 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;
++ }
+
+- /* 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.
++ /* Test to see if the iRowid value appears anywhere in the forest.
++ ** Return 1 if it does and 0 if not.
+ */
+- 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 );
++ 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;
++}
+
+- /* 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 );
++/************** End of rowset.c **********************************************/
++/************** Begin file pager.c *******************************************/
++/*
++** 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.
++*/
++#ifndef SQLITE_OMIT_DISKIO
++/************** Include wal.h in the middle of pager.c ***********************/
++/************** Begin file wal.h *********************************************/
++/*
++** 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.
++*/
+
+- switch( p->eState ){
+- case PAGER_OPEN:
+- assert( !MEMDB );
+- assert( pPager->errCode==SQLITE_OK );
+- assert( sqlite3PcacheRefCount(pPager->pPCache)==0 || pPager->tempFile );
+- break;
++#ifndef _WAL_H_
++#define _WAL_H_
+
+- 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;
++/* Additional values that can be added to the sync_flags argument of
++** sqlite3WalFrames():
++*/
++#define WAL_SYNC_TRANSACTIONS 0x20 /* Sync at the end of each transaction */
++#define SQLITE_SYNC_MASK 0x13 /* Mask off the SQLITE_SYNC_* values */
+
+- 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;
++#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
+
+- 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;
++#define WAL_SAVEPOINT_NDATA 4
+
+- 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;
++/* Connection to a write-ahead log (WAL) file.
++** There is one object of this type for each pager.
++*/
++typedef struct Wal Wal;
+
+- 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;
+- }
++/* 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 *);
+
+- return 1;
+-}
+-#endif /* ifndef NDEBUG */
++/* Set the limiting size of a WAL file. */
++SQLITE_PRIVATE void sqlite3WalLimit(Wal*, i64);
+
+-#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)
++/* 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 char *print_pager_state(Pager *p){
+- static char zRet[1024];
++SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *);
++SQLITE_PRIVATE void sqlite3WalEndReadTransaction(Wal *pWal);
+
+- 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
+- );
++/* 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 *);
+
+- return zRet;
+-}
+-#endif
++/* If the WAL is not empty, return the size of the database. */
++SQLITE_PRIVATE Pgno sqlite3WalDbsize(Wal *pWal);
+
+-/*
+-** 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.
++/* 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.
+ */
+-static int subjRequiresPage(PgHdr *pPg){
+- Pgno pgno = pPg->pgno;
+- Pager *pPager = pPg->pPager;
+- int i;
+- for(i=0; i<pPager->nSavepoint; i++){
+- PagerSavepoint *p = &pPager->aSavepoint[i];
+- if( p->nOrig>=pgno && 0==sqlite3BitvecTest(p->pInSavepoint, pgno) ){
+- return 1;
+- }
+- }
+- return 0;
+-}
++SQLITE_PRIVATE int sqlite3WalCallback(Wal *pWal);
+
+-/*
+-** Return true if the page is already in the journal file.
++/* Tell the wal layer that an EXCLUSIVE lock has been obtained (or released)
++** by the pager layer on the database file.
+ */
+-static int pageInJournal(PgHdr *pPg){
+- return sqlite3BitvecTest(pPg->pPager->pInJournal, pPg->pgno);
+-}
++SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op);
+
+-/*
+-** 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.
++/* 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.
+ */
+-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;
+-}
++SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal);
+
+-/*
+-** Write a 32-bit integer into a string buffer in big-endian byte order.
++#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).
+ */
+-#define put32bits(A,B) sqlite3Put4byte((u8*)A,B)
++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 arbitarily without effecting 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
++** 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.
++**
++******************************************************************************/
+
+ /*
+-** Write a 32-bit integer into the given file descriptor. Return SQLITE_OK
+-** on success or an error code is something goes wrong.
++** Macros for troubleshooting. Normally turned off
+ */
+-static int write32bits(sqlite3_file *fd, i64 offset, u32 val){
+- char ac[4];
+- put32bits(ac, val);
+- return sqlite3OsWrite(fd, ac, 4, offset);
+-}
++#if 0
++int sqlite3PagerTrace=1; /* True to enable tracing */
++#define sqlite3DebugPrintf printf
++#define PAGERTRACE(X) if( sqlite3PagerTrace ){ sqlite3DebugPrintf X; }
++#else
++#define PAGERTRACE(X)
++#endif
+
+ /*
+-** 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.
++** The following two macros are used within the PAGERTRACE() macros above
++** to print out file-descriptors.
+ **
+-** 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.
++** 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.
+ */
+-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 = sqlite3OsUnlock(pPager->fd, eLock);
+- if( pPager->eLock!=UNKNOWN_LOCK ){
+- pPager->eLock = (u8)eLock;
+- }
+- IOTRACE(("UNLOCK %p %d\n", pPager, eLock))
+- }
+- return rc;
+-}
++#define PAGERID(p) ((int)(p->fd))
++#define FILEHANDLEID(fd) ((int)fd)
+
+ /*
+-** 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.
++** 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:
++**
++** 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.
++**
++** Temporary pager files may enter the ERROR state, but in-memory pagers
++** cannot.
++**
++** 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.
++**
++** 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.
++**
++** 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.
+ **
+-** 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.
++** * 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 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 = 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;
+-}
++#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
+
+ /*
+-** This function determines whether or not the atomic-write optimization
+-** can be used with this pager. The optimization can be used if:
++** 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.
+ **
+-** (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.
++** 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 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.
++** 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.
+ **
+-** 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.
++** 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
++** 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.
++**
++** Pager.eLock may only be set to UNKNOWN_LOCK when the pager is in
++** PAGER_OPEN state.
+ */
+-#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 JOURNAL_HDR_SZ(pPager) + JOURNAL_PG_SZ(pPager);
+-}
+-#endif
++#define UNKNOWN_LOCK (EXCLUSIVE_LOCK+1)
+
+ /*
+-** 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.
++** A macro used for invoking the codec if there is one
+ */
+-#ifdef SQLITE_CHECK_PAGES
+#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 a 32-bit hash of the page data for pPage.
++** 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.
+ */
+-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);
+-}
++#define MAX_SECTOR_SIZE 0x10000
+
+ /*
+-** 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.
++** 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()).
+ */
+-#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 */
++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
++};
+
+ /*
+-** 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.
++** A open page cache is an instance of struct Pager. A description of
++** some of the more important member variables follows:
+ **
+-** 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.
++** eState
+ **
+-** 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 current 'state' of the pager object. See the comment and state
++** diagram above for a description of the pager state.
+ **
+-** If it is determined that no master journal file name is present
+-** zMaster[0] is set to 0 and SQLITE_OK returned.
++** eLock
+ **
+-** If an error occurs while reading from the journal file, an SQLite
+-** error code is returned.
++** 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, doNotSyncSpill
++**
++** These two boolean 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 doNotSpill is non-zero, writing to the database from pagerStress()
++** is disabled altogether. This 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().
++**
++** If doNotSyncSpill is non-zero, 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.
++**
++** subjInMemory
++**
++** 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.
++**
++** dbSize, dbOrigSize, dbFileSize
++**
++** 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).
++**
++** 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).
++**
++** 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.
++**
++** 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.
++**
++** 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 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.
++**
++** 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 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';
++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 file */
++ u8 readOnly; /* True for a read-only database */
++ u8 memDb; /* True to inhibit all file I/O */
+
+- if( SQLITE_OK!=(rc = sqlite3OsFileSize(pJrnl, &szJ))
+- || szJ<16
+- || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-16, &len))
+- || len>=nMaster
+- || 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;
+- }
++ /**************************************************************************
++ ** The following block contains those class members that change during
++ ** routine opertion. 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 doNotSyncSpill; /* Do not do a spill that requires jrnl sync */
++ u8 subjInMemory; /* True to use in-memory sub-journals */
++ 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[] */
++ char dbFileVers[16]; /* Changes whenever database file changes */
+
+- /* 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;
+-}
++ 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) */
++ /*
++ ** End of the routinely-changing class members
++ ***************************************************************************/
++
++ 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
++};
+
+ /*
+-** Return the offset of the sector boundary at or immediately
+-** following the value in pPager->journalOff, assuming a sector
+-** size of pPager->sectorSize bytes.
+-**
+-** i.e for a sector size of 512:
+-**
+-** 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;
+-}
++** 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
+
+ /*
+-** The journal file must be open when this function is called.
+-**
+-** 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.
++** 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.
+ */
+-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 */
++#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
+
+- 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.
++** Journal files begin with the following magic string. The data
++** was obtained from /dev/random. It is used only as a sanity check.
+ **
+-** 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.
++** 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 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;
+- }
+- }
++static const unsigned char aJournalMagic[] = {
++ 0xd9, 0xd5, 0x05, 0xf9, 0x20, 0xa1, 0x63, 0xd7,
++};
+
+- pPager->journalHdr = pPager->journalOff = journalHdrOffset(pPager);
++/*
++** 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)
+
+- /*
+- ** 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 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 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 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
+
+- /* The page size */
+- put32bits(&zHeader[sizeof(aJournalMagic)+16], pPager->pageSize);
++/*
++** 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
+
+- /* 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));
++/*
++** The maximum legal page number is (2^31 - 1).
++*/
++#define PAGER_MAX_PGNO 2147483647
+
+- /* 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;
+- }
++/*
++** 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) ){ ...
++**
++** instead of
++**
++** if( pPager->jfd->pMethods ){ ...
++*/
++#define isOpen(pFd) ((pFd)->pMethods)
+
+- return rc;
++/*
++** 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
+ /*
+-** 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.
++** Usage:
+ **
+-** 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.
++** assert( assert_pager_state(pPager) );
+ **
+-** 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.
++** This function runs many asserts to try to find inconsistencies in
++** the internal state of the Pager object.
+ */
+-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 */
++static int assert_pager_state(Pager *p){
++ Pager *pPager = p;
+
+- assert( isOpen(pPager->jfd) ); /* Journal file must be open. */
++ /* 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
++ );
+
+- /* 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.
++ /* 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.
+ */
+- pPager->journalOff = journalHdrOffset(pPager);
+- if( pPager->journalOff+JOURNAL_HDR_SZ(pPager) > journalSize ){
+- return SQLITE_DONE;
+- }
+- iHdrOff = pPager->journalOff;
++ assert( p->tempFile==0 || p->eLock==EXCLUSIVE_LOCK );
++ assert( p->tempFile==0 || pPager->changeCountDone );
+
+- /* 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 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.
+ */
+- 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;
+- }
+- }
++ assert( p->journalMode==PAGER_JOURNALMODE_OFF || p->useJournal );
++ assert( p->journalMode!=PAGER_JOURNALMODE_OFF || !isOpen(p->jfd) );
+
+- /* 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.
++ /* 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( 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;
++ 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 );
+ }
+
+- pPager->journalOff += JOURNAL_HDR_SZ(pPager);
+- return rc;
+-}
++ /* 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;
+
+-/*
+-** 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:
+-**
+-** + 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 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 */
++ case PAGER_READER:
++ assert( pPager->errCode==SQLITE_OK );
++ assert( p->eLock!=UNKNOWN_LOCK );
++ assert( p->eLock>=SHARED_LOCK );
++ break;
+
+- assert( pPager->setMaster==0 );
+- assert( !pagerUseWal(pPager) );
++ 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;
+
+- if( !zMaster
+- || pPager->journalMode==PAGER_JOURNALMODE_MEMORY
+- || pPager->journalMode==PAGER_JOURNALMODE_OFF
+- ){
+- return SQLITE_OK;
+- }
+- pPager->setMaster = 1;
+- assert( isOpen(pPager->jfd) );
+- assert( pPager->journalHdr <= pPager->journalOff );
++ 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;
+
+- /* Calculate the length in bytes and the checksum of zMaster */
+- for(nMaster=0; zMaster[nMaster]; nMaster++){
+- cksum += zMaster[nMaster];
+- }
++ 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;
+
+- /* 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;
++ 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;
+
+- /* 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;
++ 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;
+ }
+- 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;
++ return 1;
+ }
++#endif /* ifndef NDEBUG */
+
++#ifdef SQLITE_DEBUG
+ /*
+-** 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.
++** 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 PgHdr *pager_lookup(Pager *pPager, Pgno pgno){
+- PgHdr *p; /* Return value */
++static char *print_pager_state(Pager *p){
++ static char zRet[1024];
+
+- /* 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;
++ 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
+
+ /*
+-** Discard the entire contents of the in-memory page-cache.
++** 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 void pager_reset(Pager *pPager){
+- sqlite3BackupRestart(pPager->pBackup);
+- sqlite3PcacheClear(pPager->pPCache);
++static int subjRequiresPage(PgHdr *pPg){
++ Pgno pgno = pPg->pgno;
++ Pager *pPager = pPg->pPager;
++ int i;
++ for(i=0; i<pPager->nSavepoint; i++){
++ PagerSavepoint *p = &pPager->aSavepoint[i];
++ if( p->nOrig>=pgno && 0==sqlite3BitvecTest(p->pInSavepoint, pgno) ){
++ return 1;
++ }
++ }
++ return 0;
+ }
+
+ /*
+-** 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.
++** Return true if the page is already in the journal file.
+ */
+-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;
++static int pageInJournal(PgHdr *pPg){
++ return sqlite3BitvecTest(pPg->pPager->pInJournal, pPg->pgno);
+ }
+
+ /*
+-** 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.
++** 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 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 );
+- }
++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;
+ }
+
+ /*
+-** 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 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).
+-**
+-** 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).
++** Write a 32-bit integer into a string buffer in big-endian byte order.
+ */
+-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;
+- }
++#define put32bits(A,B) sqlite3Put4byte((u8*)A,B)
+
+- /* 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;
+- }
+
+- pPager->journalOff = 0;
+- pPager->journalHdr = 0;
+- pPager->setMaster = 0;
++/*
++** 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);
+ }
+
+ /*
+-** 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.
++** 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.
+ **
+-** 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).
++** 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 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;
++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 = sqlite3OsUnlock(pPager->fd, eLock);
++ if( pPager->eLock!=UNKNOWN_LOCK ){
++ pPager->eLock = (u8)eLock;
++ }
++ IOTRACE(("UNLOCK %p %d\n", pPager, eLock))
+ }
+ 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.
+-**
+-** Otherwise, any active savepoints are released.
+-**
+-** 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:
+-**
+-** journalMode==MEMORY
+-** Journal file descriptor is simply closed. This destroys an
+-** in-memory journal.
+-**
+-** journalMode==TRUNCATE
+-** Journal file is truncated to zero bytes in size.
+-**
+-** 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.
+-**
+-** journalMode==DELETE
+-** The journal file is closed and deleted using sqlite3OsDelete().
+-**
+-** 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.
++** 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.
+ **
+-** 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.
++** 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 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);
+- }
+- 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);
+- }
+- }
+- }
++static int pagerLockDb(Pager *pPager, int eLock){
++ int rc = SQLITE_OK;
+
+-#ifdef SQLITE_CHECK_PAGES
+- sqlite3PcacheIterateDirty(pPager->pPCache, pager_set_pagehash);
+- if( pPager->dbSize==0 && sqlite3PcacheRefCount(pPager->pPCache)>0 ){
+- PgHdr *p = pager_lookup(pPager, 1);
+- if( p ){
+- p->pageHash = 0;
+- sqlite3PagerUnref(p);
++ assert( eLock==SHARED_LOCK || eLock==RESERVED_LOCK || eLock==EXCLUSIVE_LOCK );
++ if( pPager->eLock<eLock || pPager->eLock==UNKNOWN_LOCK ){
++ rc = 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))
+ }
+ }
+-#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( !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);
++ return rc;
+ }
+
+ /*
+-** Execute a rollback if a transaction is active and unlock the
+-** database file.
++** This function determines whether or not the atomic-write optimization
++** can be used with this pager. The optimization can be used if:
+ **
+-** 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.
++** (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.
+ **
+-** 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.
++** 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.
+ */
+-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);
++#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;
+ }
+ }
+- pager_unlock(pPager);
++
++ return JOURNAL_HDR_SZ(pPager) + JOURNAL_PG_SZ(pPager);
+ }
++#endif
+
+ /*
+-** 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 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.
+-**
+-** Changing the formula used to compute this checksum results in an
+-** incompatible journal file format.
+-**
+-** 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.
++** 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.
+ */
+-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;
++#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 cksum;
++ 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);
+ }
+
+ /*
+-** Report the current page size and number of reserved bytes back
+-** to the codec.
++** 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.
+ */
+-#ifdef SQLITE_HAS_CODEC
+-static void pagerReportSize(Pager *pPager){
+- if( pPager->xCodecSizeChng ){
+- pPager->xCodecSizeChng(pPager->pCodec, pPager->pageSize,
+- (int)pPager->nReserve);
+- }
++#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) );
+ }
+
-+SQLITE_PRIVATE int sqlite3pager_is_mj_pgno(Pager *pPager, Pgno pgno) {
-+ return (PAGER_MJ_PGNO(pPager) == pgno) ? 1 : 0;
+ #else
+-# define pagerReportSize(X) /* No-op if we do not support a codec */
+-#endif
++#define pager_datahash(X,Y) 0
++#define pager_pagehash(X) 0
++#define pager_set_pagehash(X)
++#define CHECK_PAGE(x)
++#endif /* SQLITE_CHECK_PAGES */
+
+ /*
+-** 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 main rollback journal uses checksums - the statement journal does
+-** not.
+-**
+-** 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.
++** 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 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.
++** 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 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.
++** 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.
+ **
+-** Neither of these two scenarios are possible during a savepoint rollback.
++** If it is determined that no master journal file name is present
++** zMaster[0] is set to 0 and SQLITE_OK returned.
+ **
+-** 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.
++** If an error occurs while reading from the journal file, an SQLite
++** error code is returned.
+ */
+-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 */
+-
+- 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;
+- }
+- }
++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 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 ){
++ if( SQLITE_OK!=(rc = sqlite3OsFileSize(pJrnl, &szJ))
++ || szJ<16
++ || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-16, &len))
++ || len>=nMaster
++ || 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;
+ }
+
+- /* 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 = pager_lookup(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==0 );
+- pPager->doNotSpill++;
+- rc = sqlite3PagerAcquire(pPager, pgno, &pPg, 1);
+- assert( pPager->doNotSpill==1 );
+- pPager->doNotSpill--;
+- if( rc!=SQLITE_OK ) return rc;
+- pPg->flags &= ~PGHDR_NEED_READ;
+- sqlite3PcacheMakeDirty(pPg);
++ /* See if the checksum matches the master journal name */
++ for(u=0; u<len; u++){
++ cksum -= zMaster[u];
+ }
+- 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().
++ 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.
+ */
+- 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);
++ len = 0;
+ }
+- return rc;
++ zMaster[len] = '\0';
++
++ return SQLITE_OK;
+ }
+
+ /*
+-** 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"
+-**
+-** A master journal file may only be deleted once all of its child
+-** journals have been rolled back.
+-**
+-** 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 the child journal exists, and if so
+-** * if the child journal contains a reference to master journal
+-** file zMaster
+-**
+-** 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().
++** 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 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.
++** i.e for a sector size of 512:
+ **
+-** 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.
++** Pager.journalOff Return value
++** ---------------------------------------
++** 0 0
++** 512 512
++** 100 512
++** 2000 2048
++**
+ */
+-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[] */
+-
+- /* 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;
+-
+- /* 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((int)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;
+-
+- 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;
+- }
+-
+- 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);
+-
+-delmaster_out:
+- sqlite3_free(zMasterJournal);
+- if( pMaster ){
+- sqlite3OsClose(pMaster);
+- assert( !isOpen(pJournal) );
+- sqlite3_free(pMaster);
++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);
+ }
+- return rc;
++ assert( offset%JOURNAL_HDR_SZ(pPager)==0 );
++ assert( offset>=c );
++ assert( (offset-c)<JOURNAL_HDR_SZ(pPager) );
++ return offset;
+ }
+
+-
+ /*
+-** 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).
++** The journal file must be open when this function is called.
+ **
+-** 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.
++** 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).
+ **
+-** Or, it might 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 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 successful, return SQLITE_OK. If an IO error occurs while modifying
+-** the database file, return the error code to the caller.
++** 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 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;
++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);
+ }
+ }
+ }
+@@ -40870,8409 +42646,8969 @@
+ }
+
+ /*
+-** 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.
++** 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.
++**
++** 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.
+ */
+-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;
++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);
+ }
+- return iRet;
+-}
+
+-/*
+-** 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
+-** 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.
+-*/
+-static void setSectorSize(Pager *pPager){
+- assert( isOpen(pPager->fd) || pPager->tempFile );
++ /* 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;
++ }
++ }
+
+- if( pPager->tempFile
+- || (sqlite3OsDeviceCharacteristics(pPager->fd) &
+- SQLITE_IOCAP_POWERSAFE_OVERWRITE)!=0
++ 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)
+ ){
+- /* 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;
++ memcpy(zHeader, aJournalMagic, sizeof(aJournalMagic));
++ put32bits(&zHeader[sizeof(aJournalMagic)], 0xffffffff);
+ }else{
+- pPager->sectorSize = sqlite3SectorSize(pPager->fd);
++ 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;
+ }
+
+ /*
+-** 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.
+-**
+-** 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 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.
++** 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.
+ **
+-** If an I/O or malloc() error occurs, the journal-file is not deleted
+-** and an error code is returned.
++** 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.
+ **
+-** 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 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 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 */
++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 */
+
+- /* Figure out how many records are in the journal. Abort early if
+- ** the journal is empty.
++ 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.
+ */
+- assert( isOpen(pPager->jfd) );
+- rc = sqlite3OsFileSize(pPager->jfd, &szJ);
+- if( rc!=SQLITE_OK ){
+- goto end_playback;
++ pPager->journalOff = journalHdrOffset(pPager);
++ if( pPager->journalOff+JOURNAL_HDR_SZ(pPager) > journalSize ){
++ return SQLITE_DONE;
+ }
++ iHdrOff = pPager->journalOff;
+
+- /* 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.
++ /* 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.
+ */
+- 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;
++ 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;
++ }
+ }
+- 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.
++ /* 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.
+ */
+- 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( 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 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( pPager->journalOff==0 ){
++ u32 iPageSize; /* Page-size field of journal header */
++ u32 iSectorSize; /* Sector-size field of journal header */
+
+- /* 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));
++ /* 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;
+ }
+
+- /* If this is the first header read from the journal, truncate the
+- ** database file back to its original size.
++ /* 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( pPager->journalOff==JOURNAL_HDR_SZ(pPager) ){
+- rc = pager_truncate(pPager, mxPg);
+- if( rc!=SQLITE_OK ){
+- goto end_playback;
+- }
+- pPager->dbSize = mxPg;
++ if( iPageSize==0 ){
++ iPageSize = pPager->pageSize;
+ }
+
+- /* Copy original pages out of the journal and back into the
+- ** database file and/or page cache.
++ /* 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.
+ */
+- 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;
++ 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;
++ }
+
+- 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);
+- }
+- 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.
++ /* 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 = pager_delmaster(pPager, zMaster);
++ rc = sqlite3PagerSetPagesize(pPager, &iPageSize, -1);
+ testcase( rc!=SQLITE_OK );
+- }
+- if( isHot && nPlayback ){
+- sqlite3_log(SQLITE_NOTICE_RECOVER_ROLLBACK, "recovered %d pages from %s",
+- nPlayback, pPager->zJournal);
++
++ /* 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;
+ }
+
+- /* 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);
++ pPager->journalOff += JOURNAL_HDR_SZ(pPager);
+ return rc;
+ }
+
+
+ /*
+-** 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.
++** 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 page 1 is read, then the value of Pager.dbFileVers[] is set to
+-** the value read from the database file.
++** + 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 an IO error occurs, then the IO error is returned to the caller.
+-** Otherwise, SQLITE_OK is returned.
++** 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 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 */
++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->eState>=PAGER_READER && !MEMDB );
+- assert( isOpen(pPager->fd) );
++ assert( pPager->setMaster==0 );
++ assert( !pagerUseWal(pPager) );
+
+- if( NEVER(!isOpen(pPager->fd)) ){
+- assert( pPager->tempFile );
+- memset(pPg->pData, 0, pPager->pageSize);
++ if( !zMaster
++ || pPager->journalMode==PAGER_JOURNALMODE_MEMORY
++ || pPager->journalMode==PAGER_JOURNALMODE_OFF
++ ){
+ return SQLITE_OK;
+ }
++ pPager->setMaster = 1;
++ assert( isOpen(pPager->jfd) );
++ assert( pPager->journalHdr <= pPager->journalOff );
+
+-#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;
+- }
++ /* Calculate the length in bytes and the checksum of zMaster */
++ for(nMaster=0; zMaster[nMaster]; nMaster++){
++ cksum += zMaster[nMaster];
+ }
+
+- 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 noising 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));
+- }
++ /* 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);
+ }
+- CODEC1(pPager, pPg->pData, pgno, 3, rc = SQLITE_NOMEM);
++ iHdrOff = pPager->journalOff;
+
+- 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)));
++ /* 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;
+ }
+
+ /*
+-** 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.
++** 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 void pager_write_changecounter(PgHdr *pPg){
+- u32 change_counter;
+-
+- /* 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);
++static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){
++ PgHdr *p; /* Return value */
+
+- /* 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);
++ /* 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;
+ }
+
+-#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.
+-**
+-** 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.
++** Discard the entire contents of the in-memory page-cache.
+ */
+-static int pagerUndoCallback(void *pCtx, Pgno iPg){
+- int rc = SQLITE_OK;
+- Pager *pPager = (Pager *)pCtx;
+- PgHdr *pPg;
+-
+- 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);
+- }
+- sqlite3PagerUnref(pPg);
+- }
+- }
+-
+- /* 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.
+- */
++static void pager_reset(Pager *pPager){
+ sqlite3BackupRestart(pPager->pBackup);
+-
+- return rc;
++ sqlite3PcacheClear(pPager->pPCache);
+ }
+
+ /*
+-** This function is called to rollback a transaction on a WAL database.
++** 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 int pagerRollbackWal(Pager *pPager){
+- int rc; /* Return Code */
+- PgHdr *pList; /* List of dirty pages to revert */
+-
+- /* 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).
+- */
+- 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;
++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);
+ }
+-
+- return rc;
++ if( !pPager->exclusiveMode || sqlite3IsMemJournal(pPager->sjfd) ){
++ sqlite3OsClose(pPager->sjfd);
++ }
++ sqlite3_free(pPager->aSavepoint);
++ pPager->aSavepoint = 0;
++ pPager->nSavepoint = 0;
++ pPager->nSubRec = 0;
+ }
+
+ /*
+-** 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 */
+-){
+- 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 );
+-#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( 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 *p;
+- 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;
++** 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 */
+
+- 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 ){
+- PgHdr *p;
+- for(p=pList; p; p=p->pDirty){
+- sqlite3BackupUpdate(pPager->pBackup, p->pgno, (u8 *)p->pData);
++ 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 );
+ }
+ }
+-
+-#ifdef SQLITE_CHECK_PAGES
+- pList = sqlite3PcacheDirtyList(pPager->pPCache);
+- for(p=pList; p; p=p->pDirty){
+- pager_set_pagehash(p);
+- }
+-#endif
+-
+ return rc;
+ }
+
+ /*
+-** Begin a read transaction on the WAL.
++** 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.
+ **
+-** 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.
++** 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).
++**
++** 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 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);
++static void pager_unlock(Pager *pPager){
+
+- rc = sqlite3WalBeginReadTransaction(pPager->pWal, &changed);
+- if( rc!=SQLITE_OK || changed ){
+- pager_reset(pPager);
+- if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0);
+- }
++ assert( pPager->eState==PAGER_READER
++ || pPager->eState==PAGER_OPEN
++ || pPager->eState==PAGER_ERROR
++ );
+
+- return rc;
+-}
+-#endif
++ sqlite3BitvecDestroy(pPager->pInJournal);
++ pPager->pInJournal = 0;
++ releaseAllSavepoints(pPager);
+
+-/*
+-** 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).
+-**
+-** 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 pagerPagecount(Pager *pPager, Pgno *pnPage){
+- Pgno nPage; /* Value to return via *pnPage */
++ 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;
+
+- /* 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 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 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;
+- }
++ /* 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;
+ }
+- nPage = (Pgno)((n+pPager->pageSize-1) / pPager->pageSize);
++
++ /* 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 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 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( nPage>pPager->mxPgno ){
+- pPager->mxPgno = (Pgno)nPage;
++ if( pPager->errCode ){
++ assert( !MEMDB );
++ pager_reset(pPager);
++ pPager->changeCountDone = pPager->tempFile;
++ pPager->eState = PAGER_OPEN;
++ pPager->errCode = SQLITE_OK;
+ }
+
+- *pnPage = nPage;
+- return SQLITE_OK;
+-}
+-
+-#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.
++ pPager->journalOff = 0;
++ pPager->journalHdr = 0;
++ pPager->setMaster = 0;
+}
+
-+SQLITE_PRIVATE sqlite3_file *sqlite3Pager_get_fd(Pager *pPager) {
-+ return (isOpen(pPager->fd)) ? pPager->fd : NULL;
++/*
++** 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.
+ **
+-** Return SQLITE_OK or an error code.
++** 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 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.
++** 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 pagerOpenWalIfPresent(Pager *pPager){
+- int rc = SQLITE_OK;
+- assert( pPager->eState==PAGER_OPEN );
+- assert( pPager->eLock>=SHARED_LOCK );
+-
+- if( !pPager->tempFile ){
+- int isWal; /* True if WAL file exists */
+- Pgno nPage; /* Size of the database file */
+-
+- 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;
+- }
+- }
++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;
+ }
+-#endif
++
++static int pager_truncate(Pager *pPager, Pgno nPage);
+
+ /*
+-** 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.
++** 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.
+ **
+-** 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:
++** Otherwise, any active savepoints are released.
+ **
+-** * 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 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:
+ **
+-** * 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.
++** journalMode==MEMORY
++** Journal file descriptor is simply closed. This destroys an
++** in-memory journal.
+ **
+-** * Pages are then played back from the sub-journal file, starting
+-** with the PagerSavepoint.iSubRec and continuing to the end of
+-** the journal file.
++** journalMode==TRUNCATE
++** Journal file is truncated to zero bytes in size.
+ **
+-** 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.
++** 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.
+ **
+-** 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.
++** journalMode==DELETE
++** The journal file is closed and deleted using sqlite3OsDelete().
+ **
+-** 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 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.
+ */
+-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;
+- }
+- }
++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 */
+
+- /* Set the database size back to the value it was before the savepoint
+- ** being reverted was opened.
++ /* 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.
+ */
+- pPager->dbSize = pSavepoint ? pSavepoint->nOrig : pPager->dbOrigSize;
+- pPager->changeCountDone = pPager->tempFile;
+-
+- if( !pSavepoint && pagerUseWal(pPager) ){
+- return pagerRollbackWal(pPager);
++ assert( assert_pager_state(pPager) );
++ assert( pPager->eState!=PAGER_ERROR );
++ if( pPager->eState<PAGER_WRITER_LOCKED && pPager->eLock<RESERVED_LOCK ){
++ return SQLITE_OK;
+ }
+
+- /* 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 );
++ releaseAllSavepoints(pPager);
++ assert( isOpen(pPager->jfd) || pPager->pInJournal==0 );
++ if( isOpen(pPager->jfd) ){
++ assert( !pagerUseWal(pPager) );
+
+- /* 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);
++ /* 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);
++ }
++ 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);
++ }
+ }
+- assert( rc!=SQLITE_DONE );
+- }else{
+- pPager->journalOff = 0;
+ }
+
+- /* 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 );
+-
+- /*
+- ** 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( nJRec==0
+- && pPager->journalHdr+JOURNAL_HDR_SZ(pPager)==pPager->journalOff
+- ){
+- 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);
++#ifdef SQLITE_CHECK_PAGES
++ sqlite3PcacheIterateDirty(pPager->pPCache, pager_set_pagehash);
++ if( pPager->dbSize==0 && sqlite3PcacheRefCount(pPager->pPCache)>0 ){
++ PgHdr *p = pager_lookup(pPager, 1);
++ if( p ){
++ p->pageHash = 0;
++ sqlite3PagerUnref(p);
+ }
+- assert( rc!=SQLITE_DONE );
+ }
+- assert( rc!=SQLITE_OK || pPager->journalOff>=szJ );
++#endif
+
+- /* 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);
++ sqlite3BitvecDestroy(pPager->pInJournal);
++ pPager->pInJournal = 0;
++ pPager->nRec = 0;
++ sqlite3PcacheCleanAll(pPager->pPCache);
++ sqlite3PcacheTruncate(pPager->pPCache, pPager->dbSize);
+
+- 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 );
++ 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);
+ }
+
+- sqlite3BitvecDestroy(pDone);
+- if( rc==SQLITE_OK ){
+- pPager->journalOff = szJ;
++ 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;
+-}
+-
+-/*
+-** Change the maximum number of in-memory pages that are allowed.
+-*/
+-SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){
+- sqlite3PcacheSetCachesize(pPager->pPCache, mxPage);
++ return (rc==SQLITE_OK?rc2:rc);
+ }
+
+ /*
+-** Invoke SQLITE_FCNTL_MMAP_SIZE based on the current value of szMmap.
++** 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.
+ */
+-static void pagerFixMaplimit(Pager *pPager){
+-#if SQLITE_MAX_MMAP_SIZE>0
+- sqlite3_file *fd = pPager->fd;
+- if( isOpen(fd) ){
+- sqlite3_int64 sz;
+- pPager->bUseFetch = (fd->pMethods->iVersion>=3) && pPager->szMmap>0;
+- sz = pPager->szMmap;
+- sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_MMAP_SIZE, &sz);
++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);
++ }
+ }
+-#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);
+-}
+-
+-/*
+-** Free as much memory as possible from the pager.
+-*/
+-SQLITE_PRIVATE void sqlite3PagerShrink(Pager *pPager){
+- sqlite3PcacheShrink(pPager->pPCache);
++ pager_unlock(pPager);
+ }
+
+ /*
+-** Adjust the robustness of the database to damage due to OS crashes
+-** or power failures by changing the number of syncs()s when writing
+-** the rollback journal. 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.
++** 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.
+ **
+-** 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.
++** 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.
+ **
+-** 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.
++** Changing the formula used to compute this checksum results in an
++** incompatible journal file format.
+ **
+-** Numeric values associated with these states are OFF==1, NORMAL=2,
+-** and FULL=3.
++** 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.
+ */
+-#ifndef SQLITE_OMIT_PAGER_PRAGMAS
+-SQLITE_PRIVATE void sqlite3PagerSetSafetyLevel(
+- Pager *pPager, /* The pager to set safety level for */
+- int level, /* PRAGMA synchronous. 1=OFF, 2=NORMAL, 3=FULL */
+- int bFullFsync, /* PRAGMA fullfsync */
+- int bCkptFullFsync /* PRAGMA checkpoint_fullfsync */
+-){
+- 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( bFullFsync ){
+- pPager->syncFlags = SQLITE_SYNC_FULL;
+- pPager->ckptSyncFlags = SQLITE_SYNC_FULL;
+- }else if( bCkptFullFsync ){
+- pPager->syncFlags = SQLITE_SYNC_NORMAL;
+- pPager->ckptSyncFlags = SQLITE_SYNC_FULL;
+- }else{
+- pPager->syncFlags = SQLITE_SYNC_NORMAL;
+- pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL;
+- }
+- pPager->walSyncFlags = pPager->syncFlags;
+- if( pPager->fullSync ){
+- pPager->walSyncFlags |= WAL_SYNC_TRANSACTIONS;
++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;
+ }
+-#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.
++** Report the current page size and number of reserved bytes back
++** to the codec.
+ */
+-#ifdef SQLITE_TEST
+-SQLITE_API int sqlite3_opentemp_count = 0;
++#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
+
+ /*
+-** Open a temporary file.
++** 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.
+ **
+-** 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 main rollback journal uses checksums - the statement journal does
++** not.
++**
++** 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 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.
+ **
+-** The flags passed to the VFS layer xOpen() call are those specified
+-** by parameter vfsFlags ORed with the following:
++** Neither of these two scenarios are possible during a savepoint rollback.
+ **
+-** SQLITE_OPEN_READWRITE
+-** SQLITE_OPEN_CREATE
+-** SQLITE_OPEN_EXCLUSIVE
+-** SQLITE_OPEN_DELETEONCLOSE
++** 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.
+ */
+-static int pagerOpentemp(
+- Pager *pPager, /* The pager object */
+- sqlite3_file *pFile, /* Write the file descriptor here */
+- int vfsFlags /* Flags passed through to the VFS */
++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; /* Return code */
++ 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 */
+
+-#ifdef SQLITE_TEST
+- sqlite3_opentemp_count++; /* Used for testing and analysis only */
+-#endif
++ 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 */
+
+- 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;
+-}
++ aData = pPager->pTmpSpace;
++ assert( aData ); /* Temp storage must have already been allocated */
++ assert( pagerUseWal(pPager)==0 || (!isMainJrnl && isSavepnt) );
+
+-/*
+-** Set the busy handler function.
+-**
+-** 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:
+-**
+-** 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 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.
+-*/
+-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;
++ /* 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 );
+
+- 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);
++ /* 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;
+
-+SQLITE_PRIVATE void sqlite3pager_sqlite3PagerSetCodec(
-+ Pager *pPager,
-+ void *(*xCodec)(void*,void*,Pgno,int),
-+ void (*xCodecSizeChng)(void*,int,int),
-+ void (*xCodecFree)(void*),
-+ void *pCodec
++ /* 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 = pager_lookup(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==0 );
++ pPager->doNotSpill++;
++ rc = sqlite3PagerAcquire(pPager, pgno, &pPg, 1);
++ assert( pPager->doNotSpill==1 );
++ pPager->doNotSpill--;
++ 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((int)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;
++ }
+
+- if( rc==SQLITE_OK ){
+- pager_reset(pPager);
+- pPager->dbSize = (Pgno)((nByte+pageSize-1)/pageSize);
+- pPager->pageSize = pageSize;
+- sqlite3PageFree(pPager->pTmpSpace);
+- pPager->pTmpSpace = pNew;
+- sqlite3PcacheSetPageSize(pPager->pPCache, pageSize);
++ rc = readMasterJournal(pJournal, zMasterPtr, nMasterPtr);
++ sqlite3OsClose(pJournal);
++ if( rc!=SQLITE_OK ){
++ goto delmaster_out;
++ }
++
++ 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 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 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 transistions 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 */
++ /* 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( 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;
++ /* 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));
+ }
+- p->pExtra = (void *)&p[1];
+- p->flags = PGHDR_MMAP;
+- p->nRef = 1;
+- p->pPager = 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 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));
++ }
+
+- p->pgno = pgno;
+- p->pData = pData;
+- pPager->nMmapOut++;
++ /* 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;
++ }
+
+- return SQLITE_OK;
+-}
++ /* 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 );
+
+-/*
+-** 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);
++ }
++ 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) );
++
++ if( NEVER(!isOpen(pPager->fd)) ){
++ assert( pPager->tempFile );
++ memset(pPg->pData, 0, pPager->pageSize);
++ return SQLITE_OK;
++ }
+
+- 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 noising 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;
++ sqlite3PagerUnref(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
+- && (pList->pDirty ? pPager->dbSize : pList->pgno+1)>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);
++ return rc;
++}
+
+- /* Encode the database */
+- CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM, pData);
++/*
++** 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 */
++#if defined(SQLITE_DEBUG) || defined(SQLITE_CHECK_PAGES)
++ PgHdr *p; /* For looping over pages */
++#endif
+
+- /* Write out the page data. */
+- rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset);
++ 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
+
+- /* 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;
++ 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 *p;
++ PgHdr **ppNext = &pList;
++ nList = 0;
++ for(p=pList; (*ppNext = p)!=0; p=p->pDirty){
++ if( p->pgno<=nTruncate ){
++ ppNext = &p->pDirty;
++ nList++;
+ }
+- pPager->aStat[PAGER_STAT_WRITE]++;
+-
+- /* Update any backup objects copying the contents of this pager. */
+- sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)pList->pData);
++ }
++ 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 ){
++ PgHdr *p;
++ 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(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 doNotSyncSpill flag 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 flag inhibits all cache spilling regardless of whether
+- ** or not a sync is required. This is set during a rollback.
+- **
+- ** 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
+- ** 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;
+- if( pPager->doNotSpill ) return SQLITE_OK;
+- if( pPager->doNotSyncSpill && (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 */
++ Bitvec *pDone = 0; /* Bitvec to ensure pages played back only once */
+
+- /* 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());
++ 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 output variable to NULL in case an error occurs. */
+- *ppPager = 0;
++ /* 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;
+
+-#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;
+- }
++ if( !pSavepoint && pagerUseWal(pPager) ){
++ return pagerRollbackWal(pPager);
+ }
+-#endif
+
+- /* 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.
++ /* 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.
+ */
+- 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;
++ 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;
+ }
+
+- /* 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)
++ /* 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.
+ */
+- 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) );
++ 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 );
+
+- /* 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);
++ /*
++ ** 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( nJRec==0
++ && pPager->journalHdr+JOURNAL_HDR_SZ(pPager)==pPager->journalOff
++ ){
++ 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);
++ }
++ assert( rc!=SQLITE_DONE );
+ }
+- pPager->pVfs = pVfs;
+- pPager->vfsFlags = vfsFlags;
++ assert( rc!=SQLITE_OK || pPager->journalOff>=szJ );
+
+- /* Open the pager file.
++ /* 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( 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( pSavepoint ){
++ u32 ii; /* Loop counter */
++ i64 offset = (i64)pSavepoint->iSubRec*(4+pPager->pageSize);
+
+- /* 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( rc==SQLITE_OK && !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 iDc = sqlite3OsDeviceCharacteristics(pPager->fd);
+- 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
++ 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);
+ }
+- }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.
+- */
+- tempFile = 1;
+- pPager->eState = PAGER_READER;
+- pPager->eLock = EXCLUSIVE_LOCK;
+- readOnly = (vfsFlags&SQLITE_OPEN_READONLY);
++ assert( rc!=SQLITE_DONE );
+ }
+
+- /* The following call to PagerSetPagesize() serves to set the value of
+- ** Pager.pageSize and to allocate the Pager.pTmpSpace buffer.
+- */
++ sqlite3BitvecDestroy(pDone);
+ if( rc==SQLITE_OK ){
+- assert( pPager->memDb==0 );
+- rc = sqlite3PagerSetPagesize(pPager, &szPageDflt, -1);
+- testcase( rc!=SQLITE_OK );
++ pPager->journalOff = szJ;
+ }
+
+- /* If an error occurred in either of the blocks above, free the
+- ** Pager structure and close the file.
+- */
+- if( rc!=SQLITE_OK ){
+- assert( !pPager->pTmpSpace );
+- sqlite3OsClose(pPager->fd);
+- 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) ){
++ sqlite3_int64 sz;
++ pPager->bUseFetch = (fd->pMethods->iVersion>=3) && pPager->szMmap>0;
++ sz = pPager->szMmap;
++ sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_MMAP_SIZE, &sz);
+ }
++#endif
++}
+
+- /* Initialize the PCache object. */
+- assert( nExtra<1000 );
+- nExtra = ROUND8(nExtra);
+- sqlite3PcacheOpen(szPageDflt, nExtra, !memDb,
+- !memDb?pagerStress:0, (void *)pPager, pPager->pPCache);
++/*
++** 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);
++}
+
+- PAGERTRACE(("OPEN %d %s\n", FILEHANDLEID(pPager->fd), pPager->zFilename));
+- IOTRACE(("OPEN %p %s\n", pPager, pPager->zFilename))
++/*
++** Free as much memory as possible from the pager.
++*/
++SQLITE_PRIVATE void sqlite3PagerShrink(Pager *pPager){
++ sqlite3PcacheShrink(pPager->pPCache);
++}
+
+- 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; */
+-#if 0
+- assert( pPager->state == (tempFile ? PAGER_EXCLUSIVE : PAGER_UNLOCK) );
+-#endif
+- /* 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;
++/*
++** Adjust the robustness of the database to damage due to OS crashes
++** or power failures by changing the number of syncs()s when writing
++** the rollback journal. 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 sqlite3PagerSetSafetyLevel(
++ Pager *pPager, /* The pager to set safety level for */
++ int level, /* PRAGMA synchronous. 1=OFF, 2=NORMAL, 3=FULL */
++ int bFullFsync, /* PRAGMA fullfsync */
++ int bCkptFullFsync /* PRAGMA checkpoint_fullfsync */
++){
++ 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( bFullFsync ){
++ pPager->syncFlags = SQLITE_SYNC_FULL;
++ pPager->ckptSyncFlags = SQLITE_SYNC_FULL;
++ }else if( bCkptFullFsync ){
++ 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;
+ }
+- /* 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 */
++}
++#endif
+
+- *ppPager = pPager;
+- return SQLITE_OK;
++/*
++** 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
++
++/*
++** 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 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
++
++ 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;
+ }
+
++/*
++** Set the busy handler function.
++**
++** 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:
++**
++** 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 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.
++*/
++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;
+
++ 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);
++ }
++}
+
+ /*
+-** 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:
++** Change the page size used by the Pager object. The new page size
++** is passed in *pPageSize.
+ **
+-** * 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 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).
+ **
+-** 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.
++** Otherwise, if all of the following are true:
+ **
+-** 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.
++** * the new page size (value of *pPageSize) is valid (a power
++** of two between 512 and SQLITE_MAX_PAGE_SIZE, inclusive), and
+ **
+-** 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.
++** * 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.
+ */
+-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);
++SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nReserve){
++ int rc = SQLITE_OK;
+
+- assert( pPager->useJournal );
+- assert( isOpen(pPager->fd) );
+- assert( pPager->eState==PAGER_OPEN );
++ /* 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( jrnlOpen==0 || ( sqlite3OsDeviceCharacteristics(pPager->jfd) &
+- SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN
+- ));
++ 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;
+
+- *pExists = 0;
+- if( !jrnlOpen ){
+- rc = sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &exists);
++ 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( rc==SQLITE_OK ){
++ pager_reset(pPager);
++ pPager->dbSize = (Pgno)((nByte+pageSize-1)/pageSize);
++ pPager->pageSize = pageSize;
++ sqlite3PageFree(pPager->pTmpSpace);
++ pPager->pTmpSpace = pNew;
++ sqlite3PcacheSetPageSize(pPager->pPCache, pageSize);
++ }
+ }
+- 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 */
++ *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;
++}
+
+- /* Check the size of the database file. If it consists of 0 pages,
+- ** then delete the journal file. See the header comment above for
+- ** the reasoning here. Delete the obsolete journal file under
+- ** a RESERVED lock to avoid race conditions and to avoid violating
+- ** [H33020].
+- */
+- rc = pagerPagecount(pPager, &nPage);
+- if( rc==SQLITE_OK ){
+- if( nPage==0 ){
+- 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
+- ** its 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 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.
++**
++** 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;
+ }
+
+ /*
+-** 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 following operations are also performed by this function.
++** 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.
+ **
+-** 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.
++** 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;
++}
++
++
++/*
++** 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).
+ **
+-** 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.
++** 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.
+ **
+-** 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.
++** 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.
+ */
+-SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
+- int rc = SQLITE_OK; /* Return code */
++static int pager_wait_on_lock(Pager *pPager, int locktype){
++ int rc; /* Return code */
+
+- /* 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.
++ /* Check that this is either a no-op (because the requested lock is
++ ** already held, or one of the transistions that the busy-handler
++ ** may be invoked during, according to the comment above
++ ** sqlite3PagerSetBusyhandler().
+ */
+- 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; }
++ assert( (pPager->eLock>=locktype)
++ || (pPager->eLock==NO_LOCK && locktype==SHARED_LOCK)
++ || (pPager->eLock==RESERVED_LOCK && locktype==EXCLUSIVE_LOCK)
++ );
+
+- if( !pagerUseWal(pPager) && pPager->eState==PAGER_OPEN ){
+- int bHotJournal = 1; /* True if there exists a hot journal-file */
++ do {
++ rc = pagerLockDb(pPager, locktype);
++ }while( rc==SQLITE_BUSY && pPager->xBusyHandler(pPager->pBusyHandlerArg) );
++ return rc;
++}
+
+- assert( !MEMDB );
++/*
++** 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
+
+- rc = pager_wait_on_lock(pPager, SHARED_LOCK);
+- if( rc!=SQLITE_OK ){
+- assert( pPager->eLock==NO_LOCK || pPager->eLock==UNKNOWN_LOCK );
+- goto failed;
+- }
++/*
++** 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;
+
+- /* 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 ){
+- goto failed;
+- }
+- if( bHotJournal ){
+- if( pPager->readOnly ){
+- rc = SQLITE_READONLY_ROLLBACK;
+- goto failed;
+- }
++ /* 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. */
++}
+
+- /* 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);
+- }
+
+- 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;
+- }
++/*
++** 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;
++}
+
+- assert( pPager->eState==PAGER_OPEN );
+- assert( (pPager->eLock==SHARED_LOCK)
+- || (pPager->exclusiveMode && pPager->eLock>SHARED_LOCK)
+- );
++/*
++** 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( !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.
+- **
+- ** 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)];
++ assert( p->pExtra==(void *)&p[1] );
++ assert( p->pPage==0 );
++ assert( p->flags==PGHDR_MMAP );
++ assert( p->pPager==pPager );
++ assert( p->nRef==1 );
+
+- rc = pagerPagecount(pPager, &nPage);
+- if( rc ) goto failed;
++ p->pgno = pgno;
++ p->pData = pData;
++ pPager->nMmapOut++;
+
+- 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));
+- }
++ return SQLITE_OK;
++}
+
+- if( memcmp(pPager->dbFileVers, dbFileVers, sizeof(dbFileVers))!=0 ){
+- pager_reset(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;
+
+- /* 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);
+- }
+- }
+- }
++ assert( pPager->fd->pMethods->iVersion>=3 );
++ sqlite3OsUnfetch(pPager->fd, (i64)(pPg->pgno-1)*pPager->pageSize, pPg->pData);
++}
+
+- /* 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
++/*
++** 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( pagerUseWal(pPager) ){
+- assert( rc==SQLITE_OK );
+- rc = pagerBeginReadTransaction(pPager);
+- }
+
+- if( pPager->eState==PAGER_OPEN && rc==SQLITE_OK ){
+- rc = pagerPagecount(pPager, &pPager->dbSize);
+- }
++/*
++** Shutdown the page cache. Free all memory and close all files.
++**
++** 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.
++**
++** 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 sqlite3PagerClose(Pager *pPager){
++ u8 *pTmp = (u8 *)pPager->pTmpSpace;
+
+- failed:
+- if( rc!=SQLITE_OK ){
+- assert( !MEMDB );
++ 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;
++#endif
++ pager_reset(pPager);
++ if( MEMDB ){
+ pager_unlock(pPager);
+- assert( pPager->eState==PAGER_OPEN );
+ }else{
+- pPager->eState = PAGER_READER;
++ /* 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);
+ }
+- return rc;
++ 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
++
++ assert( !pPager->aSavepoint && !pPager->pInJournal );
++ assert( !isOpen(pPager->jfd) && !isOpen(pPager->sjfd) );
++
++ sqlite3_free(pPager);
++ return SQLITE_OK;
+ }
+
++#if !defined(NDEBUG) || defined(SQLITE_TEST)
+ /*
+-** 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);
+- }
++** Return the page number for page pPg.
++*/
++SQLITE_PRIVATE Pgno sqlite3PagerPagenumber(DbPage *pPg){
++ return pPg->pgno;
+ }
++#endif
+
+ /*
+-** 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.
++** Increment the reference count for page pPg.
++*/
++SQLITE_PRIVATE void sqlite3PagerRef(DbPage *pPg){
++ sqlite3PcacheRef(pPg);
++}
++
++/*
++** 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 noContent is true, it means that we do not care about the contents
+-** of the page. This occurs in two seperate scenarios:
++** 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:
+ **
+-** a) When reading a free-list leaf page from the database, and
++** * If the journal file is an in-memory journal file, no action need
++** be taken.
+ **
+-** 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.
++** * 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 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.
++** * If the device does not support the SEQUENTIAL property, then
++** journal file is synced.
+ **
+-** The acquisition might fail for several reasons. In all cases,
+-** an appropriate error code is returned and *ppPage is set to NULL.
++** Or, in pseudo-code:
+ **
+-** 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.
++** 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.
+ */
+-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_ACQUIRE_XXX flags */
+-){
+- int rc = SQLITE_OK;
+- PgHdr *pPg = 0;
+- u32 iFrame = 0; /* Frame to read from WAL file */
+- const int noContent = (flags & PAGER_ACQUIRE_NOCONTENT);
++static int syncJournal(Pager *pPager, int newHdr){
++ int rc; /* Return code */
+
+- /* 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_ACQUIRE_READONLY))
+-#ifdef SQLITE_HAS_CODEC
+- && pPager->xCodec==0
+-#endif
++ assert( pPager->eState==PAGER_WRITER_CACHEMOD
++ || pPager->eState==PAGER_WRITER_DBMOD
+ );
+-
+- assert( pPager->eState>=PAGER_READER );
+ assert( assert_pager_state(pPager) );
+- assert( noContent==0 || bMmapOk==0 );
+-
+- if( pgno==0 ){
+- return SQLITE_CORRUPT_BKPT;
+- }
++ assert( !pagerUseWal(pPager) );
+
+- /* 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{
++ rc = sqlite3PagerExclusiveLock(pPager);
++ if( rc!=SQLITE_OK ) return rc;
+
+- if( bMmapOk && pagerUseWal(pPager) ){
+- rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
+- if( rc!=SQLITE_OK ) goto pager_acquire_err;
+- }
++ 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( iFrame==0 && bMmapOk ){
+- void *pData = 0;
++ 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];
+
+- rc = sqlite3OsFetch(pPager->fd,
+- (i64)(pgno-1) * pPager->pageSize, pPager->pageSize, &pData
+- );
++ memcpy(zHeader, aJournalMagic, sizeof(aJournalMagic));
++ put32bits(&zHeader[sizeof(aJournalMagic)], pPager->nRec);
+
+- if( rc==SQLITE_OK && pData ){
+- if( pPager->eState>PAGER_READER ){
+- (void)sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &pPg);
++ 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( pPg==0 ){
+- rc = pagerAcquireMapPage(pPager, pgno, pData, &pPg);
+- }else{
+- sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1)*pPager->pageSize, pData);
++ if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){
++ return rc;
+ }
+- if( pPg ){
+- assert( rc==SQLITE_OK );
+- *ppPage = pPg;
+- return SQLITE_OK;
++
++ /* 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( rc!=SQLITE_OK ){
+- goto pager_acquire_err;
++ 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;
++ }
++
++ 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;
+ }
++ }
+
+- rc = sqlite3PcacheFetch(pPager->pPCache, pgno, 1, ppPage);
++ /* 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;
+}
+
++/*
++** 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.
++*/
++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);
+ }
+
+- 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;
++ /* 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
++ && (pList->pDirty ? pPager->dbSize : pList->pgno+1)>pPager->dbHintSize
++ ){
++ sqlite3_int64 szFile = pPager->pageSize * (sqlite3_int64)pPager->dbSize;
++ sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_SIZE_HINT, &szFile);
++ pPager->dbHintSize = pPager->dbSize;
+ }
+- 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;
++ while( rc==SQLITE_OK && pList ){
++ Pgno pgno = pList->pgno;
+
+- }else{
+- /* The pager cache has created a new page. Its content needs to
+- ** be initialized. */
++ /* 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 */
+
+- pPg = *ppPage;
+- pPg->pPager = pPager;
++ assert( (pList->flags&PGHDR_NEED_SYNC)==0 );
++ if( pList->pgno==1 ) pager_write_changecounter(pList);
+
+- /* 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;
+- }
++ /* Encode the database */
++ CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM, pData);
+
+- 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;
++ /* 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.
++ */
++ if( pgno==1 ){
++ memcpy(&pPager->dbFileVers, &pData[24], sizeof(pPager->dbFileVers));
+ }
+- assert( pPg->pPager==pPager );
+- pPager->aStat[PAGER_STAT_MISS]++;
+- rc = readDbPage(pPg, iFrame);
+- if( rc!=SQLITE_OK ){
+- goto pager_acquire_err;
++ if( pgno>pPager->dbFileSize ){
++ pPager->dbFileSize = pgno;
+ }
+- }
+- pager_set_pagehash(pPg);
+- }
++ pPager->aStat[PAGER_STAT_WRITE]++;
+
+- return SQLITE_OK;
++ /* Update any backup objects copying the contents of this pager. */
++ sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)pList->pData);
+
+-pager_acquire_err:
+- assert( rc!=SQLITE_OK );
+- if( pPg ){
+- sqlite3PcacheDrop(pPg);
++ 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;
+ }
+- pagerUnlockIfUnused(pPager);
+
+- *ppPage = 0;
+ return rc;
+ }
+
+ /*
+-** 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 DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
+- PgHdr *pPg = 0;
+- 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;
+-}
+-
+-/*
+-** Release a page reference.
++** Ensure that the sub-journal file is open. If it is already open, this
++** function is a no-op.
+ **
+-** 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_OK is returned if everything goes according to plan. An
++** SQLITE_IOERR_XXX error code is returned if a call to sqlite3OsOpen()
++** fails.
+ */
+-SQLITE_PRIVATE void sqlite3PagerUnref(DbPage *pPg){
+- if( pPg ){
+- Pager *pPager = pPg->pPager;
+- if( pPg->flags & PGHDR_MMAP ){
+- pagerReleaseMapPage(pPg);
++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{
+- sqlite3PcacheRelease(pPg);
++ rc = pagerOpentemp(pPager, pPager->sjfd, SQLITE_OPEN_SUBJOURNAL);
+ }
+- pagerUnlockIfUnused(pPager);
+ }
++ return rc;
+ }
+
+ /*
+-** 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.
+-**
+-** 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 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.
++** 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.
+ **
+-** Whether or not the journal file is opened by this function, the
+-** Pager.pInJournal bitvec structure is allocated.
++** If successful, set the bit corresponding to pPg->pgno in the bitvecs
++** for all open savepoints before returning.
+ **
+-** 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.
++** 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 pager_open_journal(Pager *pPager){
+- int rc = SQLITE_OK; /* Return code */
+- sqlite3_vfs * const pVfs = pPager->pVfs; /* Local cache of vfs pointer */
++static int subjournalPage(PgHdr *pPg){
++ int rc = SQLITE_OK;
++ Pager *pPager = pPg->pPager;
++ if( pPager->journalMode!=PAGER_JOURNALMODE_OFF ){
+
+- 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;
++ /* 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(pPg)
++ || pPg->pgno>pPager->dbOrigSize
++ );
++ rc = openSubJournal(pPager);
+
+- if( !pagerUseWal(pPager) && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){
+- pPager->pInJournal = sqlite3BitvecCreate(pPager->dbSize);
+- if( pPager->pInJournal==0 ){
+- return SQLITE_NOMEM;
+- }
++ /* 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;
+
+- /* 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)
+- );
+- #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
++ 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);
+ }
+- 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;
+- }
+-
++ if( rc==SQLITE_OK ){
++ pPager->nSubRec++;
++ assert( pPager->nSavepoint>0 );
++ rc = addToSavepointBitvecs(pPager, pPg->pgno);
++ }
+ return rc;
+ }
+
+ /*
+-** Begin a write-transaction on the specified pager object. If a
+-** write-transaction has already been opened, this function is a no-op.
++** 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.
+ **
+-** 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 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 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.
++** 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.
+ */
+-SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory){
++static int pagerStress(void *p, PgHdr *pPg){
++ Pager *pPager = (Pager *)p;
+ int rc = SQLITE_OK;
+
+- if( pPager->errCode ) return pPager->errCode;
+- assert( pPager->eState>=PAGER_READER && pPager->eState<PAGER_ERROR );
+- pPager->subjInMemory = (u8)subjInMemory;
+-
+- if( ALWAYS(pPager->eState==PAGER_READER) ){
+- assert( pPager->pInJournal==0 );
++ assert( pPg->pPager==pPager );
++ assert( pPg->flags&PGHDR_DIRTY );
+
+- 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);
+- }
++ /* The doNotSyncSpill flag 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 flag inhibits all cache spilling regardless of whether
++ ** or not a sync is required. This is set during a rollback.
++ **
++ ** 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
++ ** 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;
++ if( pPager->doNotSpill ) return SQLITE_OK;
++ if( pPager->doNotSyncSpill && (pPg->flags & PGHDR_NEED_SYNC)!=0 ){
++ return SQLITE_OK;
++ }
+
+- /* 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);
+- }
++ 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 ){
+- /* 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;
++ 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);
+ }
++ }
+
+- assert( rc==SQLITE_OK || pPager->eState==PAGER_READER );
+- assert( rc!=SQLITE_OK || pPager->eState==PAGER_WRITER_LOCKED );
+- assert( assert_pager_state(pPager) );
++ /* Mark the page as clean. */
++ if( rc==SQLITE_OK ){
++ PAGERTRACE(("STRESS %d page %d\n", PAGERID(pPager), pPg->pgno));
++ sqlite3PcacheMakeClean(pPg);
+ }
+
+- PAGERTRACE(("TRANSACTION %d\n", PAGERID(pPager)));
+- return rc;
++ return pager_error(pPager, 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.
++** 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 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.
++**
++** 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.
+ */
+-static int pager_write(PgHdr *pPg){
+- void *pData = pPg->pData;
+- Pager *pPager = pPg->pPager;
+- int rc = SQLITE_OK;
++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 */
+
+- /* 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.
++ /* 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).
+ */
+- assert( pPager->eState==PAGER_WRITER_LOCKED
+- || pPager->eState==PAGER_WRITER_CACHEMOD
+- || pPager->eState==PAGER_WRITER_DBMOD
+- );
+- assert( assert_pager_state(pPager) );
+-
+- /* If an error has been previously detected, report the same error
+- ** again. This should not happen, but the check provides robustness. */
+- if( NEVER(pPager->errCode) ) return pPager->errCode;
++ if( sqlite3JournalSize(pVfs)>sqlite3MemJournalSize() ){
++ journalFileSize = ROUND8(sqlite3JournalSize(pVfs));
++ }else{
++ journalFileSize = ROUND8(sqlite3MemJournalSize());
++ }
+
+- /* Higher-level routines never call this function if database is not
+- ** writable. But check anyway, just for robustness. */
+- if( NEVER(pPager->readOnly) ) return SQLITE_PERM;
++ /* Set the output variable to NULL in case an error occurs. */
++ *ppPager = 0;
+
+- CHECK_PAGE(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;
++ }
++ }
++#endif
+
+- /* 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.
++ /* 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( pPager->eState==PAGER_WRITER_LOCKED ){
+- rc = pager_open_journal(pPager);
+- if( rc!=SQLITE_OK ) return rc;
++ 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;
++ }
+ }
+- 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.
++ /* 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)
+ */
+- sqlite3PcacheMakeDirty(pPg);
+- if( pageInJournal(pPg) && !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( !pageInJournal(pPg) && !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, 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;
++ 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) );
+
+- 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;
++ /* 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;
+
+- 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 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);
+
+- 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;
++ /* 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( rc==SQLITE_OK && !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;
+ }
+- }else{
+- if( pPager->eState!=PAGER_WRITER_DBMOD ){
+- pPg->flags |= PGHDR_NEED_SYNC;
++ }
++#ifdef SQLITE_ENABLE_ATOMIC_WRITE
++ {
++ int iDc = sqlite3OsDeviceCharacteristics(pPager->fd);
++ 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;
++ }
+ }
+- PAGERTRACE(("APPEND %d page %d needSync=%d\n",
+- PAGERID(pPager), pPg->pgno,
+- ((pPg->flags&PGHDR_NEED_SYNC)?1:0)));
+ }
++#endif
+ }
+-
+- /* 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( subjRequiresPage(pPg) ){
+- rc = subjournalPage(pPg);
+- }
++ }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.
++ */
++ tempFile = 1;
++ pPager->eState = PAGER_READER;
++ pPager->eLock = EXCLUSIVE_LOCK;
++ readOnly = (vfsFlags&SQLITE_OPEN_READONLY);
++ }
++
++ /* 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 );
++ }
++
++ /* If an error occurred in either of the blocks above, free the
++ ** Pager structure and close the file.
++ */
++ if( rc!=SQLITE_OK ){
++ assert( !pPager->pTmpSpace );
++ sqlite3OsClose(pPager->fd);
++ sqlite3_free(pPager);
++ return rc;
+ }
+
+- /* Update the database size and return.
+- */
+- if( pPager->dbSize<pPg->pgno ){
+- pPager->dbSize = pPg->pgno;
++ /* 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))
++
++ 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; */
++#if 0
++ assert( pPager->state == (tempFile ? PAGER_EXCLUSIVE : PAGER_UNLOCK) );
++#endif
++ /* 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;
+ }
+- return rc;
++ /* 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;
+ }
+
++
++
+ /*
+-** 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.
++** 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 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 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 an error occurs, SQLITE_NOMEM or an IO error code is returned
+-** as appropriate. Otherwise, SQLITE_OK.
++** 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 sqlite3PagerWrite(DbPage *pDbPage){
+- int rc = SQLITE_OK;
+-
+- PgHdr *pPg = pDbPage;
+- Pager *pPager = pPg->pPager;
+- Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize);
++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( (pPg->flags & PGHDR_MMAP)==0 );
+- assert( pPager->eState>=PAGER_WRITER_LOCKED );
+- assert( pPager->eState!=PAGER_ERROR );
+- assert( assert_pager_state(pPager) );
++ assert( pPager->useJournal );
++ assert( isOpen(pPager->fd) );
++ assert( pPager->eState==PAGER_OPEN );
+
+- if( nPagePerSector>1 ){
+- 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 */
++ assert( jrnlOpen==0 || ( sqlite3OsDeviceCharacteristics(pPager->jfd) &
++ SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN
++ ));
+
+- /* Set the doNotSyncSpill flag 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->doNotSyncSpill==0 );
+- pPager->doNotSyncSpill++;
++ *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 */
+
+- /* 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.
++ /* 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.
+ */
+- 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);
++ rc = sqlite3OsCheckReservedLock(pPager->fd, &locked);
++ if( rc==SQLITE_OK && !locked ){
++ Pgno nPage; /* Number of pages in database file */
+
+- 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);
++ /* Check the size of the database file. If it consists of 0 pages,
++ ** then delete the journal file. See the header comment above for
++ ** the reasoning here. Delete the obsolete journal file under
++ ** a RESERVED lock to avoid race conditions and to avoid violating
++ ** [H33020].
++ */
++ rc = pagerPagecount(pPager, &nPage);
++ if( rc==SQLITE_OK ){
++ if( nPage==0 ){
++ 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 ){
+- rc = pager_write(pPage);
+- if( pPage->flags&PGHDR_NEED_SYNC ){
+- needSync = 1;
++ u8 first = 0;
++ rc = sqlite3OsRead(pPager->jfd, (void *)&first, 1, 0);
++ if( rc==SQLITE_IOERR_SHORT_READ ){
++ rc = SQLITE_OK;
+ }
+- sqlite3PagerUnref(pPage);
++ 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
++ ** its 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;
+ }
+ }
+- }else if( (pPage = pager_lookup(pPager, pg))!=0 ){
+- if( pPage->flags&PGHDR_NEED_SYNC ){
+- needSync = 1;
+- }
+- sqlite3PagerUnref(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;
+- sqlite3PagerUnref(pPage);
+- }
+ }
+ }
+-
+- assert( pPager->doNotSyncSpill==1 );
+- pPager->doNotSyncSpill--;
+- }else{
+- rc = pager_write(pDbPage);
+ }
+- return rc;
+-}
+
+-/*
+-** 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;
++ return rc;
+ }
+-#endif
+
+ /*
+-** 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.
++** 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.
+ **
+-** 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);
+- }
+-}
+-
+-/*
+-** 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.
++** The following operations are also performed by this function.
+ **
+-** 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.
++** 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.
+ **
+-** 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.
++** 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 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.
++** 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.
+ */
+-static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
+- int rc = SQLITE_OK;
+-
+- assert( pPager->eState==PAGER_WRITER_CACHEMOD
+- || pPager->eState==PAGER_WRITER_DBMOD
+- );
+- assert( assert_pager_state(pPager) );
++SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
++ int rc = SQLITE_OK; /* Return code */
+
+- /* 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.
++ /* 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.
+ */
+-#ifndef SQLITE_ENABLE_ATOMIC_WRITE
+-# define DIRECT_MODE 0
+- assert( isDirectMode==0 );
+- UNUSED_PARAMETER(isDirectMode);
+-#else
+-# define DIRECT_MODE isDirectMode
+-#endif
++ 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( !pPager->changeCountDone && ALWAYS(pPager->dbSize>0) ){
+- PgHdr *pPgHdr; /* Reference to page 1 */
++ if( !pagerUseWal(pPager) && pPager->eState==PAGER_OPEN ){
++ int bHotJournal = 1; /* True if there exists a hot journal-file */
+
+- assert( !pPager->tempFile && isOpen(pPager->fd) );
++ assert( !MEMDB );
+
+- /* Open page 1 of the file for writing. */
+- rc = sqlite3PagerGet(pPager, 1, &pPgHdr);
+- assert( pPgHdr==0 || rc==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 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 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( !DIRECT_MODE && ALWAYS(rc==SQLITE_OK) ){
+- rc = sqlite3PagerWrite(pPgHdr);
++ 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;
++ }
++
++ /* 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);
++ }
++
++ 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;
++ }
++
++ assert( pPager->eState==PAGER_OPEN );
++ assert( (pPager->eLock==SHARED_LOCK)
++ || (pPager->exclusiveMode && pPager->eLock>SHARED_LOCK)
++ );
+ }
+
+- if( rc==SQLITE_OK ){
+- /* Actually do the update of the change counter */
+- pager_write_changecounter(pPgHdr);
++ 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.
++ **
++ ** 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;
+
+- /* 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]++;
+- }
+- 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;
++ 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{
+- pPager->changeCountDone = 1;
++ memset(dbFileVers, 0, sizeof(dbFileVers));
++ }
++
++ 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);
++ }
+ }
+ }
+
+- /* Release the page reference. */
+- sqlite3PagerUnref(pPgHdr);
++ /* 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
-+/* END CRYPTO */
+ }
+- return rc;
+-}
+
+-/*
+-** 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 sqlite3PagerSync(Pager *pPager){
+- int rc = SQLITE_OK;
+- if( !pPager->noSync ){
+- assert( !MEMDB );
+- rc = sqlite3OsSync(pPager->fd, pPager->syncFlags);
+- }else if( isOpen(pPager->fd) ){
++ if( pagerUseWal(pPager) ){
++ assert( rc==SQLITE_OK );
++ rc = pagerBeginReadTransaction(pPager);
++ }
++
++ if( pPager->eState==PAGER_OPEN && rc==SQLITE_OK ){
++ rc = pagerPagecount(pPager, &pPager->dbSize);
++ }
++
++ failed:
++ if( rc!=SQLITE_OK ){
+ assert( !MEMDB );
+- rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SYNC_OMITTED, 0);
+- if( rc==SQLITE_NOTFOUND ){
+- rc = SQLITE_OK;
+- }
++ pager_unlock(pPager);
++ assert( pPager->eState==PAGER_OPEN );
++ }else{
++ pPager->eState = PAGER_READER;
+ }
+ 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.
++** If the reference count has reached zero, rollback any active
++** transaction and unlock the pager.
+ **
+-** 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 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);
++** 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);
+ }
+- 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).
++** 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.
+ **
+-** This routine ensures that:
++** 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 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 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.
+ **
+-** 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).
++** 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.
+ **
+-** Note that if zMaster==NULL, this does not overwrite a previous value
+-** passed to an sqlite3PagerCommitPhaseOne() call.
++** If noContent is true, it means that we do not care about the contents
++** of the page. This occurs in two seperate scenarios:
+ **
+-** 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.
++** 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.
++**
++** 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 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 */
++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_ACQUIRE_XXX flags */
+ ){
+- int rc = SQLITE_OK; /* Return code */
++ int rc = SQLITE_OK;
++ PgHdr *pPg = 0;
++ u32 iFrame = 0; /* Frame to read from WAL file */
++ const int noContent = (flags & PAGER_ACQUIRE_NOCONTENT);
+
+- assert( pPager->eState==PAGER_WRITER_LOCKED
+- || pPager->eState==PAGER_WRITER_CACHEMOD
+- || pPager->eState==PAGER_WRITER_DBMOD
+- || pPager->eState==PAGER_ERROR
++ /* 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_ACQUIRE_READONLY))
++#ifdef SQLITE_HAS_CODEC
++ && pPager->xCodec==0
++#endif
+ );
++
++ assert( pPager->eState>=PAGER_READER );
+ assert( assert_pager_state(pPager) );
++ assert( noContent==0 || bMmapOk==0 );
+
+- /* If a prior error occurred, report that error again. */
+- if( NEVER(pPager->errCode) ) return pPager->errCode;
++ if( pgno==0 ){
++ return SQLITE_CORRUPT_BKPT;
++ }
+
+- PAGERTRACE(("DATABASE SYNC: File=%s zMaster=%s nSize=%d\n",
+- pPager->zFilename, zMaster, pPager->dbSize));
++ /* 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 no database changes have been made, return early. */
+- if( pPager->eState<PAGER_WRITER_CACHEMOD ) return SQLITE_OK;
++ if( bMmapOk && pagerUseWal(pPager) ){
++ rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
++ if( rc!=SQLITE_OK ) goto pager_acquire_err;
++ }
+
+- 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( iFrame==0 && bMmapOk ){
++ void *pData = 0;
+
++ rc = sqlite3OsFetch(pPager->fd,
++ (i64)(pgno-1) * pPager->pageSize, pPager->pageSize, &pData
+ );
+- 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);
+
- /************** End of pager.c ***********************************************/
- /************** Begin file wal.c *********************************************/
++ if( rc==SQLITE_OK && pData ){
++ if( pPager->eState>PAGER_READER ){
++ (void)sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &pPg);
++ }
++ 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;
+ }
+ }
+- #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;
++ goto pager_acquire_err;
+ }
+- 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;
++ rc = sqlite3PcacheFetch(pPager->pPCache, pgno, 1, ppPage);
++ }
++
++ 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;
++ }
++
++ if( MEMDB || pPager->dbSize<pgno || noContent || !isOpen(pPager->fd) ){
++ if( pgno>pPager->mxPgno ){
++ rc = SQLITE_FULL;
++ goto pager_acquire_err;
+ }
+-
+- /* Finally, sync the database file. */
+- if( !noSync ){
+- rc = sqlite3PagerSync(pPager);
++ 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;
+ }
+- IOTRACE(("DBSYNC %p\n", pPager))
+ }
++ pager_set_pagehash(pPg);
+ }
+
+-commit_phase_one_exit:
+- if( rc==SQLITE_OK && !pagerUseWal(pPager) ){
+- pPager->eState = PAGER_WRITER_FINISHED;
++ return SQLITE_OK;
++
++pager_acquire_err:
++ assert( rc!=SQLITE_OK );
++ if( pPg ){
++ sqlite3PcacheDrop(pPg);
+ }
++ pagerUnlockIfUnused(pPager);
++
++ *ppPage = 0;
+ return rc;
+ }
+
+-
+ /*
+-** 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.
++** 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.
+ **
+-** If an error occurs, an IO error code is returned and the pager
+-** moves into the error state. Otherwise, SQLITE_OK is returned.
++** 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 sqlite3PagerCommitPhaseTwo(Pager *pPager){
+- int rc = SQLITE_OK; /* Return code */
+-
+- /* 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;
+-
+- assert( pPager->eState==PAGER_WRITER_LOCKED
+- || pPager->eState==PAGER_WRITER_FINISHED
+- || (pagerUseWal(pPager) && pPager->eState==PAGER_WRITER_CACHEMOD)
+- );
+- assert( assert_pager_state(pPager) );
++SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
++ PgHdr *pPg = 0;
++ 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;
++}
+
+- /* 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 );
+- pPager->eState = PAGER_READER;
+- return SQLITE_OK;
++/*
++** 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.
++*/
++SQLITE_PRIVATE void sqlite3PagerUnref(DbPage *pPg){
++ if( pPg ){
++ Pager *pPager = pPg->pPager;
++ if( pPg->flags & PGHDR_MMAP ){
++ pagerReleaseMapPage(pPg);
++ }else{
++ sqlite3PcacheRelease(pPg);
++ }
++ pagerUnlockIfUnused(pPager);
+ }
+-
+- PAGERTRACE(("COMMIT %d\n", PAGERID(pPager)));
+- rc = pager_end_transaction(pPager, pPager->setMaster, 1);
+- return pager_error(pPager, rc);
+ }
+
/*
-@@ -44127,3533 +46473,2869 @@
- ** that correspond to frames greater than the new K value are removed
- ** from the hash table at this point.
+-** 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 is already in PAGER_ERROR state when this function is called,
+-** it returns Pager.errCode immediately. No work is performed in this case.
+-**
+-** Otherwise, in rollback mode, this function performs two functions:
++** 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.
+ **
+-** 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
++** 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.
+ **
+-** 2) It finalizes the journal file, so that it is not used for hot
+-** rollback at any point in the future.
++** 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.
+ **
+-** Finalization of the journal file (task 2) is only performed if the
+-** rollback is successful.
++** Whether or not the journal file is opened by this function, the
++** Pager.pInJournal bitvec structure is allocated.
+ **
+-** 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.
++** 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.
*/
+-SQLITE_PRIVATE int sqlite3PagerRollback(Pager *pPager){
+- int rc = SQLITE_OK; /* Return code */
+- PAGERTRACE(("ROLLBACK %d\n", PAGERID(pPager)));
++static int pager_open_journal(Pager *pPager){
++ int rc = SQLITE_OK; /* Return code */
++ sqlite3_vfs * const pVfs = pPager->pVfs; /* Local cache of vfs pointer */
+
+- /* 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( pPager->eState==PAGER_WRITER_LOCKED );
+ assert( assert_pager_state(pPager) );
+- if( pPager->eState==PAGER_ERROR ) return pPager->errCode;
+- if( pPager->eState<=PAGER_READER ) return SQLITE_OK;
++ 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;
+
+- 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;
++ 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)
++ );
++ #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
++ }
++ 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);
+ }
+- }else{
+- rc = pager_playback(pPager, 0);
+ }
+
+- 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 );
++ if( rc!=SQLITE_OK ){
++ sqlite3BitvecDestroy(pPager->pInJournal);
++ pPager->pInJournal = 0;
++ }else{
++ assert( pPager->eState==PAGER_WRITER_LOCKED );
++ pPager->eState = PAGER_WRITER_CACHEMOD;
++ }
+
+- /* 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);
++ return rc;
+ }
+
+ /*
+-** Return TRUE if the database file is opened read-only. Return FALSE
+-** if the database is (in theory) writable.
++** Begin a write-transaction on the specified pager object. If a
++** write-transaction has already been opened, 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.
++**
++** 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 u8 sqlite3PagerIsreadonly(Pager *pPager){
+- return pPager->readOnly;
+-}
++SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory){
++ int rc = SQLITE_OK;
+
+-/*
+-** Return the number of references to the pager.
+-*/
+-SQLITE_PRIVATE int sqlite3PagerRefcount(Pager *pPager){
+- return sqlite3PcacheRefCount(pPager->pPCache);
+-}
++ if( pPager->errCode ) return pPager->errCode;
++ assert( pPager->eState>=PAGER_READER && pPager->eState<PAGER_ERROR );
++ pPager->subjInMemory = (u8)subjInMemory;
+
+-/*
+-** 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;
+-}
++ if( ALWAYS(pPager->eState==PAGER_READER) ){
++ assert( pPager->pInJournal==0 );
+
+-/*
+-** Return the number of references to the specified page.
+-*/
+-SQLITE_PRIVATE int sqlite3PagerPageRefcount(DbPage *pPage){
+- return sqlite3PcachePageRefcount(pPage);
+-}
++ 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);
++ }
+
+-#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;
++ /* 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);
++ }
++ }
++
++ 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;
++ }
++
++ assert( rc==SQLITE_OK || pPager->eState==PAGER_READER );
++ assert( rc!=SQLITE_OK || pPager->eState==PAGER_WRITER_LOCKED );
++ assert( assert_pager_state(pPager) );
++ }
++
++ PAGERTRACE(("TRANSACTION %d\n", PAGERID(pPager)));
++ return rc;
+ }
+-#endif
+
+ /*
+-** 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.
++** 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 void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, int *pnVal){
++static int pager_write(PgHdr *pPg){
++ void *pData = pPg->pData;
++ Pager *pPager = pPg->pPager;
++ int rc = SQLITE_OK;
+
+- assert( eStat==SQLITE_DBSTATUS_CACHE_HIT
+- || eStat==SQLITE_DBSTATUS_CACHE_MISS
+- || eStat==SQLITE_DBSTATUS_CACHE_WRITE
++ /* 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( 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 );
++ /* If an error has been previously detected, report the same error
++ ** again. This should not happen, but the check provides robustness. */
++ if( NEVER(pPager->errCode) ) return pPager->errCode;
+
+- *pnVal += pPager->aStat[eStat - SQLITE_DBSTATUS_CACHE_HIT];
+- if( reset ){
+- pPager->aStat[eStat - SQLITE_DBSTATUS_CACHE_HIT] = 0;
++ /* Higher-level routines never call this function if database is not
++ ** writable. But check anyway, just for robustness. */
++ if( NEVER(pPager->readOnly) ) return SQLITE_PERM;
++
++ 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;
+ }
+-}
++ assert( pPager->eState>=PAGER_WRITER_CACHEMOD );
++ assert( assert_pager_state(pPager) );
+
+-/*
+-** Return true if this is an in-memory pager.
+-*/
+-SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager *pPager){
+- return MEMDB;
+-}
++ /* Mark the page as dirty. If the page has already been written
++ ** to the journal then we can return right away.
++ */
++ sqlite3PcacheMakeDirty(pPg);
++ if( pageInJournal(pPg) && !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( !pageInJournal(pPg) && !pagerUseWal(pPager) ){
++ assert( pagerUseWal(pPager)==0 );
++ if( pPg->pgno<=pPager->dbOrigSize && isOpen(pPager->jfd) ){
++ u32 cksum;
++ char *pData2;
++ i64 iOff = pPager->journalOff;
+
+-/*
+-** 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.
+-**
+-** 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 */
++ /* 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->eState>=PAGER_WRITER_LOCKED );
+- assert( assert_pager_state(pPager) );
++ assert( pPager->journalHdr<=pPager->journalOff );
++ CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2);
++ cksum = pager_cksum(pPager, (u8*)pData2);
+
+- if( nSavepoint>nCurrent && pPager->useJournal ){
+- int ii; /* Iterator variable */
+- PagerSavepoint *aNew; /* New Pager.aSavepoint array */
++ /* 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;
+
+- /* 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;
++ 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;
+
+- /* 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;
++ 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{
+- 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);
++ 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)));
+ }
+- pPager->nSavepoint = ii+1;
+ }
+- assert( pPager->nSavepoint==nSavepoint );
+- assertTruncateConstraint(pPager);
++
++ /* 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( subjRequiresPage(pPg) ){
++ rc = subjournalPage(pPg);
++ }
+ }
+
++ /* Update the database size and return.
++ */
++ if( pPager->dbSize<pPg->pgno ){
++ pPager->dbSize = pPg->pgno;
++ }
+ 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.
+-**
+-** 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.
+-**
+-** 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.
+-**
+-** 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.
++** 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.
+ **
+-** 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.
++** 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 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 */
++** If an error occurs, SQLITE_NOMEM or an IO error code is returned
++** as appropriate. Otherwise, SQLITE_OK.
++*/
++SQLITE_PRIVATE int sqlite3PagerWrite(DbPage *pDbPage){
++ int rc = SQLITE_OK;
+
+- assert( op==SAVEPOINT_RELEASE || op==SAVEPOINT_ROLLBACK );
+- assert( iSavepoint>=0 || op==SAVEPOINT_ROLLBACK );
++ PgHdr *pPg = pDbPage;
++ Pager *pPager = pPg->pPager;
++ Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize);
+
+- if( rc==SQLITE_OK && iSavepoint<pPager->nSavepoint ){
+- int ii; /* Iterator variable */
+- int nNew; /* Number of remaining savepoints after this op. */
++ assert( (pPg->flags & PGHDR_MMAP)==0 );
++ assert( pPager->eState>=PAGER_WRITER_LOCKED );
++ assert( pPager->eState!=PAGER_ERROR );
++ assert( assert_pager_state(pPager) );
++
++ if( nPagePerSector>1 ){
++ 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 */
++
++ /* Set the doNotSyncSpill flag 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->doNotSyncSpill==0 );
++ pPager->doNotSyncSpill++;
+
+- /* 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.
++ /* 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.
+ */
+- nNew = iSavepoint + (( op==SAVEPOINT_RELEASE ) ? 0 : 1);
+- for(ii=nNew; ii<pPager->nSavepoint; ii++){
+- sqlite3BitvecDestroy(pPager->aSavepoint[ii].pInSavepoint);
++ 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;
+ }
+- pPager->nSavepoint = nNew;
++ assert(nPage>0);
++ assert(pg1<=pPg->pgno);
++ assert((pg1+nPage)>pPg->pgno);
+
+- /* 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 );
++ 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;
++ }
++ sqlite3PagerUnref(pPage);
++ }
+ }
+- pPager->nSubRec = 0;
++ }else if( (pPage = pager_lookup(pPager, pg))!=0 ){
++ if( pPage->flags&PGHDR_NEED_SYNC ){
++ needSync = 1;
++ }
++ sqlite3PagerUnref(pPage);
+ }
+ }
+- /* 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.
++
++ /* 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.
+ */
+- 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 && needSync ){
++ assert( !MEMDB );
++ for(ii=0; ii<nPage; ii++){
++ PgHdr *pPage = pager_lookup(pPager, pg1+ii);
++ if( pPage ){
++ pPage->flags |= PGHDR_NEED_SYNC;
++ sqlite3PagerUnref(pPage);
++ }
++ }
+ }
+- }
+
++ assert( pPager->doNotSyncSpill==1 );
++ pPager->doNotSyncSpill--;
++ }else{
++ rc = pager_write(pDbPage);
++ }
+ return rc;
+ }
+
+ /*
+-** 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.
++** 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 const char *sqlite3PagerFilename(Pager *pPager, int nullIfMemDb){
+- return (nullIfMemDb && pPager->memDb) ? "" : pPager->zFilename;
++#ifndef NDEBUG
++SQLITE_PRIVATE int sqlite3PagerIswriteable(DbPage *pPg){
++ return pPg->flags&PGHDR_DIRTY;
+ }
++#endif
+
+ /*
+-** Return the VFS structure for the pager.
++** 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 const sqlite3_vfs *sqlite3PagerVfs(Pager *pPager){
+- return pPager->pVfs;
++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 the file handle for the database file associated
+-** with the pager. This might return NULL if the file has
+-** not yet been opened.
++** 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.
+ */
+-SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager *pPager){
+- return pPager->fd;
+-}
++static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
++ int rc = SQLITE_OK;
+
+-/*
+-** Return the full pathname of the journal file.
+-*/
+-SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager *pPager){
+- return pPager->zJournal;
++ assert( pPager->eState==PAGER_WRITER_CACHEMOD
++ || pPager->eState==PAGER_WRITER_DBMOD
++ );
++ assert( assert_pager_state(pPager) );
++
++ /* 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.
++ */
++#ifndef SQLITE_ENABLE_ATOMIC_WRITE
++# define DIRECT_MODE 0
++ assert( isDirectMode==0 );
++ UNUSED_PARAMETER(isDirectMode);
++#else
++# define DIRECT_MODE isDirectMode
++#endif
++
++ if( !pPager->changeCountDone && ALWAYS(pPager->dbSize>0) ){
++ PgHdr *pPgHdr; /* Reference to page 1 */
++
++ assert( !pPager->tempFile && isOpen(pPager->fd) );
++
++ /* Open page 1 of the file for writing. */
++ rc = sqlite3PagerGet(pPager, 1, &pPgHdr);
++ assert( pPgHdr==0 || rc==SQLITE_OK );
++
++ /* 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( !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]++;
++ }
++ 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;
++ }
++ }else{
++ pPager->changeCountDone = 1;
++ }
++ }
++
++ /* Release the page reference. */
++ sqlite3PagerUnref(pPgHdr);
++ }
++ return rc;
+ }
+
+ /*
+-** Return true if fsync() calls are disabled for this pager. Return FALSE
+-** if fsync()s are executed normally.
++** 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 sqlite3PagerNosync(Pager *pPager){
+- return pPager->noSync;
++SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager){
++ int rc = SQLITE_OK;
++ if( !pPager->noSync ){
++ assert( !MEMDB );
++ rc = sqlite3OsSync(pPager->fd, pPager->syncFlags);
++ }else if( isOpen(pPager->fd) ){
++ assert( !MEMDB );
++ rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SYNC_OMITTED, 0);
++ if( rc==SQLITE_NOTFOUND ){
++ rc = SQLITE_OK;
++ }
++ }
++ return rc;
+ }
+
+-#ifdef SQLITE_HAS_CODEC
+ /*
+-** Set or retrieve the codec for this pager
++** 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.
++**
++** 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 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;
++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 rc;
+ }
+-#endif
+
+-#ifndef SQLITE_OMIT_AUTOVACUUM
+ /*
+-** Move the page pPg to location pgno in the file.
++** 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).
+ **
+-** 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.
++** This routine ensures that:
+ **
+-** 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 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.
+ **
+-** 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).
++** 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).
+ **
+-** 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.
++** Note that if zMaster==NULL, this does not overwrite a previous value
++** passed to an sqlite3PagerCommitPhaseOne() call.
+ **
+-** This function may return SQLITE_NOMEM or an IO error code if an error
+-** occurs. Otherwise, it returns SQLITE_OK.
++** 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 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 */
++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 */
+
+- assert( pPg->nRef>0 );
+- assert( pPager->eState==PAGER_WRITER_CACHEMOD
++ 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) );
+
+- /* 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;
+- }
+-
+- /* 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;
+- }
+-
+- 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.
+- */
+- if( (pPg->flags&PGHDR_NEED_SYNC) && !isCommit ){
+- needSyncPgno = pPg->pgno;
+- assert( pPager->journalMode==PAGER_JOURNALMODE_OFF ||
+- pageInJournal(pPg) || pPg->pgno>pPager->dbOrigSize );
+- assert( pPg->flags&PGHDR_DIRTY );
+- }
++ /* If a prior error occurred, report that error again. */
++ if( NEVER(pPager->errCode) ) return pPager->errCode;
+
+- /* 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 = pager_lookup(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);
+- }
+- }
++ PAGERTRACE(("DATABASE SYNC: File=%s zMaster=%s nSize=%d\n",
++ pPager->zFilename, zMaster, pPager->dbSize));
+
+- origPgno = pPg->pgno;
+- sqlite3PcacheMove(pPg, pgno);
+- sqlite3PcacheMakeDirty(pPg);
++ /* If no database changes have been made, return early. */
++ if( pPager->eState<PAGER_WRITER_CACHEMOD ) return SQLITE_OK;
+
+- /* 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);
+- sqlite3PagerUnref(pPgOld);
+- }
++ /* 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);
+
+- 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);
++ /* 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;
+ }
+- return rc;
++
++ /* Finally, sync the database file. */
++ if( !noSync ){
++ rc = sqlite3PagerSync(pPager);
++ }
++ IOTRACE(("DBSYNC %p\n", pPager))
+ }
+- pPgHdr->flags |= PGHDR_NEED_SYNC;
+- sqlite3PcacheMakeDirty(pPgHdr);
+- sqlite3PagerUnref(pPgHdr);
+ }
+
+- return SQLITE_OK;
+-}
+-#endif
+-
+-/*
+-** Return a pointer to the data for the specified page.
+-*/
+-SQLITE_PRIVATE void *sqlite3PagerGetData(DbPage *pPg){
+- assert( pPg->nRef>0 || pPg->pPager->memDb );
+- return pPg->pData;
++commit_phase_one_exit:
++ if( rc==SQLITE_OK && !pagerUseWal(pPager) ){
++ pPager->eState = PAGER_WRITER_FINISHED;
++ }
++ return rc;
+ }
+
+-/*
+-** Return a pointer to the Pager.nExtra bytes of "extra" space
+-** allocated along with the specified page.
+-*/
+-SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *pPg){
+- return pPg->pExtra;
+-}
+
+ /*
+-** 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.
++** 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.
+ **
+-** The returned value is either PAGER_LOCKINGMODE_NORMAL or
+-** PAGER_LOCKINGMODE_EXCLUSIVE, indicating the current (possibly updated)
+-** locking-mode.
++** 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 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 int sqlite3PagerCommitPhaseTwo(Pager *pPager){
++ int rc = SQLITE_OK; /* Return code */
++
++ /* 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;
++
++ assert( pPager->eState==PAGER_WRITER_LOCKED
++ || pPager->eState==PAGER_WRITER_FINISHED
++ || (pagerUseWal(pPager) && pPager->eState==PAGER_WRITER_CACHEMOD)
++ );
++ assert( assert_pager_state(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 );
++ pPager->eState = PAGER_READER;
++ return SQLITE_OK;
+ }
+- return (int)pPager->exclusiveMode;
++
++ PAGERTRACE(("COMMIT %d\n", PAGERID(pPager)));
++ rc = pager_end_transaction(pPager, pPager->setMaster, 1);
++ return pager_error(pPager, rc);
+ }
+
+ /*
+-** Set the journal-mode for this pager. Parameter eMode must be one of:
++** 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.
+ **
+-** PAGER_JOURNALMODE_DELETE
+-** PAGER_JOURNALMODE_TRUNCATE
+-** PAGER_JOURNALMODE_PERSIST
+-** PAGER_JOURNALMODE_OFF
+-** PAGER_JOURNALMODE_MEMORY
+-** PAGER_JOURNALMODE_WAL
++** 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.
+ **
+-** The journalmode is set to the value specified if the change is allowed.
+-** The change may be disallowed for the following reasons:
++** Otherwise, in rollback mode, this function performs two functions:
+ **
+-** * An in-memory database can only have its journal_mode set to _OFF
+-** or _MEMORY.
++** 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
+ **
+-** * Temporary databases cannot have _WAL journalmode.
++** 2) It finalizes the journal file, so that it is not used for hot
++** rollback at any point in the future.
+ **
+-** The returned indicate the current (possibly updated) journal-mode.
++** 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 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
+-
+-
+- /* 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 );
+-
+- /* 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 );
++SQLITE_PRIVATE int sqlite3PagerRollback(Pager *pPager){
++ int rc = SQLITE_OK; /* Return code */
++ PAGERTRACE(("ROLLBACK %d\n", PAGERID(pPager)));
+
+- /* Do allow the journalmode of an in-memory database to be set to
+- ** anything other than MEMORY or OFF
++ /* 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.
+ */
+- if( MEMDB ){
+- assert( eOld==PAGER_JOURNALMODE_MEMORY || eOld==PAGER_JOURNALMODE_OFF );
+- if( eMode!=PAGER_JOURNALMODE_MEMORY && eMode!=PAGER_JOURNALMODE_OFF ){
+- eMode = eOld;
+- }
+- }
+-
+- 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 ){
++ assert( assert_pager_state(pPager) );
++ if( pPager->eState==PAGER_ERROR ) return pPager->errCode;
++ if( pPager->eState<=PAGER_READER ) return SQLITE_OK;
+
+- /* 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.
++ 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.
+ */
+- 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 );
+- }
++ pPager->errCode = SQLITE_ABORT;
++ pPager->eState = PAGER_ERROR;
++ return rc;
+ }
++ }else{
++ rc = pager_playback(pPager, 0);
+ }
+
+- /* Return the new journal mode */
+- return (int)pPager->journalMode;
++ 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 );
++
++ /* 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);
+ }
+
+ /*
+-** Return the current journal mode.
++** Return TRUE if the database file is opened read-only. Return FALSE
++** if the database is (in theory) writable.
+ */
+-SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager *pPager){
+- return (int)pPager->journalMode;
++SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager *pPager){
++ return pPager->readOnly;
+ }
+
+ /*
+-** 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.
++** Return the number of references to the pager.
+ */
+-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;
++SQLITE_PRIVATE int sqlite3PagerRefcount(Pager *pPager){
++ return sqlite3PcacheRefCount(pPager->pPCache);
+ }
+
+ /*
+-** Get/set the size-limit used for persistent journal files.
+-**
+-** Setting the size limit to -1 means no limit is enforced.
+-** An attempt to set a limit smaller than -1 is a no-op.
++** Return the approximate number of bytes of memory currently
++** used by the pager and its associated cache.
+ */
+-SQLITE_PRIVATE i64 sqlite3PagerJournalSizeLimit(Pager *pPager, i64 iLimit){
+- if( iLimit>=-1 ){
+- pPager->journalSizeLimit = iLimit;
+- sqlite3WalLimit(pPager->pWal, iLimit);
+- }
+- return pPager->journalSizeLimit;
++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;
+ }
+
+ /*
+-** 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.
++** Return the number of references to the specified page.
+ */
+-SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager *pPager){
+- return &pPager->pBackup;
++SQLITE_PRIVATE int sqlite3PagerPageRefcount(DbPage *pPage){
++ return sqlite3PcachePageRefcount(pPage);
+ }
+
+-#ifndef SQLITE_OMIT_VACUUM
++#ifdef SQLITE_TEST
+ /*
+-** Unless this is an in-memory or temporary database, clear the pager cache.
++** This routine is used for testing and analysis only.
+ */
+-SQLITE_PRIVATE void sqlite3PagerClearCache(Pager *pPager){
+- if( !MEMDB && pPager->tempFile==0 ) pager_reset(pPager);
++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
+
-#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.
++** 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 int sqlite3PagerCheckpoint(Pager *pPager, int eMode, int *pnLog, int *pnCkpt){
+- int rc = SQLITE_OK;
+- if( pPager->pWal ){
+- rc = sqlite3WalCheckpoint(pPager->pWal, eMode,
+- pPager->xBusyHandler, pPager->pBusyHandlerArg,
+- pPager->ckptSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
+- pnLog, pnCkpt
+- );
+- }
+- return rc;
+-}
++SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, int *pnVal){
+
+-SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager){
+- return sqlite3WalCallback(pPager->pWal);
+-}
++ assert( eStat==SQLITE_DBSTATUS_CACHE_HIT
++ || eStat==SQLITE_DBSTATUS_CACHE_MISS
++ || eStat==SQLITE_DBSTATUS_CACHE_WRITE
++ );
+
+-/*
+-** 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);
++ 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;
++ }
+ }
+
+ /*
+-** Attempt to take an exclusive lock on the database file. If a PENDING lock
+-** is obtained instead, immediately release it.
++** Return true if this is an in-memory pager.
+ */
+-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;
++SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager *pPager){
++ return MEMDB;
+ }
+
+ /*
+-** 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.
++** 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.
++**
++** 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.
+ */
+-static int pagerOpenWal(Pager *pPager){
+- int rc = 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->pWal==0 && pPager->tempFile==0 );
+- assert( pPager->eLock==SHARED_LOCK || pPager->eLock==EXCLUSIVE_LOCK );
++ assert( pPager->eState>=PAGER_WRITER_LOCKED );
++ assert( assert_pager_state(pPager) );
+
+- /* 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);
+- }
++ if( nSavepoint>nCurrent && pPager->useJournal ){
++ int ii; /* Iterator variable */
++ PagerSavepoint *aNew; /* New Pager.aSavepoint array */
+
+- /* 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
++ /* 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);
+ }
+- pagerFixMaplimit(pPager);
+
+ return rc;
+ }
+
-
+ /*
+-** The caller must be holding a SHARED lock on the database file to call
+-** this function.
++** 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.
++**
++** 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.
+ **
+-** 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 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 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.
+-*/
+-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 */
++** 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.
++**
++** 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( 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) );
++ assert( op==SAVEPOINT_RELEASE || op==SAVEPOINT_ROLLBACK );
++ assert( iSavepoint>=0 || op==SAVEPOINT_ROLLBACK );
+
+- if( !pPager->tempFile && !pPager->pWal ){
+- if( !sqlite3PagerWalSupported(pPager) ) return SQLITE_CANTOPEN;
++ if( rc==SQLITE_OK && iSavepoint<pPager->nSavepoint ){
++ int ii; /* Iterator variable */
++ int nNew; /* Number of remaining savepoints after this op. */
+
+- /* Close any rollback journal previously open */
+- sqlite3OsClose(pPager->jfd);
++ /* 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;
+
+- rc = pagerOpenWal(pPager);
+- if( rc==SQLITE_OK ){
+- pPager->journalMode = PAGER_JOURNALMODE_WAL;
+- pPager->eState = PAGER_OPEN;
++ /* 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);
+ }
+- }else{
+- *pbOpen = 1;
+ }
+
+ return rc;
+ }
+
+ /*
+-** This function is called to close the connection to the log file prior
+-** to switching from WAL to rollback mode.
++** Return the full pathname of the database file.
+ **
+-** 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.
++** 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.
+ */
+-SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager){
+- int rc = SQLITE_OK;
++SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager *pPager, int nullIfMemDb){
++ return (nullIfMemDb && pPager->memDb) ? "" : pPager->zFilename;
++}
+
+- assert( pPager->journalMode==PAGER_JOURNALMODE_WAL );
++/*
++** Return the VFS structure for the pager.
++*/
++SQLITE_PRIVATE const sqlite3_vfs *sqlite3PagerVfs(Pager *pPager){
++ return pPager->pVfs;
++}
+
+- /* 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 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;
+ }
+
+-#endif /* !SQLITE_OMIT_WAL */
++/*
++** Return the full pathname of the journal file.
++*/
++SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager *pPager){
++ return pPager->zJournal;
++}
+
+-#ifdef SQLITE_ENABLE_ZIPVFS
+ /*
+-** 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.
++** Return true if fsync() calls are disabled for this pager. Return FALSE
++** if fsync()s are executed normally.
+ */
+-SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
+- assert( pPager->eState==PAGER_READER );
+- return sqlite3WalFramesize(pPager->pWal);
++SQLITE_PRIVATE int sqlite3PagerNosync(Pager *pPager){
++ return pPager->noSync;
+ }
+-#endif
+
+ #ifdef SQLITE_HAS_CODEC
+ /*
+-** 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.
++** Set or retrieve the codec for this pager
+ */
+-SQLITE_PRIVATE void *sqlite3PagerCodec(PgHdr *pPg){
+- void *aData = 0;
+- CODEC2(pPg->pPager, pPg->pData, pPg->pgno, 6, return 0, aData);
+- return aData;
++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);
+ }
+-#endif /* SQLITE_HAS_CODEC */
-
+-#endif /* SQLITE_OMIT_DISKIO */
++SQLITE_PRIVATE void *sqlite3PagerGetCodec(Pager *pPager){
++ return pPager->pCodec;
++}
++#endif
+
+-/************** End of pager.c ***********************************************/
+-/************** Begin file wal.c *********************************************/
++#ifndef SQLITE_OMIT_AUTOVACUUM
+ /*
+-** 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:
++** Move the page pPg to location pgno in the file.
+ **
+-** iKey = (P * 383) % HASHTABLE_NSLOT
++** 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.
+ **
+-** 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.
++** 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 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.
++** 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).
+ **
+-** 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.
++** 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.
+ **
+-** 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.
++** This function may return SQLITE_NOMEM or an IO error code if an error
++** occurs. Otherwise, it returns SQLITE_OK.
+ */
+-#ifndef SQLITE_OMIT_WAL
++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) );
++
++ /* 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;
++ }
++
++ /* 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;
++ }
++
++ 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.
++ */
++ if( (pPg->flags&PGHDR_NEED_SYNC) && !isCommit ){
++ needSyncPgno = pPg->pgno;
++ assert( pPager->journalMode==PAGER_JOURNALMODE_OFF ||
++ pageInJournal(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 = pager_lookup(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);
++ }
++ }
+
-/*
-** Trace output macros
-*/
@@ -2788,9 +63643,54 @@
-# define WALTRACE(X) if(sqlite3WalTrace) sqlite3DebugPrintf X
-#else
-# define WALTRACE(X)
--#endif
--
--/*
++ 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);
++ sqlite3PagerUnref(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);
++ sqlite3PagerUnref(pPgHdr);
++ }
++
++ return SQLITE_OK;
++}
+ #endif
+
+ /*
-** The maximum (and only) versions of the wal and wal-index formats
-** that may be interpreted by this version of SQLite.
-**
@@ -2802,14 +63702,21 @@
-** 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 a pointer to the data for the specified page.
+ */
-#define WAL_MAX_VERSION 3007000
-#define WALINDEX_MAX_VERSION 3007000
--
--/*
++SQLITE_PRIVATE void *sqlite3PagerGetData(DbPage *pPg){
++ assert( pPg->nRef>0 || pPg->pPager->memDb );
++ return pPg->pData;
++}
+
+ /*
-** Indices of various locking bytes. WAL_NREADER is the number
-** of available reader locks and should be at least 3.
--*/
++** Return a pointer to the Pager.nExtra bytes of "extra" space
++** allocated along with the specified page.
+ */
-#define WAL_WRITE_LOCK 0
-#define WAL_ALL_BUT_WRITE 1
-#define WAL_CKPT_LOCK 1
@@ -2823,17 +63730,27 @@
-typedef struct WalIterator WalIterator;
-typedef struct WalCkptInfo WalCkptInfo;
-
--
--/*
++SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *pPg){
++ return pPg->pExtra;
++}
+
+ /*
-** 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.
--**
++** 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 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.
--*/
++** The returned value is either PAGER_LOCKINGMODE_NORMAL or
++** PAGER_LOCKINGMODE_EXCLUSIVE, indicating the current (possibly updated)
++** locking-mode.
+ */
-struct WalIndexHdr {
- u32 iVersion; /* Wal-index version */
- u32 unused; /* Unused (padding) field */
@@ -2847,8 +63764,20 @@
- u32 aSalt[2]; /* Two salt values copied from WAL header */
- u32 aCksum[2]; /* Checksum over all prior fields */
-};
--
--/*
++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;
++}
+
+ /*
-** 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.
@@ -2860,7 +63789,8 @@
-** 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.
--**
++** Set the journal-mode for this pager. Parameter eMode must be one of:
+ **
-** 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)
@@ -2869,12 +63799,20 @@
-** 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.
--**
++** PAGER_JOURNALMODE_DELETE
++** PAGER_JOURNALMODE_TRUNCATE
++** PAGER_JOURNALMODE_PERSIST
++** PAGER_JOURNALMODE_OFF
++** PAGER_JOURNALMODE_MEMORY
++** PAGER_JOURNALMODE_WAL
+ **
-** 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 journalmode is set to the value specified if the change is allowed.
++** The change may be disallowed for the following reasons:
+ **
-** 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
@@ -2886,24 +63824,35 @@
-** 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.
--**
++** * An in-memory database can only have its journal_mode set to _OFF
++** or _MEMORY.
+ **
-** 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.
--**
++** * Temporary databases cannot have _WAL journalmode.
+ **
-** We assume that 32-bit loads are atomic and so no locks are needed in
-** order to read from any aReadMark[] entries.
--*/
++** The returned indicate the current (possibly updated) journal-mode.
+ */
-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 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
+
-/* 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
@@ -2912,14 +63861,26 @@
-#define WALINDEX_LOCK_OFFSET (sizeof(WalIndexHdr)*2 + sizeof(WalCkptInfo))
-#define WALINDEX_LOCK_RESERVED 16
-#define WALINDEX_HDR_SIZE (WALINDEX_LOCK_OFFSET+WALINDEX_LOCK_RESERVED)
--
+
-/* Size of header before each frame in wal */
-#define WAL_FRAME_HDRSIZE 24
--
++ /* 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 );
+
-/* Size of write ahead log header, including checksum. */
-/* #define WAL_HDRSIZE 24 */
-#define WAL_HDRSIZE 32
--
++ /* 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 );
+
-/* 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.
@@ -2930,7 +63891,16 @@
-** all data as 32-bit little-endian words.
-*/
-#define WAL_MAGIC 0x377f0682
--
++ /* 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;
++ }
++ }
+
-/*
-** Return the offset of frame iFrame in the write-ahead log file,
-** assuming a database page size of szPage bytes. The offset returned
@@ -2939,11 +63909,70 @@
-#define walFrameOffset(iFrame, szPage) ( \
- WAL_HDRSIZE + ((iFrame)-1)*(i64)((szPage)+WAL_FRAME_HDRSIZE) \
-)
--
--/*
++ 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 );
++ }
++ }
++ }
++
++ /* Return the new journal mode */
++ return (int)pPager->journalMode;
++}
+
+ /*
-** An open write-ahead log file is represented by an instance of the
-** following object.
--*/
++** Return the current journal mode.
+ */
-struct Wal {
- sqlite3_vfs *pVfs; /* The VFS used to create pDbFd */
- sqlite3_file *pDbFd; /* File handle for the database file */
@@ -2970,28 +63999,59 @@
- u8 lockError; /* True if a locking error has occurred */
-#endif
-};
--
--/*
++SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager *pPager){
++ return (int)pPager->journalMode;
++}
+
+ /*
-** Candidate values for Wal.exclusiveMode.
--*/
++** 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.
+ */
-#define WAL_NORMAL_MODE 0
-#define WAL_EXCLUSIVE_MODE 1
-#define WAL_HEAPMEMORY_MODE 2
--
--/*
++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;
++}
+
+ /*
-** Possible values for WAL.readOnly
--*/
++** Get/set the size-limit used for persistent journal files.
++**
++** Setting the size limit to -1 means no limit is enforced.
++** An attempt to set a limit smaller than -1 is a no-op.
+ */
-#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 i64 sqlite3PagerJournalSizeLimit(Pager *pPager, i64 iLimit){
++ if( iLimit>=-1 ){
++ pPager->journalSizeLimit = iLimit;
++ sqlite3WalLimit(pPager->pWal, iLimit);
++ }
++ return pPager->journalSizeLimit;
++}
+
+ /*
-** Each page of the wal-index mapping contains a hash-table made up of
-** an array of HASHTABLE_NSLOT elements of the following type.
--*/
++** 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.
+ */
-typedef u16 ht_slot;
--
--/*
++SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager *pPager){
++ return &pPager->pBackup;
++}
+
++#ifndef SQLITE_OMIT_VACUUM
+ /*
-** 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
@@ -3005,7 +64065,8 @@
-** walIteratorFree() - Free an iterator.
-**
-** This functionality is used by the checkpoint code (see walCheckpoint()).
--*/
++** Unless this is an in-memory or temporary database, clear the pager cache.
+ */
-struct WalIterator {
- int iPrior; /* Last result returned from the iterator */
- int nSegment; /* Number of entries in aSegment[] */
@@ -3017,12 +64078,20 @@
- int iZero; /* Frame number associated with aPgno[0] */
- } aSegment[1]; /* One for every 32KB page in the wal-index */
-};
--
--/*
++SQLITE_PRIVATE void sqlite3PagerClearCache(Pager *pPager){
++ if( !MEMDB && pPager->tempFile==0 ) pager_reset(pPager);
++}
++#endif
+
++#ifndef SQLITE_OMIT_WAL
+ /*
-** 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.
--**
++** 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.
+ **
-** Changing any of these constants will alter the wal-index format and
-** create incompatibilities.
-*/
@@ -3034,15 +64103,30 @@
-** 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.
--*/
++** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART.
+ */
-#define HASHTABLE_NPAGE_ONE (HASHTABLE_NPAGE - (WALINDEX_HDR_SIZE/sizeof(u32)))
--
++SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, int eMode, int *pnLog, int *pnCkpt){
++ int rc = SQLITE_OK;
++ if( pPager->pWal ){
++ rc = sqlite3WalCheckpoint(pPager->pWal, eMode,
++ pPager->xBusyHandler, pPager->pBusyHandlerArg,
++ pPager->ckptSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
++ pnLog, pnCkpt
++ );
++ }
++ return rc;
++}
+
-/* The wal-index is divided into pages of WALINDEX_PGSZ bytes each. */
-#define WALINDEX_PGSZ ( \
- sizeof(ht_slot)*HASHTABLE_NSLOT + HASHTABLE_NPAGE*sizeof(u32) \
-)
--
--/*
++SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager){
++ return sqlite3WalCallback(pPager->pWal);
++}
+
+ /*
-** 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.
@@ -3050,10 +64134,16 @@
-** 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.
--*/
++** Return true if the underlying VFS for the given pager supports the
++** primitives necessary for write-ahead logging.
+ */
-static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){
- int rc = SQLITE_OK;
--
++SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager){
++ const sqlite3_io_methods *pMethods = pPager->fd->pMethods;
++ return pPager->exclusiveMode || (pMethods->iVersion>=2 && pMethods->xShmMap);
++}
+
- /* Enlarge the pWal->apWiData[] array if required */
- if( pWal->nWiData<=iPage ){
- int nByte = sizeof(u32*)*(iPage+1);
@@ -3068,7 +64158,13 @@
- pWal->apWiData = apNew;
- pWal->nWiData = iPage+1;
- }
--
++/*
++** 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 */
+
- /* Request a pointer to the required page from the VFS */
- if( pWal->apWiData[iPage]==0 ){
- if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){
@@ -3083,29 +64179,65 @@
- rc = SQLITE_OK;
- }
- }
-- }
--
++ 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);
+ }
+
- *ppPage = pWal->apWiData[iPage];
- assert( iPage==0 || *ppPage || rc!=SQLITE_OK );
-- return rc;
--}
--
--/*
+ return rc;
+ }
+
+ /*
-** Return a pointer to the WalCkptInfo structure in the wal-index.
--*/
++** 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 volatile WalCkptInfo *walCkptInfo(Wal *pWal){
- assert( pWal->nWiData>0 && pWal->apWiData[0] );
- return (volatile WalCkptInfo*)&(pWal->apWiData[0][sizeof(WalIndexHdr)/2]);
-}
--
++static int pagerOpenWal(Pager *pPager){
++ int rc = SQLITE_OK;
+
-/*
-** 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];
--}
--
++ 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;
+ }
+
-/*
-** The argument to this macro must be of type u32. On a little-endian
-** architecture, it returns the u32 value that results from interpreting
@@ -3117,65 +64249,148 @@
- (((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).
--**
++** The caller must be holding a SHARED lock on the database file to call
++** this function.
+ **
-** The checksum is written back into aOut[] before returning.
--**
++** 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.
+ **
-** nByte must be a positive multiple of 8.
--*/
++** 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 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 */
--){
++SQLITE_PRIVATE int sqlite3PagerOpenWal(
++ Pager *pPager, /* Pager object */
++ int *pbOpen /* OUT: Set to true if call is a no-op */
+ ){
- u32 s1, s2;
- u32 *aData = (u32 *)a;
- u32 *aEnd = (u32 *)&a[nByte];
--
++ int rc = SQLITE_OK; /* Return code */
+
- if( aIn ){
- s1 = aIn[0];
- s2 = aIn[1];
- }else{
- s1 = s2 = 0;
- }
--
++ 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) );
+
- assert( nByte>=8 );
- assert( (nByte&0x00000007)==0 );
--
++ if( !pPager->tempFile && !pPager->pWal ){
++ if( !sqlite3PagerWalSupported(pPager) ) return SQLITE_CANTOPEN;
+
- if( nativeCksum ){
- do {
- s1 += *aData++ + s2;
- s2 += *aData++ + s1;
- }while( aData<aEnd );
-- }else{
++ /* 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;
++ }
+ }else{
- do {
- s1 += BYTESWAP32(aData[0]) + s2;
- s2 += BYTESWAP32(aData[1]) + s1;
- aData += 2;
- }while( aData<aEnd );
-- }
--
++ *pbOpen = 1;
+ }
+
- aOut[0] = s1;
- aOut[1] = s2;
--}
--
++ return rc;
+ }
+
-static void walShmBarrier(Wal *pWal){
- if( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE ){
- sqlite3OsShmBarrier(pWal->pDbFd);
-- }
--}
--
--/*
++/*
++** 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.
++*/
++SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager){
++ int rc = SQLITE_OK;
++
++ 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);
++ }
++ }
++
++ /* 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
+ /*
-** Write the header information in pWal->hdr into the wal-index.
-**
-** The checksum on pWal->hdr is updated before it is written.
--*/
++** 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 walIndexWriteHdr(Wal *pWal){
- volatile WalIndexHdr *aHdr = walIndexHdr(pWal);
- const int nCksum = offsetof(WalIndexHdr, aCksum);
@@ -3187,13 +64402,20 @@
- memcpy((void *)&aHdr[1], (void *)&pWal->hdr, sizeof(WalIndexHdr));
- walShmBarrier(pWal);
- memcpy((void *)&aHdr[0], (void *)&pWal->hdr, sizeof(WalIndexHdr));
--}
--
--/*
++SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
++ assert( pPager->eState==PAGER_READER );
++ return sqlite3WalFramesize(pPager->pWal);
+ }
++#endif
+
++#ifdef SQLITE_HAS_CODEC
+ /*
-** 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:
--**
++** This function is called by the wal module when writing page content
++** into the log file.
+ **
-** 0: Page number.
-** 4: For commit records, the size of the database image in pages
-** after the commit. For all other records, zero.
@@ -3201,7 +64423,9 @@
-** 12: Salt-2 (copied from the wal-header)
-** 16: Checksum-1.
-** 20: Checksum-2.
--*/
++** This function returns a pointer to a buffer containing the encrypted
++** page content. If a malloc fails, this function may return NULL.
+ */
-static void walEncodeFrame(
- Wal *pWal, /* The write-ahead log */
- u32 iPage, /* Database page number for frame */
@@ -3215,15 +64439,26 @@
- sqlite3Put4byte(&aFrame[0], iPage);
- sqlite3Put4byte(&aFrame[4], nTruncate);
- memcpy(&aFrame[8], pWal->hdr.aSalt, 8);
--
++SQLITE_PRIVATE void *sqlite3PagerCodec(PgHdr *pPg){
++ void *aData = 0;
++ CODEC2(pPg->pPager, pPg->pData, pPg->pgno, 6, return 0, aData);
++ return aData;
++}
++#endif /* SQLITE_HAS_CODEC */
+
- nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN);
- walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum);
- walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum);
--
++#endif /* SQLITE_OMIT_DISKIO */
+
- sqlite3Put4byte(&aFrame[16], aCksum[0]);
- sqlite3Put4byte(&aFrame[20], aCksum[1]);
--}
--
++/* BEGIN SQLCIPHER */
++#ifdef SQLITE_HAS_CODEC
++SQLITE_PRIVATE void sqlite3pager_get_codec(Pager *pPager, void **ctx) {
++ *ctx = pPager->pCodec;
+ }
+
-/*
-** 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
@@ -3235,26 +64470,47 @@
- u32 *pnTruncate, /* OUT: New db size (or 0 if not commit) */
- u8 *aData, /* Pointer to page data (for checksum) */
- u8 *aFrame /* Frame data */
--){
++SQLITE_PRIVATE int sqlite3pager_is_mj_pgno(Pager *pPager, Pgno pgno) {
++ return (PAGER_MJ_PGNO(pPager) == pgno) ? 1 : 0;
++}
++
++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
+ ){
- 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 );
--
++ sqlite3PagerSetCodec(pPager, xCodec, xCodecSizeChng, xCodecFree, pCodec);
++}
+
- /* 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;
- }
--
++SQLITE_PRIVATE void sqlite3pager_sqlite3PagerSetError( Pager *pPager, int error) {
++ pPager->errCode = error;
++}
+
- /* A frame is only valid if the page number is creater than zero.
- */
- pgno = sqlite3Get4byte(&aFrame[0]);
- if( pgno==0 ){
- return 0;
- }
--
++#endif
++/* END SQLCIPHER */
+
- /* 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
@@ -3269,7 +64525,7 @@
- /* Checksum failed. */
- return 0;
- }
--
+
- /* If we reach this point, the frame is valid. Return the page number
- ** and the new database size.
- */
@@ -3277,6 +64533,250 @@
- *pnTruncate = sqlite3Get4byte(&aFrame[4]);
- return 1;
-}
++/************** 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.
++**
++** 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.
++*/
+#ifndef SQLITE_OMIT_WAL
@@ -4074,8 +65574,9 @@
- ** checkpointing the log file.
- */
- if( pWal->hdr.nPage ){
-- sqlite3_log(SQLITE_OK, "Recovered %d frames from WAL file %s",
-- pWal->hdr.nPage, pWal->zWalName
+- sqlite3_log(SQLITE_NOTICE_RECOVER_WAL,
+- "recovered %d frames from WAL file %s",
+- pWal->hdr.mxFrame, pWal->zWalName
- );
- }
+static void walShmBarrier(Wal *pWal){
@@ -4226,18 +65727,31 @@
- 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;
+ /* A frame is only valid if the page number is creater than zero.
+ */
+ pgno = sqlite3Get4byte(&aFrame[0]);
+ if( pgno==0 ){
+ return 0;
-+ }
+ }
-- /* 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;
+- if( rc!=SQLITE_OK ){
+- walIndexClose(pRet, 0);
+- sqlite3OsClose(pRet->pWalFd);
+- sqlite3_free(pRet);
+- }else{
+- int iDC = sqlite3OsDeviceCharacteristics(pRet->pWalFd);
+- 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));
+ /* 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
@@ -4252,25 +65766,25 @@
+ /* Checksum failed. */
+ return 0;
}
-
-- if( rc!=SQLITE_OK ){
-- walIndexClose(pRet, 0);
-- sqlite3OsClose(pRet->pWalFd);
-- sqlite3_free(pRet);
+- 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;
-+}
-+
+ }
+
+
+#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.
-+*/
+ */
+-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";
@@ -4278,34 +65792,58 @@
+ return "CKPT-LOCK";
+ }else if( lockIdx==WAL_RECOVER_LOCK ){
+ return "RECOVER-LOCK";
- }else{
-- int iDC = sqlite3OsDeviceCharacteristics(pRet->pWalFd);
-- 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));
++ }else{
+ static char zName[15];
+ sqlite3_snprintf(sizeof(zName), zName, "READ-LOCK[%d]",
+ lockIdx-WAL_READ_LOCK(0));
+ return zName;
- }
-- return rc;
++ }
}
+#endif /*defined(SQLITE_TEST) || defined(SQLITE_DEBUG) */
+
/*
--** Change the size to which the WAL file is trucated on each reset.
+-** 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.
+** 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.
*/
--SQLITE_PRIVATE void sqlite3WalLimit(Wal *pWal, i64 iLimit){
-- if( pWal ) pWal->mxWalSize = iLimit;
+-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);
+static int walLockShared(Wal *pWal, int lockIdx){
+ int rc;
+ if( pWal->exclusiveMode ) return SQLITE_OK;
@@ -4341,56 +65879,6 @@
}
/*
--** 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.
-+** 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 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);
-+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);
- }
-
--/*
-** This function merges two sorted lists into a single sorted list.
-**
-** aLeft[] and aRight[] are arrays of indices. The sort key is
@@ -4408,6 +65896,19 @@
-** 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.
++*/
++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);
++}
++
+/*
+** 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
@@ -4891,7 +66392,12 @@
+ u32 aFrameCksum[2] = {0, 0};
+ int iLock; /* Lock offset to lock for checkpoint */
+ int nLock; /* Number of locks to hold */
-+
+
+- szPage = walPagesize(pWal);
+- testcase( szPage<=32768 );
+- testcase( szPage>=65536 );
+- pInfo = walCkptInfo(pWal);
+- if( pInfo->nBackfill>=pWal->hdr.mxFrame ) return 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.
@@ -4910,15 +66416,10 @@
+ }
+ WALTRACE(("WAL%p: recovery begin...\n", pWal));
-- szPage = walPagesize(pWal);
-- testcase( szPage<=32768 );
-- testcase( szPage>=65536 );
-- pInfo = walCkptInfo(pWal);
-- if( pInfo->nBackfill>=pWal->hdr.mxFrame ) return SQLITE_OK;
-+ memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
-
- /* Allocate the iterator */
- rc = walIteratorInit(pWal, &pIter);
++ memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
++
+ rc = sqlite3OsFileSize(pWal->pWalFd, &nSize);
if( rc!=SQLITE_OK ){
- return rc;
@@ -5004,8 +66505,8 @@
+ goto finished;
}
-- /* If the database file may grow as a result of this checkpoint, hint
-- ** about the eventual size of the db file to the VFS layer.
+- /* 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);
@@ -5019,31 +66520,31 @@
+ if( version!=WAL_MAX_VERSION ){
+ rc = SQLITE_CANTOPEN_BKPT;
+ goto finished;
- }
-
-- /* 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);
++ }
++
+ /* 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 */
-+
+
+- /* 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);
+ /* Read and decode the next log frame. */
+ iFrame++;
+ rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset);
@@ -5130,8 +66631,9 @@
+ ** checkpointing the log file.
+ */
+ if( pWal->hdr.nPage ){
-+ sqlite3_log(SQLITE_OK, "Recovered %d frames from WAL file %s",
-+ pWal->hdr.nPage, pWal->zWalName
++ sqlite3_log(SQLITE_NOTICE_RECOVER_WAL,
++ "recovered %d frames from WAL file %s",
++ pWal->hdr.mxFrame, pWal->zWalName
+ );
}
}
@@ -5147,8 +66649,7 @@
/*
-** 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 an open wal-index.
- */
+-*/
-static void walLimitSize(Wal *pWal, i64 nMax){
- i64 sz;
- int rx;
@@ -5160,55 +66661,23 @@
- sqlite3EndBenignMalloc();
- if( rx ){
- sqlite3_log(rx, "cannot limit WAL size: %s", pWal->zWalName);
-+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);
- }
- }
-
+- }
+-}
+-
-/*
-** Close a connection to a log file.
-+/*
-+** 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 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.
-+**
-+** 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.
++** Close an open wal-index.
*/
-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 */
-+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 = SQLITE_OK;
- if( pWal ){
- int isDelete = 0; /* True to unlink wal and wal-index files */
-+ int rc; /* Return Code */
-+ Wal *pRet; /* Object to allocate and return */
-+ int flags; /* Flags passed to OsOpen() */
-
+-
- /* 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
@@ -5246,71 +66715,30 @@
- }
- }
- }
-+ assert( zWalName && zWalName[0] );
-+ assert( pDbFd );
-
+-
- walIndexClose(pWal, isDelete);
- sqlite3OsClose(pWal->pWalFd);
- if( isDelete ){
- sqlite3BeginBenignMalloc();
- sqlite3OsDelete(pWal->pVfs, pWal->zWalName, 0);
- sqlite3EndBenignMalloc();
-+ /* 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.
-+ */
-+#ifdef WIN_SHM_BASE
-+ assert( WIN_SHM_BASE==WALINDEX_LOCK_OFFSET );
-+#endif
-+#ifdef UNIX_SHM_BASE
-+ assert( UNIX_SHM_BASE==WALINDEX_LOCK_OFFSET );
-+#endif
-+
-+
-+ /* Allocate an instance of struct Wal to return. */
-+ *ppWal = 0;
-+ pRet = (Wal*)sqlite3MallocZero(sizeof(Wal) + pVfs->szOsFile);
-+ if( !pRet ){
-+ return SQLITE_NOMEM;
-+ }
-+
-+ 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;
-+ }
-+
-+ if( rc!=SQLITE_OK ){
-+ walIndexClose(pRet, 0);
-+ sqlite3OsClose(pRet->pWalFd);
-+ sqlite3_free(pRet);
-+ }else{
-+ int iDC = sqlite3OsDeviceCharacteristics(pRet->pWalFd);
-+ if( iDC & SQLITE_IOCAP_SEQUENTIAL ){ pRet->syncHeader = 0; }
-+ if( iDC & SQLITE_IOCAP_POWERSAFE_OVERWRITE ){
-+ pRet->padToSectorBoundary = 0;
++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;
}
- WALTRACE(("WAL%p: closed\n", pWal));
- sqlite3_free((void *)pWal->apWiData);
- sqlite3_free(pWal);
-+ *ppWal = pRet;
-+ WALTRACE(("WAL%d: opened\n", pRet));
++ }else{
++ sqlite3OsShmUnmap(pWal->pDbFd, isDelete);
}
- return rc;
+- return rc;
}
- /*
+-/*
-** Try to read the wal-index header. Return 0 on success and 1 if
-** there is a problem.
-**
@@ -5319,23 +66747,47 @@
-** 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.
+ **
-** If the checksum cannot be verified return non-zero. If the header
-** is read successfully and the checksum verified, return zero.
-+** Change the size to which the WAL file is trucated on each 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.
*/
-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 );
+
- /* 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
@@ -5345,43 +66797,53 @@
- ** 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.
+ */
- aHdr = walIndexHdr(pWal);
- memcpy(&h1, (void *)&aHdr[0], sizeof(h1));
- walShmBarrier(pWal);
- memcpy(&h2, (void *)&aHdr[1], sizeof(h2));
-+SQLITE_PRIVATE void sqlite3WalLimit(Wal *pWal, i64 iLimit){
-+ if( pWal ) pWal->mxWalSize = iLimit;
-+}
++#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 */
-- }
-+/*
-+** 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.
-+*/
-+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 */
++
++ 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;
+ }
- if( memcmp(&pWal->hdr, &h1, sizeof(WalIndexHdr)) ){
- *pChanged = 1;
@@ -5389,59 +66851,49 @@
- pWal->szPage = (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16);
- testcase( pWal->szPage<=32768 );
- testcase( pWal->szPage>=65536 );
-+ 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++;
++ if( rc!=SQLITE_OK ){
++ walIndexClose(pRet, 0);
++ sqlite3OsClose(pRet->pWalFd);
++ sqlite3_free(pRet);
++ }else{
++ int iDC = sqlite3OsDeviceCharacteristics(pRet->pWalFd);
++ 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;
++}
- /* The header was successfully read. Return zero. */
- return 0;
-+ *piPage = p->iPrior = iRet;
-+ return (iRet==0xFFFFFFFF);
++/*
++** 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;
}
/*
-** 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.
-+** This function merges two sorted lists into a single sorted list.
- **
+-**
-** 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
-** to 0.
-+** 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:
++** 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.
-+** 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.
++** 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 */
@@ -5457,30 +66909,21 @@
- return rc;
- };
- assert( page0 || pWal->writeLock==0 );
-+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;
-
+-
- /* 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);
-+ assert( nLeft>0 && nRight>0 );
-+ while( iRight<nRight || iLeft<nLeft ){
-+ ht_slot logpage;
-+ Pgno dbpage;
++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 */
- /* If the first attempt failed, it might have been due to a race
- ** with a writer. So get a WRITE lock and try again.
@@ -5503,10 +66946,71 @@
- */
- 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++;
++ }
++ }
++
++ *piPage = p->iPrior = iRet;
++ return (iRet==0xFFFFFFFF);
++}
++
++/*
++** 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;
++
++ assert( nLeft>0 && nRight>0 );
++ while( iRight<nRight || iLeft<nLeft ){
++ ht_slot logpage;
++ Pgno dbpage;
++
+ if( (iLeft<nLeft)
+ && (iRight>=nRight || aContent[aLeft[iLeft]]<aContent[aRight[iRight]])
+ ){
@@ -5864,15 +67368,15 @@
}
/*
--** Read a page from the WAL, if it is present in the WAL and if the
--** current read transaction is configured to use the WAL.
+-** 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.
**
--** The *pInWal is set to 1 if the requested page is in the WAL and
--** has been loaded. Or *pInWal is set to 0 if the page was not in
--** the WAL and needs to be read out of the database.
+-** 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.
@@ -5880,12 +67384,10 @@
+** The calling routine should invoke walIteratorFree() to destroy the
+** WalIterator object when it has finished with it.
*/
--SQLITE_PRIVATE int sqlite3WalRead(
+-SQLITE_PRIVATE int sqlite3WalFindFrame(
- Wal *pWal, /* WAL handle */
- Pgno pgno, /* Database page number to read data for */
-- int *pInWal, /* OUT: True if data is read from WAL */
-- int nOut, /* Size of buffer pOut in bytes */
-- u8 *pOut /* Buffer to write page data to */
+- u32 *piRead /* OUT: Frame number (or zero) */
-){
- u32 iRead = 0; /* If !=0, WAL frame to return data from */
- u32 iLast = pWal->hdr.mxFrame; /* Last page in WAL for this reader */
@@ -5911,7 +67413,7 @@
+ ** it only runs if there is actually content in the log (mxFrame>0).
*/
- if( iLast==0 || pWal->readLock==0 ){
-- *pInWal = 0;
+- *piRead = 0;
- return SQLITE_OK;
+ assert( pWal->ckptLock && pWal->hdr.mxFrame>0 );
+ iLast = pWal->hdr.mxFrame;
@@ -5962,7 +67464,13 @@
- 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;
++ }
+
- rc = walHashGet(pWal, iHash, &aHash, &aPgno, &iZero);
- if( rc!=SQLITE_OK ){
- return rc;
@@ -5973,29 +67481,6 @@
- if( iFrame<=iLast && aPgno[aHash[iKey]]==pgno ){
- /* assert( iFrame>iRead ); -- not true if there is corruption */
- iRead = iFrame;
-- }
-- if( (nCollide--)==0 ){
-- return SQLITE_CORRUPT_BKPT;
-- }
-- }
-+ aTmp = (ht_slot *)sqlite3ScratchMalloc(
-+ sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast)
-+ );
-+ if( !aTmp ){
-+ rc = SQLITE_NOMEM;
- }
-
--#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. */
-- {
-- u32 iRead2 = 0;
-- u32 iTest;
-- for(iTest=iLast; iTest>0; iTest--){
-- if( walFramePgno(pWal, iTest)==pgno ){
-- iRead2 = iTest;
-- break;
+ for(i=0; rc==SQLITE_OK && i<nSegment; i++){
+ volatile ht_slot *aHash;
+ u32 iZero;
@@ -6012,7 +67497,9 @@
+ 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++;
+
@@ -6025,56 +67512,64 @@
+ p->aSegment[i].aIndex = aIndex;
+ p->aSegment[i].aPgno = (u32 *)aPgno;
}
-- assert( iRead==iRead2 );
}
--#endif
+ sqlite3ScratchFree(aTmp);
-- /* If iRead is non-zero, then it is the log frame number that contains the
-- ** required page. Read and return data from the log file.
-- */
-- if( iRead ){
-- int sz;
-- i64 iOffset;
-- sz = pWal->hdr.szPage;
-- sz = (sz&0xfe00) + ((sz&0x0001)<<16);
-- testcase( sz<=32768 );
-- testcase( sz>=65536 );
-- iOffset = walFrameOffset(iRead, sz) + WAL_FRAME_HDRSIZE;
-- *pInWal = 1;
-- /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
-- return sqlite3OsRead(pWal->pWalFd, pOut, (nOut>sz ? sz : nOut), iOffset);
+-#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. */
+- {
+- u32 iRead2 = 0;
+- u32 iTest;
+- for(iTest=iLast; iTest>0; iTest--){
+- if( walFramePgno(pWal, iTest)==pgno ){
+- iRead2 = iTest;
+- break;
+- }
+- }
+- assert( iRead==iRead2 );
+ if( rc!=SQLITE_OK ){
+ walIteratorFree(p);
}
+-#endif
-
-- *pInWal = 0;
+- *piRead = iRead;
- return SQLITE_OK;
+ *pp = p;
+ return rc;
}
--
--/*
--** Return the size of the database in pages (or zero, if unknown).
-+/*
+ /*
+-** 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 Pgno sqlite3WalDbsize(Wal *pWal){
-- if( pWal && ALWAYS(pWal->readLock>=0) ){
-- return pWal->hdr.nPage;
-- }
-- return 0;
+-SQLITE_PRIVATE int sqlite3WalReadFrame(
+- Wal *pWal, /* WAL handle */
+- u32 iRead, /* Frame to read */
+- int nOut, /* Size of buffer pOut in bytes */
+- u8 *pOut /* Buffer to write page data to */
+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 sz;
+- i64 iOffset;
+- sz = pWal->hdr.szPage;
+- sz = (sz&0xfe00) + ((sz&0x0001)<<16);
+- testcase( sz<=32768 );
+- testcase( sz>=65536 );
+- 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);
+ int rc;
+ do {
+ rc = walLockExclusive(pWal, lockIdx, n);
@@ -6082,14 +67577,22 @@
+ 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.
-+*/
+ */
+-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);
-+}
+ }
+-
-/*
-** This function starts a write transaction on the WAL.
+/*
@@ -6132,6 +67635,10 @@
*/
-SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){
- int rc;
+-
+- /* 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 */
@@ -6151,26 +67658,31 @@
+ volatile WalCkptInfo *pInfo; /* The checkpoint status information */
+ int (*xBusy)(void*) = 0; /* Function to call when waiting for locks */
-- /* Cannot start a write transaction without first holding a read
-- ** transaction. */
-- assert( pWal->readLock>=0 );
+- 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;
-- 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 ){
+ /* Allocate the iterator */
+ rc = walIteratorInit(pWal, &pIter);
+ if( rc!=SQLITE_OK ){
-+ return rc;
+ return rc;
}
+- pWal->writeLock = 1;
+ assert( pIter );
-- /* Only one writer allowed at a time. Get the write lock. Return
-- ** SQLITE_BUSY if unable.
+- /* 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
@@ -6178,9 +67690,10 @@
+ ** overwrite database pages that are in use by active readers and thus
+ ** cannot be backfilled from the WAL.
*/
-- rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
-- if( rc ){
-- return rc;
+- if( memcmp(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr))!=0 ){
+- walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
+- pWal->writeLock = 0;
+- rc = SQLITE_BUSY;
+ mxSafeFrame = pWal->hdr.mxFrame;
+ mxPage = pWal->hdr.nPage;
+ for(i=1; i<WAL_NREADER; i++){
@@ -6199,33 +67712,109 @@
+ }
+ }
}
-- 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.
+- 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;
-+
+
+-/*
+-** 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);
+- pWal->writeLock = 0;
+- pWal->truncateOnCommit = 0;
+- }
+- return SQLITE_OK;
+-}
+ /* Sync the WAL to disk */
+ if( sync_flags ){
+ rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
+ }
-+
-+ /* If the database file may grow as a result of this checkpoint, hint
-+ ** about the eventual size of the db file to the VFS layer.
-+ */
+
+-/*
+-** 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.
+-**
+-** 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.
+-**
+-** Otherwise, if the callback function does not return an error, this
+-** function returns SQLITE_OK.
+-*/
+-SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx){
+- int rc = SQLITE_OK;
+- if( ALWAYS(pWal->writeLock) ){
+- Pgno iMax = pWal->hdr.mxFrame;
+- Pgno iFrame;
+-
+- /* 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.
+ */
+- memcpy(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr));
+-
+- for(iFrame=pWal->hdr.mxFrame+1;
+- ALWAYS(rc==SQLITE_OK) && iFrame<=iMax;
+- iFrame++
+- ){
+- /* 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
+- ** (if (a) is false) or simply expels the page from the cache (if (b)
+- ** is false).
+- **
+- ** If the upper layer is doing a rollback, it is guaranteed that there
+- ** are no outstanding references to any page other than page 1. And
+- ** page 1 is never written to the log until the transaction is
+- ** committed. As a result, the call to xUndo may not fail.
+- */
+- 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;
+-}
+
+-/*
+-** Argument aWalData must point to an array of WAL_SAVEPOINT_NDATA u32
+-** values. This function populates the array with values required to
+-** "rollback" the write position of the WAL handle back to the current
+-** point in the event of a savepoint rollback (via WalSavepointUndo()).
+-*/
+-SQLITE_PRIVATE void sqlite3WalSavepoint(Wal *pWal, u32 *aWalData){
+- assert( pWal->writeLock );
+- aWalData[0] = pWal->hdr.mxFrame;
+- aWalData[1] = pWal->hdr.aFrameCksum[0];
+- aWalData[2] = pWal->hdr.aFrameCksum[1];
+- aWalData[3] = pWal->nCkpt;
+-}
+
+-/*
+-** Move the write position of the WAL back to the point identified by
+-** the values in the aWalData[] array. aWalData must point to an array
+-** of WAL_SAVEPOINT_NDATA u32 values that has been previously populated
+-** by a call to WalSavepoint().
+-*/
+-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;
@@ -6240,7 +67829,9 @@
+ rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset);
+ if( rc!=SQLITE_OK ) break;
+ }
-+
+
+- 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 ){
@@ -6255,26 +67846,61 @@
+ pInfo->nBackfill = mxSafeFrame;
+ }
+ }
-+
+
+- if( aWalData[3]!=pWal->nCkpt ){
+- /* This savepoint was opened immediately after the write-transaction
+- ** was started. Right after that, the writer decided to wrap around
+- ** to the start of the log. Update the savepoint values to match.
+- */
+- aWalData[0] = 0;
+- aWalData[3] = pWal->nCkpt;
+ /* Release the reader lock held while backfilling */
+ walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
-+ }
-+
+ }
+
+- 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;
-+ }
-+
+ }
+
+- 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
+-** to the current log file, it is possible to overwrite the start of the
+-** existing log file with the new frames (i.e. "reset" the log). If so,
+-** it sets pWal->hdr.mxFrame to 0. Otherwise, pWal->hdr.mxFrame is left
+-** unchanged.
+-**
+-** SQLITE_OK is returned if no error is encountered (regardless of whether
+-** or not pWal->hdr.mxFrame is modified). An SQLite error code is returned
+-** if an error occurs.
+-*/
+-static int walRestartLog(Wal *pWal){
+- int rc = SQLITE_OK;
+- int cnt;
+-
+- 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( memcmp(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr))!=0 ){
-- walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
-- pWal->writeLock = 0;
-- rc = SQLITE_BUSY;
++ */
+ if( rc==SQLITE_OK && eMode!=SQLITE_CHECKPOINT_PASSIVE ){
+ assert( pWal->writeLock );
+ if( pInfo->nBackfill<pWal->hdr.mxFrame ){
@@ -6282,28 +67908,92 @@
+ }else if( eMode==SQLITE_CHECKPOINT_RESTART ){
+ assert( mxSafeFrame==pWal->hdr.mxFrame );
+ rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(1), WAL_NREADER-1);
-+ if( rc==SQLITE_OK ){
-+ walUnlockExclusive(pWal, 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
+- ** readers are currently using the WAL), then the transactions
+- ** frames will overwrite the start of the existing log. Update the
+- ** wal-index header to reflect this.
+- **
+- ** 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 );
+ walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
+- }else if( rc!=SQLITE_BUSY ){
+- return rc;
+ }
+ }
+- walUnlockShared(pWal, WAL_READ_LOCK(0));
+- pWal->readLock = -1;
+- cnt = 0;
+- do{
+- int notUsed;
+- rc = walTryBeginRead(pWal, ¬Used, 1, ++cnt);
+- }while( rc==WAL_RETRY );
+- assert( (rc&0xff)!=SQLITE_BUSY ); /* BUSY not possible when useWal==1 */
+- testcase( (rc&0xff)==SQLITE_IOERR );
+- testcase( rc==SQLITE_PROTOCOL );
+- testcase( rc==SQLITE_OK );
}
-
++
+ walcheckpoint_out:
+ walIteratorFree(pIter);
return rc;
}
/*
--** End a write transaction. The commit has already been done. This
--** routine merely releases the lock.
+-** Information about the current state of the WAL file and where
+-** the next fsync should occur - passed from sqlite3WalFrames() into
+-** walWriteToLog().
+-*/
+-typedef struct WalWriter {
+- Wal *pWal; /* The complete WAL information */
+- sqlite3_file *pFd; /* The WAL file to which we write */
+- sqlite3_int64 iSyncPoint; /* Fsync at this offset */
+- int syncFlags; /* Flags for the fsync */
+- int szPage; /* Size of one page */
+-} WalWriter;
+-
+-/*
+-** 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.
*/
--SQLITE_PRIVATE int sqlite3WalEndWriteTransaction(Wal *pWal){
-- if( pWal->writeLock ){
-- walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
-- pWal->writeLock = 0;
-- pWal->truncateOnCommit = 0;
+-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 */
+-){
+- int rc;
+- if( iOffset<p->iSyncPoint && iOffset+iAmt>=p->iSyncPoint ){
+- int iFirstAmt = (int)(p->iSyncPoint - iOffset);
+- rc = sqlite3OsWrite(p->pFd, pContent, iFirstAmt, iOffset);
+- if( rc ) return rc;
+- iOffset += iFirstAmt;
+- iAmt -= iFirstAmt;
+- pContent = (void*)(iFirstAmt + (char*)pContent);
+- assert( p->syncFlags & (SQLITE_SYNC_NORMAL|SQLITE_SYNC_FULL) );
+- rc = sqlite3OsSync(p->pFd, p->syncFlags);
+- if( iAmt==0 || rc ) return rc;
+static void walLimitSize(Wal *pWal, i64 nMax){
+ i64 sz;
+ int rx;
@@ -6316,36 +68006,39 @@
+ if( rx ){
+ sqlite3_log(rx, "cannot limit WAL size: %s", pWal->zWalName);
}
-- return SQLITE_OK;
+- rc = sqlite3OsWrite(p->pFd, pContent, iAmt, iOffset);
+- return rc;
}
/*
--** 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.
--**
--** 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.
--**
--** Otherwise, if the callback function does not return an error, this
--** function returns SQLITE_OK.
+-** Write out a single frame of the WAL
+** Close a connection to a log file.
*/
--SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx){
+-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 = SQLITE_OK;
-- if( ALWAYS(pWal->writeLock) ){
-- Pgno iMax = pWal->hdr.mxFrame;
-- Pgno iFrame;
--
-- /* Restore the clients cache of the wal-index header to the state it
-- ** was in before the client began writing to the database.
+ ){
+- 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 */
+
@@ -6356,8 +68049,7 @@
+ ** the wal and wal-index files.
+ **
+ ** The EXCLUSIVE lock is not released before returning.
- */
-- memcpy(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr));
++ */
+ rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE);
+ if( rc==SQLITE_OK ){
+ if( pWal->exclusiveMode==WAL_NORMAL_MODE ){
@@ -6387,45 +68079,24 @@
+ }
+ }
+ }
-
-- for(iFrame=pWal->hdr.mxFrame+1;
-- ALWAYS(rc==SQLITE_OK) && iFrame<=iMax;
-- iFrame++
-- ){
-- /* 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
-- ** (if (a) is false) or simply expels the page from the cache (if (b)
-- ** is false).
-- **
-- ** If the upper layer is doing a rollback, it is guaranteed that there
-- ** are no outstanding references to any page other than page 1. And
-- ** page 1 is never written to the log until the transaction is
-- ** committed. As a result, the call to xUndo may not fail.
-- */
-- assert( walFramePgno(pWal, iFrame)!=1 );
-- rc = xUndo(pUndoCtx, walFramePgno(pWal, iFrame));
++
+ walIndexClose(pWal, isDelete);
+ sqlite3OsClose(pWal->pWalFd);
+ if( isDelete ){
+ sqlite3BeginBenignMalloc();
+ sqlite3OsDelete(pWal->pVfs, pWal->zWalName, 0);
+ sqlite3EndBenignMalloc();
- }
-- walCleanupHash(pWal);
++ }
+ WALTRACE(("WAL%p: closed\n", pWal));
+ sqlite3_free((void *)pWal->apWiData);
+ sqlite3_free(pWal);
- }
-- assert( rc==SQLITE_OK );
++ }
return rc;
}
-/*
--** Argument aWalData must point to an array of WAL_SAVEPOINT_NDATA u32
--** values. This function populates the array with values required to
--** "rollback" the write position of the WAL handle back to the current
--** point in the event of a savepoint rollback (via WalSavepointUndo()).
+-** Write a set of frames to the log. The caller must hold the write-lock
+-** on the log file (obtained using sqlite3WalBeginWriteTransaction()).
+/*
+** Try to read the wal-index header. Return 0 on success and 1 if
+** there is a problem.
@@ -6443,31 +68114,35 @@
+** If the checksum cannot be verified return non-zero. If the header
+** is read successfully and the checksum verified, return zero.
*/
--SQLITE_PRIVATE void sqlite3WalSavepoint(Wal *pWal, u32 *aWalData){
-- assert( pWal->writeLock );
-- aWalData[0] = pWal->hdr.mxFrame;
-- aWalData[1] = pWal->hdr.aFrameCksum[0];
-- aWalData[2] = pWal->hdr.aFrameCksum[1];
-- aWalData[3] = pWal->nCkpt;
--}
+-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 */
+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 */
--/*
--** Move the write position of the WAL back to the point identified by
--** the values in the aWalData[] array. aWalData must point to an array
--** of WAL_SAVEPOINT_NDATA u32 values that has been previously populated
--** by a call to WalSavepoint().
--*/
--SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData){
-- int rc = SQLITE_OK;
+- assert( pList );
+- assert( pWal->writeLock );
+ /* The first page of the wal-index must be mapped at this point. */
+ assert( pWal->nWiData>0 && pWal->apWiData[0] );
-- assert( pWal->writeLock );
-- assert( aWalData[3]!=pWal->nCkpt || aWalData[0]<=pWal->hdr.mxFrame );
+- /* 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) );
+ /* 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
@@ -6483,29 +68158,70 @@
+ walShmBarrier(pWal);
+ memcpy(&h2, (void *)&aHdr[1], sizeof(h2));
-- if( aWalData[3]!=pWal->nCkpt ){
-- /* This savepoint was opened immediately after the write-transaction
-- ** was started. Right after that, the writer decided to wrap around
-- ** to the start of the log. Update the savepoint values to match.
-- */
-- aWalData[0] = 0;
-- aWalData[3] = pWal->nCkpt;
+-#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(&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( 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 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( memcmp(&pWal->hdr, &h1, sizeof(WalIndexHdr)) ){
+ *pChanged = 1;
+ memcpy(&pWal->hdr, &h1, sizeof(WalIndexHdr));
@@ -6513,65 +68229,78 @@
+ testcase( pWal->szPage<=32768 );
+ testcase( pWal->szPage>=65536 );
}
+- assert( (int)pWal->szPage==szPage );
-- 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;
+ /* The header was successfully read. Return zero. */
+ return 0;
- }
++}
--
- /*
--** 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
--** to the current log file, it is possible to overwrite the start of the
--** existing log file with the new frames (i.e. "reset" the log). If so,
--** it sets pWal->hdr.mxFrame to 0. Otherwise, pWal->hdr.mxFrame is left
--** unchanged.
+- /* 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.
- **
--** SQLITE_OK is returned if no error is encountered (regardless of whether
--** or not pWal->hdr.mxFrame is modified). An SQLite error code is returned
--** if an error occurs.
++**
+** 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
+** to 0.
+**
+** If the wal-index header is successfully read, return SQLITE_OK.
+** Otherwise an SQLite error code.
- */
--static int walRestartLog(Wal *pWal){
-- int rc = SQLITE_OK;
-- int cnt;
++*/
+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 */
-- 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( 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
-- ** frames will overwrite the start of the existing log. Update the
-- ** wal-index header to reflect this.
-- **
-- ** 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 */
+- /* 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);
+- }
+- }
+ assert( pChanged );
+ rc = walIndexPage(pWal, 0, &page0);
+ if( rc!=SQLITE_OK ){
@@ -6579,28 +68308,40 @@
+ };
+ assert( page0 || pWal->writeLock==0 );
-- 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 );
-- walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
-- }else if( rc!=SQLITE_BUSY ){
-- 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 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;
+- }
+ 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.
+ /* 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 ){
@@ -6620,63 +68361,27 @@
+ rc = walIndexRecover(pWal);
+ *pChanged = 1;
+ }
- }
++ }
+ pWal->writeLock = 0;
+ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
- }
-- walUnlockShared(pWal, WAL_READ_LOCK(0));
-- pWal->readLock = -1;
-- cnt = 0;
-- do{
-- int notUsed;
-- rc = walTryBeginRead(pWal, ¬Used, 1, ++cnt);
-- }while( rc==WAL_RETRY );
-- assert( (rc&0xff)!=SQLITE_BUSY ); /* BUSY not possible when useWal==1 */
-- testcase( (rc&0xff)==SQLITE_IOERR );
-- testcase( rc==SQLITE_PROTOCOL );
-- testcase( rc==SQLITE_OK );
++ }
}
-- return rc;
--}
--
--/*
--** Information about the current state of the WAL file and where
--** the next fsync should occur - passed from sqlite3WalFrames() into
--** walWriteToLog().
--*/
--typedef struct WalWriter {
-- Wal *pWal; /* The complete WAL information */
-- sqlite3_file *pFd; /* The WAL file to which we write */
-- sqlite3_int64 iSyncPoint; /* Fsync at this offset */
-- int syncFlags; /* Flags for the fsync */
-- int szPage; /* Size of one page */
--} WalWriter;
--/*
--** 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.
--*/
--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 */
--){
-- int rc;
-- if( iOffset<p->iSyncPoint && iOffset+iAmt>=p->iSyncPoint ){
-- int iFirstAmt = (int)(p->iSyncPoint - iOffset);
-- rc = sqlite3OsWrite(p->pFd, pContent, iFirstAmt, iOffset);
-- if( rc ) return rc;
-- iOffset += iFirstAmt;
-- iAmt -= iFirstAmt;
-- pContent = (void*)(iFirstAmt + (char*)pContent);
-- assert( p->syncFlags & (SQLITE_SYNC_NORMAL|SQLITE_SYNC_FULL) );
-- rc = sqlite3OsSync(p->pFd, p->syncFlags);
-- if( iAmt==0 || rc ) return rc;
+- 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;
+- }
+ /* If the header is read successfully, check the version number to make
+ ** sure the wal-index was not constructed with some future format that
+ ** this version of SQLite cannot understand.
@@ -6684,51 +68389,33 @@
+ if( badHdr==0 && pWal->hdr.iVersion!=WALINDEX_MAX_VERSION ){
+ rc = SQLITE_CANTOPEN_BKPT;
}
-- rc = sqlite3OsWrite(p->pFd, pContent, iAmt, iOffset);
-+
+
+- WALTRACE(("WAL%p: frame write %s\n", pWal, rc ? "failed" : "ok"));
return rc;
}
- /*
--** Write out a single frame of the WAL
+-/*
+-** This routine is called to implement sqlite3_wal_checkpoint() and
+-** related interfaces.
++/*
+** This is the value that walTryBeginRead returns when it needs to
+** be retried.
- */
--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;
--}
++*/
+#define WAL_RETRY (-1)
-
--/*
--** Write a set of frames to the log. The caller must hold the write-lock
--** on the log file (obtained using sqlite3WalBeginWriteTransaction()).
++
+/*
+** 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()
@@ -6770,29 +68457,23 @@
+** so it takes care to hold an exclusive lock on the corresponding
+** WAL_READ_LOCK() while changing values.
*/
--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) */
+-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; /* 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 */
--
-- assert( pList );
-- assert( pWal->writeLock );
+- int rc; /* Return code */
+- int isChanged = 0; /* True if a new wal-index header is loaded */
+- int eMode2 = eMode; /* Mode to pass to walCheckpoint() */
-
-- /* 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( 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 */
@@ -6800,18 +68481,27 @@
+ int i; /* Loop counter */
+ int rc = SQLITE_OK; /* Return code */
--#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( 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;
- }
--#endif
+- pWal->ckptLock = 1;
+ assert( pWal->readLock<0 ); /* Not currently locked */
-- /* 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 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.
+ ** 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
@@ -6827,8 +68517,8 @@
+ ** so that on the 100th (and last) RETRY we delay for 21 milliseconds.
+ ** The total delay time before giving up is less than 1 second.
*/
-- if( SQLITE_OK!=(rc = walRestartLog(pWal)) ){
-- return rc;
+- if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){
+- rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_WRITE_LOCK, 1);
+ if( cnt>5 ){
+ int nDelay = 1; /* Pause time in microseconds */
+ if( cnt>100 ){
@@ -6837,35 +68527,8 @@
+ }
+ if( cnt>=10 ) nDelay = (cnt-9)*238; /* Max delay 21ms. Total delay 996ms */
+ sqlite3OsSleep(pWal->pVfs, nDelay);
- }
-
-- /* 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( !useWal ){
+ rc = walIndexReadHdr(pWal, pChanged);
+ if( rc==SQLITE_BUSY ){
@@ -6893,28 +68556,23 @@
+ rc = SQLITE_BUSY_RECOVERY;
+ }
+ }
- if( rc!=SQLITE_OK ){
- return rc;
- }
++ 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
++
+ pInfo = walCkptInfo(pWal);
+ if( !useWal && pInfo->nBackfill==pWal->hdr.mxFrame ){
+ /* The WAL has been completely backfilled (or it is empty).
+ ** and can be safely ignored.
- */
-- if( pWal->syncHeader && sync_flags ){
-- rc = sqlite3OsSync(pWal->pWalFd, sync_flags & SQLITE_SYNC_MASK);
-- if( rc ) return rc;
++ */
+ rc = walLockShared(pWal, WAL_READ_LOCK(0));
+ walShmBarrier(pWal);
-+ if( rc==SQLITE_OK ){
+ if( rc==SQLITE_OK ){
+- pWal->writeLock = 1;
+- }else if( rc==SQLITE_BUSY ){
+- eMode2 = SQLITE_CHECKPOINT_PASSIVE;
+- 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.
@@ -6938,59 +68596,17 @@
+ return rc;
}
}
-- assert( (int)pWal->szPage==szPage );
--
-- /* 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;
--
-- /* 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;
-- }
-- /* 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.
+- /* 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);
+ /* 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.
- */
-- if( isCommit && (sync_flags & WAL_SYNC_TRANSACTIONS)!=0 ){
-- if( pWal->padToSectorBoundary ){
-- int sectorSize = sqlite3OsSectorSize(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);
++ */
+ mxReadMark = 0;
+ mxI = 0;
+ for(i=1; i<WAL_NREADER; i++){
@@ -7023,14 +68639,10 @@
+ return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTLOCK;
+ }
-- /* 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);
+- /* Copy data from the log to the database file. */
+- if( rc==SQLITE_OK ){
+- if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
+- rc = SQLITE_CORRUPT_BKPT;
+ rc = walLockShared(pWal, WAL_READ_LOCK(mxI));
+ if( rc ){
+ return rc==SQLITE_BUSY ? WAL_RETRY : rc;
@@ -7061,30 +68673,29 @@
+ ){
+ walUnlockShared(pWal, WAL_READ_LOCK(mxI));
+ return WAL_RETRY;
-+ }else{
+ }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);
+ assert( mxReadMark<=pWal->hdr.mxFrame );
+ pWal->readLock = (i16)mxI;
}
-- walLimitSize(pWal, sz);
-- pWal->truncateOnCommit = 0;
}
+ return rc;
+}
-- /* 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.
-- */
-- 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);
+- 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));
- }
+/*
+** Begin a read transaction on the database.
@@ -7104,21 +68715,12 @@
+ int rc; /* Return code */
+ int cnt = 0; /* Number of TryBeginRead attempts */
-- 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;
-- }
+- /* 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);
+ do{
+ rc = walTryBeginRead(pWal, pChanged, 0, ++cnt);
+ }while( rc==WAL_RETRY );
@@ -7127,76 +68729,87 @@
+ 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.
+/*
+** 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;
}
--
-- WALTRACE(("WAL%p: frame write %s\n", pWal, rc ? "failed" : "ok"));
-- return rc;
+- return (int)ret;
}
--/*
--** This routine is called to implement sqlite3_wal_checkpoint() and
--** related interfaces.
+ /*
+-** This function is called to change the WAL subsystem into or out
+-** of locking_mode=EXCLUSIVE.
-**
--** Obtain a CHECKPOINT lock and then backfill as much information as
--** we can from WAL into the database.
-+/*
-+** Read a page from the WAL, if it is present in the WAL and if the
-+** current read transaction is configured to use 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.
+-**
+-** 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 parameter xBusy is not NULL, it is a pointer to a busy-handler
--** callback. In this case this function runs a blocking checkpoint.
-+** The *pInWal is set to 1 if the requested page is in the WAL and
-+** has been loaded. Or *pInWal is set to 0 if the page was not in
-+** the WAL and needs to be read out of the database.
+-** 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 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 */
-+SQLITE_PRIVATE int sqlite3WalRead(
+-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 */
-+ int *pInWal, /* OUT: True if data is read from WAL */
-+ int nOut, /* Size of buffer pOut in bytes */
-+ u8 *pOut /* Buffer to write page data to */
- ){
-- int rc; /* Return code */
-- int isChanged = 0; /* True if a new wal-index header is loaded */
-- int eMode2 = eMode; /* Mode to pass to walCheckpoint() */
++ u32 *piRead /* OUT: Frame number (or zero) */
++){
+ 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 */
-- assert( pWal->ckptLock==0 );
-- assert( pWal->writeLock==0 );
+- /* 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.
+- */
+ /* This routine is only be called from within a read transaction. */
-+ assert( pWal->readLock>=0 || pWal->lockError );
+ assert( pWal->readLock>=0 || pWal->lockError );
+- assert( pWal->readLock>=0 || (op<=0 && pWal->exclusiveMode==0) );
-- 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;
+- if( op==0 ){
+- if( pWal->exclusiveMode ){
+- pWal->exclusiveMode = 0;
+- if( walLockShared(pWal, WAL_READ_LOCK(pWal->readLock))!=SQLITE_OK ){
+- pWal->exclusiveMode = 1;
+ /* 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,
@@ -7204,22 +68817,14 @@
+ ** WAL were empty.
+ */
+ if( iLast==0 || pWal->readLock==0 ){
-+ *pInWal = 0;
++ *piRead = 0;
+ return SQLITE_OK;
- }
-- 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.
++ }
++
+ /* 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).
- **
-- ** 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.
++ **
+ ** 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
@@ -7240,21 +68845,7 @@
+ ** (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;
-- rc = SQLITE_OK;
-- }
-- }
--
-- /* Read the wal-index header. */
-- if( rc==SQLITE_OK ){
-- rc = walIndexReadHdr(pWal, &isChanged);
-- }
++ */
+ 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 */
@@ -7262,13 +68853,7 @@
+ int iKey; /* Hash slot index */
+ int nCollide; /* Number of hash collisions remaining */
+ int rc; /* Error code */
-
-- /* 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);
++
+ rc = walHashGet(pWal, iHash, &aHash, &aPgno, &iZero);
+ if( rc!=SQLITE_OK ){
+ return rc;
@@ -7282,14 +68867,23 @@
+ }
+ if( (nCollide--)==0 ){
+ return SQLITE_CORRUPT_BKPT;
-+ }
+ }
+- rc = pWal->exclusiveMode==0;
+- }else{
+- /* Already in locking_mode=NORMAL */
+- rc = 0;
}
-+ }
-
-- /* 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 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;
++
+#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
@@ -7302,164 +68896,62 @@
+ 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));
-+ /* If iRead is non-zero, then it is the log frame number that contains the
-+ ** required page. Read and return data from the log file.
-+ */
-+ if( iRead ){
-+ int sz;
-+ i64 iOffset;
-+ sz = pWal->hdr.szPage;
-+ sz = (sz&0xfe00) + ((sz&0x0001)<<16);
-+ testcase( sz<=32768 );
-+ testcase( sz>=65536 );
-+ iOffset = walFrameOffset(iRead, sz) + WAL_FRAME_HDRSIZE;
-+ *pInWal = 1;
-+ /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
-+ return sqlite3OsRead(pWal->pWalFd, pOut, (nOut>sz ? sz : nOut), iOffset);
- }
-
-- /* 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);
-+ *pInWal = 0;
-+ return SQLITE_OK;
- }
-
--/* 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 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;
++ *piRead = iRead;
++ return SQLITE_OK;
}
--/*
--** 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.
--*/
++/*
++** 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 */
++ int nOut, /* Size of buffer pOut in bytes */
++ u8 *pOut /* Buffer to write page data to */
++){
++ int sz;
++ i64 iOffset;
++ sz = pWal->hdr.szPage;
++ sz = (sz&0xfe00) + ((sz&0x0001)<<16);
++ testcase( sz<=32768 );
++ testcase( sz>=65536 );
++ 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);
+ }
+
-#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 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 Pgno sqlite3WalDbsize(Wal *pWal){
++ if( pWal && ALWAYS(pWal->readLock>=0) ){
++ return pWal->hdr.nPage;
++ }
++ return 0;
+ }
-#endif
--
+
-#endif /* #ifndef SQLITE_OMIT_WAL */
-/************** End of wal.c *************************************************/
@@ -7469,18 +68961,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.
+ */
-/************** Include btreeInt.h in the middle of btmutex.c ****************/
-/************** Begin file btreeInt.h ****************************************/
-/*
@@ -7686,6 +69187,17 @@
-** 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.
+ */
@@ -7770,7 +69282,7 @@
+ assert( walFramePgno(pWal, iFrame)!=1 );
+ rc = xUndo(pUndoCtx, walFramePgno(pWal, iFrame));
+ }
-+ walCleanupHash(pWal);
++ if( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal);
+ }
+ assert( rc==SQLITE_OK );
+ return rc;
@@ -8062,7 +69574,40 @@
-#define WRITE_LOCK 2
+ assert( pList );
+ assert( pWal->writeLock );
-+
+
+-/* A Btree handle
+-**
+-** 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.
+-**
+-** 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.
+-*/
+-struct Btree {
+- sqlite3 *db; /* The database connection holding this btree */
+- BtShared *pBt; /* Sharable content of this btree */
+- u8 inTrans; /* TRANS_NONE, TRANS_READ or TRANS_WRITE */
+- u8 sharable; /* True if we can share pBt with another db */
+- 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 */
+- 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 */
+ /* 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) );
@@ -8072,8 +69617,19 @@
+ WALTRACE(("WAL%p: frame write begin. %d frames. mxFrame=%d. %s\n",
+ pWal, cnt, pWal->hdr.mxFrame, isCommit ? "Commit" : "Spill"));
+ }
-+#endif
-+
+ #endif
+-};
+
+-/*
+-** Btree.inTrans may take one of the following values.
+-**
+-** 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.
+-*/
+-#define TRANS_NONE 0
+-#define TRANS_READ 1
+-#define TRANS_WRITE 2
+ /* 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.
+ */
@@ -8163,7 +69719,7 @@
+ */
+ if( isCommit && (sync_flags & WAL_SYNC_TRANSACTIONS)!=0 ){
+ if( pWal->padToSectorBoundary ){
-+ int sectorSize = sqlite3OsSectorSize(pWal->pWalFd);
++ int sectorSize = sqlite3SectorSize(pWal->pWalFd);
+ w.iSyncPoint = ((iOffset+sectorSize-1)/sectorSize)*sectorSize;
+ while( iOffset<w.iSyncPoint ){
+ rc = walWriteOneFrame(&w, pLast, nTruncate, iOffset);
@@ -8221,80 +69777,6 @@
+ pWal->iCallback = iFrame;
+ }
+ }
-+
-+ WALTRACE(("WAL%p: frame write %s\n", pWal, rc ? "failed" : "ok"));
-+ return rc;
-+}
-
--/* A Btree handle
--**
--** 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.
-+/*
-+** This routine is called to implement sqlite3_wal_checkpoint() and
-+** related interfaces.
- **
--** 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.
-+** Obtain a CHECKPOINT lock and then backfill as much information as
-+** we can from WAL into the database.
- **
--** 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.
-+** If parameter xBusy is not NULL, it is a pointer to a busy-handler
-+** callback. In this case this function runs a blocking checkpoint.
- */
--struct Btree {
-- sqlite3 *db; /* The database connection holding this btree */
-- BtShared *pBt; /* Sharable content of this btree */
-- u8 inTrans; /* TRANS_NONE, TRANS_READ or TRANS_WRITE */
-- u8 sharable; /* True if we can share pBt with another db */
-- 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 */
-- 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
--};
-+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() */
-
--/*
--** Btree.inTrans may take one of the following values.
--**
--** 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.
--*/
--#define TRANS_NONE 0
--#define TRANS_READ 1
--#define TRANS_WRITE 2
-+ assert( pWal->ckptLock==0 );
-+ assert( pWal->writeLock==0 );
-/*
-** An instance of this object represents a single database file.
@@ -8325,12 +69807,23 @@
-**
-** 1) The current writer (BtShared.pWriter) concludes its transaction, OR
-** 2) The number of locks held by other connections drops to zero.
--**
++ WALTRACE(("WAL%p: frame write %s\n", pWal, rc ? "failed" : "ok"));
++ return rc;
++}
++
++/*
++** This routine is called to implement sqlite3_wal_checkpoint() and
++** related interfaces.
+ **
-** while in the 'pending-lock' state, no connection may start a new
-** transaction.
--**
++** Obtain a CHECKPOINT lock and then backfill as much information as
++** we can from WAL into the database.
+ **
-** This feature is included to help prevent writer-starvation.
--*/
++** If parameter xBusy is not NULL, it is a pointer to a busy-handler
++** callback. In this case this function runs a blocking checkpoint.
+ */
-struct BtShared {
- Pager *pPager; /* The page cache */
- sqlite3 *db; /* Database connection currently using this Btree */
@@ -8340,6 +69833,7 @@
-#ifndef SQLITE_OMIT_AUTOVACUUM
- 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
- u8 inTransaction; /* Transaction state */
- u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */
@@ -8364,16 +69858,20 @@
-#endif
- u8 *pTmpSpace; /* BtShared.pageSize bytes of space for tmp use */
-};
-+ 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;
++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() */
-/*
-** Allowed values for BtShared.btsFlags
@@ -8385,24 +69883,8 @@
-#define BTS_NO_WAL 0x0010 /* Do not open write-ahead-log files */
-#define BTS_EXCLUSIVE 0x0020 /* pWriter has an exclusive lock */
-#define BTS_PENDING 0x0040 /* Waiting for read-locks to clear */
-+ /* 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;
-+ }
-+ }
++ assert( pWal->ckptLock==0 );
++ assert( pWal->writeLock==0 );
-/*
-** An instance of the following structure is used to hold information
@@ -8420,10 +69902,16 @@
- u16 iOverflow; /* Offset to overflow page number. Zero if no overflow */
- u16 nSize; /* Size of the cell content on the main b-tree page */
-};
-+ /* Read the wal-index header. */
-+ if( rc==SQLITE_OK ){
-+ rc = walIndexReadHdr(pWal, &isChanged);
++ 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;
-/*
-** Maximum depth of an SQLite B-Tree structure. Any B-Tree deeper than
@@ -8435,13 +69923,24 @@
-** assumed that the database is corrupt.
-*/
-#define BTCURSOR_MAX_DEPTH 20
-+ /* 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);
++ /* 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;
+ }
++ }
-/*
-** A cursor is a pointer to a particular entry within a particular
@@ -8483,10 +69982,11 @@
- u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */
- MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */
-};
-+ /* 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);
+ }
+ }
@@ -8519,27 +70019,24 @@
-#define CURSOR_VALID 1
-#define CURSOR_REQUIRESEEK 2
-#define CURSOR_FAULT 3
-+ 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, xBusy, pBusyArg, sync_flags, zBuf);
++ }
-/*
-** The database page the PENDING_BYTE occupies. This page is never used.
-*/
-# define PENDING_BYTE_PAGE(pBt) PAGER_MJ_PGNO(pBt)
-+ /* 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);
-+}
++ /* 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);
++ }
++ }
-/*
-** These macros define the location of the pointer-map entry for a
@@ -8555,6 +70052,24 @@
-** 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( 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);
++ pWal->ckptLock = 0;
++ WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok"));
++ return (rc==SQLITE_OK && eMode!=eMode2 ? SQLITE_BUSY : 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
@@ -8753,51 +70268,59 @@
#ifndef SQLITE_OMIT_SHARED_CACHE
#if SQLITE_THREADSAFE
-@@ -86559,10 +88241,16 @@
+@@ -88696,10 +91032,24 @@
*/
SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
int rc = sqlite3_overload_function(db, "MATCH", 2);
++/* BEGIN SQLCIPHER */
++#ifdef SQLITE_HAS_CODEC
+#ifndef OMIT_EXPORT
+ extern void sqlcipher_exportFunc(sqlite3_context *, int, sqlite3_value **);
+#endif
++#endif
++/* END SQLCIPHER */
assert( rc==SQLITE_NOMEM || rc==SQLITE_OK );
if( rc==SQLITE_NOMEM ){
db->mallocFailed = 1;
}
++/* BEGIN SQLCIPHER */
++#ifdef SQLITE_HAS_CODEC
+#ifndef OMIT_EXPORT
+ sqlite3CreateFunc(db, "sqlcipher_export", 1, SQLITE_TEXT, 0, sqlcipher_exportFunc, 0, 0, 0);
+#endif
++#endif
++/* END SQLCIPHER */
}
/*
-@@ -91386,6 +93074,12 @@
+@@ -93695,6 +96045,12 @@
sqlite3 *db = pParse->db; /* The database connection */
Db *pDb; /* The specific database being pragmaed */
- Vdbe *v = pParse->pVdbe = sqlite3VdbeCreate(db); /* Prepared statement */
-+/** BEGIN CRYPTO **/
+ Vdbe *v = sqlite3GetVdbe(pParse); /* Prepared statement */
++/* BEGIN SQLCIPHER */
+#ifdef SQLITE_HAS_CODEC
+ extern int codec_pragma(sqlite3*, int, Parse *, const char *, const char *);
+#endif
-+/** END CRYPTO **/
++/* END SQLCIPHER */
+
if( v==0 ) return;
sqlite3VdbeRunOnlyOnce(v);
-@@ -91445,6 +93139,13 @@
+@@ -93755,6 +96111,13 @@
pParse->rc = rc;
}else
-+/** BEGIN CRYPTO **/
++/* BEGIN SQLCIPHER */
+#ifdef SQLITE_HAS_CODEC
+ if(codec_pragma(db, iDb, pParse, zLeft, zRight)) {
+ /* codec_pragma executes internal */
+ }else
+ #endif
-+/** END CRYPTO **/
++/* END SQLCIPHER */
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
/*
-@@ -92000,60 +93701,6 @@
+@@ -94348,60 +96711,6 @@
#ifndef SQLITE_OMIT_SCHEMA_PRAGMAS
/*
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]